From 5362d6ccbb12d5cd92597de5248cd62dab46a76d Mon Sep 17 00:00:00 2001 From: Sergio Gil Date: Sat, 27 Sep 2008 21:33:11 +0200 Subject: [PATCH] Added :allow_nil option for delegate --- .../active_support/core_ext/module/delegation.rb | 28 +++++++++++++++++++- activesupport/test/core_ext/module_test.rb | 21 ++++++++++++++- 2 files changed, 47 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..8491bad 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -47,16 +47,42 @@ class Module # Foo.new.min # => 4 # Foo.new.max # => 11 # + # 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 + # attr_accessor :bar + # def initialize(bar = nil) + # @bar = bar + # end + # delegate :zoo, :to => :bar + # end + # + # Foo.new.zoo # raises NoMethodError exception (you called nil.zoo) + # + # class Foo + # attr_accessor :bar + # 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)." end + + allow_nil = options[:allow_nil] && "#{to} && " methods.each do |method| module_eval(<<-EOS, "(__DELEGATION__)", 1) def #{method}(*args, &block) - #{to}.__send__(#{method.inspect}, *args, &block) + #{allow_nil}#{to}.__send__(#{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..e083379 100644 --- a/activesupport/test/core_ext/module_test.rb +++ b/activesupport/test/core_ext/module_test.rb @@ -36,6 +36,10 @@ Someone = Struct.new(:name, :place) do delegate :upcase, :to => "place.city" end +Project = Struct.new(:description, :person) do + delegate :name, :to => :person, :allow_nil => true +end + class Name delegate :upcase, :to => :@full_name @@ -84,7 +88,22 @@ class ModuleTest < Test::Unit::TestCase assert_raises(ArgumentError) { eval($nowhere) } assert_raises(ArgumentError) { eval($noplace) } end - + + def test_delegation_with_allow_nil + rails = Project.new("Rails", Someone.new("David")) + assert_equal rails.name, "David" + end + + def test_delegation_with_allow_nil_and_nil_value + rails = Project.new("Rails") + assert_nil rails.name + end + + def test_delegation_without_allow_nil_and_nil_value + david = Someone.new("David") + assert_raises(NoMethodError) { david.street } + end + def test_parent assert_equal Yz::Zy, Yz::Zy::Cd.parent assert_equal Yz, Yz::Zy.parent -- 1.5.3.7