1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Optimize the performance of #delegate

Remove the use of #__send__ in order to boost performance. This also
means that you can no longer delegate to private methods on the
target object.
This commit is contained in:
Daniel Schierbeck 2011-08-29 13:07:03 +02:00 committed by Daniel Schierbeck
parent 1db54dffaf
commit 1bac04e854
2 changed files with 32 additions and 9 deletions

View file

@ -124,23 +124,27 @@ class Module
file, line = caller.first.split(':', 2)
line = line.to_i
if allow_nil
methods.each do |method|
methods.each do |method|
method = method.to_s
# Attribute writer methods only accept one argument. Makes sure []=
# methods still accept two arguments.
definition = (method =~ /[^\]]=$/) ? "arg" : "*args, &block"
if allow_nil
module_eval(<<-EOS, file, line - 2)
def #{method_prefix}#{method}(*args, &block) # def customer_name(*args, &block)
def #{method_prefix}#{method}(#{definition}) # def customer_name(*args, &block)
if #{to} || #{to}.respond_to?(:#{method}) # if client || client.respond_to?(:name)
#{to}.__send__(:#{method}, *args, &block) # client.__send__(:name, *args, &block)
#{to}.#{method}(#{definition}) # client.name(*args, &block)
end # end
end # end
EOS
end
else
methods.each do |method|
else
exception = %(raise "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
module_eval(<<-EOS, file, line - 1)
def #{method_prefix}#{method}(*args, &block) # def customer_name(*args, &block)
#{to}.__send__(:#{method}, *args, &block) # client.__send__(:name, *args, &block)
def #{method_prefix}#{method}(#{definition}) # def customer_name(*args, &block)
#{to}.#{method}(#{definition}) # client.name(*args, &block)
rescue NoMethodError # rescue NoMethodError
if #{to}.nil? # if client.nil?
#{exception} # # add helpful message to the exception

View file

@ -60,6 +60,14 @@ Tester = Struct.new(:client) do
delegate :name, :to => :client, :prefix => false
end
class ParameterSet
delegate :[], :[]=, :to => :@params
def initialize
@params = {:foo => "bar"}
end
end
class Name
delegate :upcase, :to => :@full_name
@ -83,6 +91,17 @@ class ModuleTest < ActiveSupport::TestCase
assert_equal "Fred", @david.place.name
end
def test_delegation_to_index_get_method
@params = ParameterSet.new
assert_equal "bar", @params[:foo]
end
def test_delegation_to_index_set_method
@params = ParameterSet.new
@params[:foo] = "baz"
assert_equal "baz", @params[:foo]
end
def test_delegation_down_hierarchy
assert_equal "CHICAGO", @david.upcase
end