Using delegate in ruby
Sunday, June 28th, 2009As I have been wandering ruby gems and rails plugin codes, I found delegate is used in many ways. For example, in attachment_fu plugin,
delegate :content_types, :to => Technoweenie::AttachmentFu
And in mechanize gem,
def_delegator :parser, :search, :search
Things to do with above codes are intuitive. In the first, if it receives content_types request, then invoke Technoweenie::AttachementFu.content_types. And in second one, if it receives search request, then invoke parser.search method. It is what the delegate normally do.
This is handy beacause it reduces the effort to declare an additional function like below.
def content_types Technoweenie::AttachmentFu.content_types end
As you can see in the above examples, there are two ways in using delegate.(Maybe more than two in the whole ruby world, but now I am focusing what I’ve found.) One is using activesupport, and the other way is using Forwardable module in Ruby standard libray.
delegate in ActiveSupport
Activesupport extends Module and adds delegate method to it. Therefore just by requiring activesupport, you can use delegate method at any Class.
irb(main):001:0> Object.respond_to? :delegate => false irb(main):002:0> require 'activesupport' => true irb(main):003:0> Object.respond_to? :delegate => true
Using delegate is easy. Just two things are needed. method name to delegate and target object.
require 'activesupport'
class SayHello
def greet(name)
"hello #{name}"
end
end
class Foo
attr_accessor :greeter
delegate :greet, :to => :greeter
end
foo = Foo.new
foo.greeter = SayHello.new
foo.greet("Tom") # => "hello Tom"
After declaring delegate, Foo comes to have instance method ‘greet’, which forwards greet request to greeter. To make delegate smarter, two more options, prefix and allow_nil are possible.
A prefix option adds prefix word to the method. For example ,
class Foo
attr_accessor :greeter
delegate :greet, :to => :greeter, :prefix => :hello
end
foo.hello_greet("Tom") # => "hello Tom"
If allow_nil option is true, delegate method returns nil instead of Exception, when delegate object is absent. For example,
class Foo
attr_accessor :greeter
delegate :greet, :to => :greeter, :allow_nil => true
end
foo = Foo.new
foo.greeter = nil
foo.greet("Tom") # => nil
delegate in Forwardable module
If you are not a big fan of activesupport, you can use Forwardable module in standard ruby library. To do the same thing using forwardable is like below.
require "forwardable"
class SayHello
def greet(name)
"hello #{name}"
end
end
class Foo
extend Forwardable
attr_accessor :greeter
def_delegator :greeter, :greet
end
foo = Foo.new
foo.greeter = SayHello.new
foo.greet("Tom") # => "hello Tom"
The parameters of def_delegator is target_object, method, alias_method(optional). An alias_method is the name of method that Foo creates. If alias_method is absent, method is used instead. So In the above, Foo come to have greet method, which calls greeter.greet. Any other options are not allowed.