aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support/core_ext/module/delegation.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport/lib/active_support/core_ext/module/delegation.rb')
-rw-r--r--activesupport/lib/active_support/core_ext/module/delegation.rb29
1 files changed, 20 insertions, 9 deletions
diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb
index 9fe7f8fe01..14d7f0c484 100644
--- a/activesupport/lib/active_support/core_ext/module/delegation.rb
+++ b/activesupport/lib/active_support/core_ext/module/delegation.rb
@@ -205,18 +205,18 @@ class Module
if allow_nil
method_def = [
"def #{method_prefix}#{method}(#{definition})",
- "_ = #{to}",
- "if !_.nil? || nil.respond_to?(:#{method})",
- " _.#{method}(#{definition})",
- "end",
- "end"
+ " _ = #{to}",
+ " if !_.nil? || nil.respond_to?(:#{method})",
+ " _.#{method}(#{definition})",
+ " end",
+ "end"
].join ";"
else
exception = %(raise DelegationError, "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
method_def = [
"def #{method_prefix}#{method}(#{definition})",
- " _ = #{to}",
+ " _ = #{to}",
" _.#{method}(#{definition})",
"rescue NoMethodError => e",
" if _.nil? && e.name == :#{method}",
@@ -274,8 +274,14 @@ class Module
# variables, methods, constants, etc.
#
# The delegated method must be public on the target, otherwise it will
- # raise +NoMethodError+.
- def delegate_missing_to(target)
+ # raise +DelegationError+. If you wish to instead return +nil+,
+ # use the <tt>:allow_nil</tt> option.
+ #
+ # The <tt>marshal_dump</tt> and <tt>_dump</tt> methods are exempt from
+ # delegation due to possible interference when calling
+ # <tt>Marshal.dump(object)</tt>, should the delegation target method
+ # of <tt>object</tt> add or remove instance variables.
+ def delegate_missing_to(target, allow_nil: nil)
target = target.to_s
target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target)
@@ -284,6 +290,7 @@ class Module
# It may look like an oversight, but we deliberately do not pass
# +include_private+, because they do not get delegated.
+ return false if name == :marshal_dump || name == :_dump
#{target}.respond_to?(name) || super
end
@@ -295,7 +302,11 @@ class Module
super
rescue NoMethodError
if #{target}.nil?
- raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
+ if #{allow_nil == true}
+ nil
+ else
+ raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
+ end
else
raise
end