views:

44

answers:

2

Guys,

Is there a may to write an instance method that only operates on a collection of the class?

So for example say I have something like this:

class Foo
    def collection_method
      puts "I only work on a collection of Foo!"
    end
end

@foos = []

5.times {@foos << Foo.new}

@foo = Foo.new

@foos.collection_method  #=> I only work on a collection of Foo!
@foo.collection_method #=> Some sort of expection or error
A: 

Ruby has no concept of "collections of a certain object", but you can easily monkey-patch in a method on Array that only works when all items in the array are of your type.

irb(main):001:0> class Foo
irb(main):002:1>  def bar
irb(main):003:2>   puts "bar"
irb(main):004:2>  end
irb(main):005:1> end
=> nil
irb(main):006:0>
irb(main):007:0* class Array
irb(main):008:1>  def collection_method
irb(main):009:2>   raise "Not all Foo objects" unless self.all? { |x| x.instance_of? Foo }
irb(main):010:2>   self[0].bar
irb(main):011:2>  end
irb(main):012:1> end
=> nil
irb(main):013:0> [1,2,3].collection_method
RuntimeError: Not all Foo objects
        from (irb):9:in `collection_method'
        from (irb):13
        from ♥:0
irb(main):014:0> [Foo.new, Foo.new].collection_method
bar
=> nil

But this really goes against the grain of a dynamic language. It would be more natural to just try it out (whatever you're doing) and deal with errors as they arise.

Mark Rushakoff
A: 

In your code, @foos is an Array. So you can :

  • Add a method to Array

    class Array
      def collection_method
        ...
      end
    end
    
  • Create your own "Array" Class

    class MyArray < Array
      def collection_method
        ...
      end
    end
    
    
    @foos = MyArray.new
    ...
    

I think that's the first solution is not the better one...

greg