This post originated from an RSS feed registered with Ruby Buzz
by Daniel Berger.
Original Post: Forwarding with Ruby
Feed Title: Testing 1,2,3...
Feed URL: http://djberg96.livejournal.com/data/rss
Feed Description: A blog on Ruby and other stuff.
This weekend I completely revamped the Forwardable module, though I hadn't planned to. Originally, I was just frickin' annoyed that a bug I reported over a year ago in the Forwardable module still had not been fixed. Once I got into the guts of the thing, I felt compelled to just rework the whole damned thing (and provide a test suite to boot). I also realized that the SingleForwardable module was completely unnecessary - everything could be done with Forwardable.
The good news is that the API is unchanged. :)
On to some code. For those that aren't familiar with Forwardable, it's an easy way of allowing you to do method delegation. For example, let's say I have a class Foo, with an instance variable @arr, which is a simple Array:
class Foo
def initialize
@arr = ["foo", "bar", "baz"]
end
end
Now say that you would like all instances of Foo to be able to respond to the length method, such that they actually return the length of @arr. You could define a length method manually, but that wouldn't be any fun. Let's use the Forwardable module instead:
require "forwardable"
class Foo
extend Forwardable
def_delegator(:@arr, :length)
def initialize
@arr = ["foo","bar","baz"]
end
end
f = Foo.new
p f.length # 3
Now, whenever Foo#length is call, it's actually forwarding that call to the @arr instance variable and returning the appropriate value. Cool, huh?
Now, I realize that for a single method it isn't very useful. But what if you wanted to delegate every method of the Array class? That's where delegation can come in truly handy. In that case, use the def_delegators method instead, passing it an array of methods:
require "forwardable"
class Foo
extend Forwardable
def_delegators(:@arr, *(Array.instance_methods)) # Splat!
def initialize
@arr = ["foo","bar","baz"]
end
end
f = Foo.new
p f.length # legal
f.shift # legal
f.pop # legal, and so on...
You can also extend individual instances of Foo if you like.