Improved Rails’ delegate method
The Rails framework includes a simple “delegate” method, which is mixed in the models, and can be used in order to delegate methods to other classes. However it’s limited at least in the following:
1. It doesn’t prevent “train wrecks” – e.g. if the class that the method is delegated to is nil, then there will be an attempt to call this method on the nil class.
2. It doesn’t allow renaming of the methods, e.g. if you have a method called “name” in your class, and a method called “name” in other class you want to delegate to, you have no means of doing this.
The implementation below remedies these shortcomings.
class Module def delegate(*methods) options = methods.pop unless options.is_a?(Hash) && to = options[:to] raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, :to => :greeter)." end prefix = options[:prefix] || '' orig_prefix = prefix if prefix != true and !prefix.empty? prefix += '_' end methods.each do |method| prefix = to.to_s + '_' if orig_prefix == true module_eval(<<-EOS, "(__DELEGATION__)", 1) def #{prefix}#{method}(*args, &block) return nil unless #{to} #{to}.__send__(#{method.inspect}, *args, &block) end EOS end end end |
You can use it like this:
delegate :name, :to=> :other, :prefix=>true |
and it will delegate a method “name” in “other” class as “other_name” in your class.
Or, alternatively
delegate :name, :to=> :other, :prefix=>'some' |
will delegate “some_name” to class “other”, method “name”.
January 19th, 2009 at 05:43
Awesome! This works with Merb/Datamapper as well with no changes required.
Reply
November 27th, 2009 at 05:16
A DRY way to apply Law of Demeter with demeter gem
http://github.com/emerleite/demeter
http://gemcutter.org/gems/demeter
Reply