Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Only raise DelegationError if it's is the source of the exception

This fixes situations where nested NoMethodError exceptions are masked
by delegations. This would cause confusion especially where there was a
problem in the Rails booting process because of a delegation in the
routes reloading code.

Fixes #10559
  • Loading branch information...
commit 07a4c76a07641840892463eb934400abdf694927 1 parent e7e81b4
@pixeltrix pixeltrix authored
View
6 activesupport/CHANGELOG.md
@@ -1,3 +1,9 @@
+* Only raise `Module::DelegationError` if it's the source of the exception.
+
+ Fixes #10559
+
+ *Andrew White*
+
* Make `Time.at_with_coercion` retain the second fraction and return local time.
Fixes #11350
View
21 activesupport/lib/active_support/core_ext/module/delegation.rb
@@ -183,16 +183,17 @@ def #{method_prefix}#{method}(#{definition}) # def customer_name(*args, &
exception = %(raise DelegationError, "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
module_eval(<<-EOS, file, line - 2)
- def #{method_prefix}#{method}(#{definition}) # def customer_name(*args, &block)
- _ = #{to} # _ = client
- _.#{method}(#{definition}) # _.name(*args, &block)
- rescue NoMethodError # rescue NoMethodError
- if _.nil? # if _.nil?
- #{exception} # # add helpful message to the exception
- else # else
- raise # raise
- end # end
- end # end
+ def #{method_prefix}#{method}(#{definition}) # def customer_name(*args, &block)
+ _ = #{to} # _ = client
+ _.#{method}(#{definition}) # _.name(*args, &block)
+ rescue NoMethodError => e # rescue NoMethodError => e
+ location = "%s:%d:in `%s'" % [__FILE__, __LINE__ - 2, '#{method_prefix}#{method}'] # location = "%s:%d:in `%s'" % [__FILE__, __LINE__ - 2, 'customer_name']
+ if _.nil? && e.backtrace.first == location # if _.nil? && e.backtrace.first == location
+ #{exception} # # add helpful message to the exception
+ else # else
+ raise # raise
+ end # end
+ end # end
EOS
end
end
View
27 activesupport/test/core_ext/module_test.rb
@@ -66,6 +66,23 @@ def self.table_name
delegate :name, :to => :client, :prefix => false
end
+Product = Struct.new(:name) do
+ delegate :name, :to => :manufacturer, :prefix => true
+ delegate :name, :to => :type, :prefix => true
+
+ def manufacturer
+ @manufacturer ||= begin
+ nil.unknown_method
+ end
+ end
+
+ def type
+ @type ||= begin
+ nil.type_name
+ end
+ end
+end
+
class ParameterSet
delegate :[], :[]=, :to => :@params
@@ -264,6 +281,16 @@ def test_delegation_invokes_the_target_exactly_once
assert_equal [3], se.ints
end
+ def test_delegation_doesnt_mask_nested_no_method_error_on_nil_receiver
+ product = Product.new('Widget')
+
+ # Nested NoMethodError is a different name from the delegation
+ assert_raise(NoMethodError) { product.manufacturer_name }
+
+ # Nested NoMethodError is the same name as the delegation
+ assert_raise(NoMethodError) { product.type_name }
+ end
+
def test_parent
assert_equal Yz::Zy, Yz::Zy::Cd.parent
assert_equal Yz, Yz::Zy.parent
Please sign in to comment.
Something went wrong with that request. Please try again.