From 03068b2209bb4a43b831766ae3a15f2dcfb5d971 Mon Sep 17 00:00:00 2001 From: Sergio Gil Date: Fri, 19 Sep 2008 21:20:26 +0200 Subject: [PATCH] delegate accepts :target and :allow_nil as options --- .../active_support/core_ext/module/delegation.rb | 33 ++++++++++++++++++- activesupport/test/core_ext/module_test.rb | 12 +++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index e0b5f3e..4b5a64b 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -47,16 +47,45 @@ class Module # Foo.new.min # => 4 # Foo.new.max # => 11 # + # You can specify a target if you don't want your method to have the same name: + # + # class Foo < ActiveRecord::Base + # belongs_to :greeter + # delegate :hi, :to => :greeter, :target => :hello + # end + # + # If the object in which you delegate can be nil, you may want to use the + # :allow_nil option. In that case, it returns nil instead of raising a + # NoMethodError exception: + # + # class Foo + # def initialize(bar = nil) + # @bar = bar + # end + # delegate :zoo, :to => :bar + # end + # + # Foo.new.zoo # raises NoMethodError exception (you called nil.zoo) + # + # class Foo + # def initialize(bar = nil) + # @bar = bar + # end + # delegate :zoo, :to => :bar, :allow_nil => true + # end + # + # Foo.new.zoo # returns nil + # 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)." + raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as an argument (e.g. delegate :hello, :to => :greeter)." end methods.each do |method| module_eval(<<-EOS, "(__DELEGATION__)", 1) def #{method}(*args, &block) - #{to}.__send__(#{method.inspect}, *args, &block) + #{to.to_s + ' && ' if options[:allow_nil]}#{to}.__send__(#{(options[:target] || method).inspect}, *args, &block) end EOS end diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb index ecdea38..b05a85d 100644 --- a/activesupport/test/core_ext/module_test.rb +++ b/activesupport/test/core_ext/module_test.rb @@ -84,6 +84,18 @@ class ModuleTest < Test::Unit::TestCase assert_raises(ArgumentError) { eval($nowhere) } assert_raises(ArgumentError) { eval($noplace) } end + + def test_delegation_with_allow_nil + Someone.class_eval { undef :street; delegate :street, :to => :place, :allow_nil => true} + david = Someone.new("David") + assert_nil david.street + end + + def test_delegation_with_target + Someone.class_eval { delegate :town, :to => :place, :target => :city } + david = Someone.new("David", Somewhere.new("Paulina", "Chicago")) + assert_equal "Chicago", david.town + end def test_parent assert_equal Yz::Zy, Yz::Zy::Cd.parent -- 1.5.3.7