From a14ba6e3d58d6f63f47c0549f60306c4989478ba Mon Sep 17 00:00:00 2001 From: usa Date: Sat, 25 Mar 2017 14:43:16 +0000 Subject: merge revision(s) 53383,55366: [Backport #12478] * lib/forwardable.rb (def_instance_delegator): adjust backtrace of method body by tail call optimization. adjusting the delegated target is still done by deleting backtrace. * lib/forwardable.rb (def_single_delegator): ditto. * lib/forwardable.rb (Forwardable._delegator_method): extract method generator and deal with non-module objects. [ruby-dev:49656] [Bug #12478] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_2@58085 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/forwardable.rb | 70 ++++++++++++++++++++++++++---------------------------- 1 file changed, 34 insertions(+), 36 deletions(-) (limited to 'lib') diff --git a/lib/forwardable.rb b/lib/forwardable.rb index 602cd8b815..e78b9ed1e0 100644 --- a/lib/forwardable.rb +++ b/lib/forwardable.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: false # # forwardable.rb - # $Release Version: 1.1$ @@ -177,33 +178,44 @@ module Forwardable # q.push 23 #=> NoMethodError # def def_instance_delegator(accessor, method, ali = method) - accessor = accessor.to_s - if method_defined?(accessor) || private_method_defined?(accessor) - accessor = "#{accessor}()" - end + gen = Forwardable._delegator_method(self, accessor, method, ali) - line_no = __LINE__; str = %{ - def #{ali}(*args, &block) - begin - #{accessor}.__send__(:#{method}, *args, &block) - rescue Exception - $@.delete_if{|s| Forwardable::FILE_REGEXP =~ s} unless Forwardable::debug - ::Kernel::raise - end - end - } # If it's not a class or module, it's an instance - begin - module_eval(str, __FILE__, line_no) - rescue - instance_eval(str, __FILE__, line_no) - end - + (Module === self ? self : singleton_class).module_eval(&gen) end alias delegate instance_delegate alias def_delegators def_instance_delegators alias def_delegator def_instance_delegator + + def self._delegator_method(obj, accessor, method, ali) + accessor = accessor.to_s unless Symbol === accessor + + if Module === obj ? + obj.method_defined?(accessor) || obj.private_method_defined?(accessor) : + obj.respond_to?(accessor, true) + accessor = "#{accessor}()" + end + + line_no = __LINE__+1; str = "#{<<-"begin;"}\n#{<<-"end;"}" + begin; + proc do + def #{ali}(*args, &block) + begin + #{accessor} + ensure + $@.delete_if {|s| ::Forwardable::FILE_REGEXP =~ s} if $@ and !::Forwardable::debug + end.__send__ :#{method}, *args, &block + end + end + end; + + RubyVM::InstructionSequence + .compile(str, __FILE__, __FILE__, line_no, + trace_instruction: false, + tailcall_optimization: true) + .eval + end end # SingleForwardable can be used to setup delegation at the object level as well. @@ -274,23 +286,9 @@ module SingleForwardable # the method of the same name in _accessor_). If _new_name_ is # provided, it is used as the name for the delegate method. def def_single_delegator(accessor, method, ali = method) - accessor = accessor.to_s - if method_defined?(accessor) || private_method_defined?(accessor) - accessor = "#{accessor}()" - end - - line_no = __LINE__; str = %{ - def #{ali}(*args, &block) - begin - #{accessor}.__send__(:#{method}, *args, &block) - rescue Exception - $@.delete_if{|s| Forwardable::FILE_REGEXP =~ s} unless Forwardable::debug - ::Kernel::raise - end - end - } + gen = Forwardable._delegator_method(self, accessor, method, ali) - instance_eval(str, __FILE__, line_no) + instance_eval(&gen) end alias delegate single_delegate -- cgit v1.2.3