views:

45

answers:

2

I would like to write a module that provides active record like functionality on an array instance variable.

Examples of its use would be

x = Container.new
x.include(ContainerModule)
x.elements << Element.new
x.elements.find id

module ContainerModule
   def initialize(*args)
     @elements = []
     class << @elements
        def <<(element)
          #do something with the Container...
          super(element)         
        end

        def find(id)
          #find an element using the Container's id
          self
          #=> #<Array..>  but I need #<Container..>
        end
     end
     super(*args)
  end
end

The problem is that I need the Container object within these methods. Any reference to self will return the Array, not the Container object.

Is there any way to do this?

Thanks!

A: 

Your best approach may be to work with the Hash class, which has operations like finding by id already. Particularly, the fetch method may help you out.

corprew
A hash really isn't an option. It needs to act like an array since the code base used it as such.
rube_noob
I may be misinterpreting what it is you need, but couldn't you just pass hash_object.values() to things that need to treat with it as an array?
corprew
+1  A: 

Would something like this work for you?

class Container
  attr_accessor :elements

  def initialize
    @elements = ContainerElements.new
  end
end

class ContainerElements < Array

  def find_by_id(id)
    self.find {|g| g.id == id }
  end

end

So i create a container-class, and a ContainerElements that inherits from Array, with an added (specific) find_by_id method. If you really want to call it find you need to alias it.

Example code would be:

class ElemWithId
  attr_accessor :id
  def initialize(value)
    @id = value
  end
end

cc = Container.new
cc.elements << ElemWithId.new(1)
cc.elements << ElemWithId.new(5)

puts "elements = #{cc.elements} "
puts "Finding: #{cc.elements.find_by_id(5)} "

Hope this helps ...

nathanvda