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"]
ruby have forwardable in standart library for this situations.
https://gist.github.com/1904776
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!
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
That’s brillant, trans. Thanks for sharing!
This site was… how do you say it? Relevant!!
Finally I’ve found something that helped me. Appreciate it!