How to hook to an Array instance in a Ruby module

On some project we needed to create a module containing an Array attribute. We wanted to hook onto some of the methods of this particular Array instance to call our own code. Here is how we did it:


module TheModule
attr_reader :items
def initialize(*args)
@items = []

def @items.<<(item)
super
"You added the item #{item} with <<!"
end

def @items.push(item)
super
"You added the item #{item} with push!"
end
super
end
end

class TheClass
include TheModule
end

And now the output:


x = TheClass.new
x.items # => []
x.items << 'blue' # => You added the item 'blue' with <<!
x.items.push 'orange' # => You added the item 'orange' with push!
x.items # => ["blue", "orange"]

  • https://github.com/selman selman

    ruby have forwardable in standart library for this situations.

    https://gist.github.com/1904776

  • http://www.rubyfleebie.com Frank

    Thanks Selman, Forwardable is a pretty interesting module. Never heard about it before! But this post was about finding a way to hook to an attribute in a class and add custom code to its methods. (i.e. the “You added the item #{item} with push!” part). Not so much about making a class instance behave like some other object. But thanks for mentioning Forwardable, I have learned something!

  • http://trans.github.com trans

    Very interesting approach!

    You could make that a little neater and better document by creating a “role” module.

    module ItemsRole
    def <<(item)
    super
    "You added the item #{item} with <<!"
    end

    def push(item)
    super
    "You added the item #{item} with push!"
    end
    end

    And then:

    @items.extend ItemsRole

  • http://www.rubyfleebie.com Frank

    That’s brillant, trans. Thanks for sharing!

  • http://puffyauger1828.skyrock.com/3219187005-Hertfordshire-Pre-Registration-Pharmacist-Student-Placement-Job.html Travis

    This site was… how do you say it? Relevant!!
    Finally I’ve found something that helped me. Appreciate it!