Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Module.delegate #2275

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 20 additions & 17 deletions activesupport/lib/active_support/core_ext/module/delegation.rb
Expand Up @@ -109,7 +109,7 @@ def delegate(*methods)
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

if options[:prefix] == true && options[:to].to_s =~ /^[^a-z_]/
if options[:prefix] == true && to.to_s =~ /^[^a-z_]/
raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method."
end

Expand All @@ -119,24 +119,27 @@ def delegate(*methods)
line = line.to_i

methods.each do |method|
on_nil =
if options[:allow_nil]
'return'
else
%(raise "#{self}##{prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
method_name = prefix + method.to_s
module_eval(<<-EOS, file, line - 1)
def #{method_name}(*args, &block)
ActiveSupport::Delegation.perform(self, #{to}, #{method.inspect}, #{method_name.inspect}, #{options[:allow_nil].inspect}, #{options[:to].inspect}, args, block)
end

module_eval(<<-EOS, file, line - 5)
def #{prefix}#{method}(*args, &block) # def customer_name(*args, &block)
#{to}.__send__(#{method.inspect}, *args, &block) # client.__send__(:name, *args, &block)
rescue NoMethodError # rescue NoMethodError
if #{to}.nil? # if client.nil?
#{on_nil} # return # depends on :allow_nil
else # else
raise # raise
end # end
end # end
EOS
end
end
end

module ActiveSupport
module Delegation #:nodoc:
def self.perform(object, target, method, method_name, allow_nil, to, args, block)
target.__send__(method, *args, &block)
rescue NoMethodError
if target.nil?
return nil if allow_nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'd be clearer to have a separate method that swallows nils, rather than passing allow_nil and conditionally handling it here.

raise "#{object.class}##{method_name} delegated to #{to}.#{method}, but #{to} is nil: #{object.inspect}"
else
raise
end
end
end
end