summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authornagachika <nagachika@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-02-07 17:18:46 +0000
committernagachika <nagachika@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-02-07 17:18:46 +0000
commit1034b6d23dee1ab33e5da4f5d816b2af0cefc062 (patch)
treec67c0a24c6f0a1dc7ba508f838ea77ad76f93146 /lib
parent161f08ba0d090438c1aae47344fdb1724e38a37e (diff)
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_3@57570 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib')
-rw-r--r--lib/forwardable.rb69
1 files changed, 33 insertions, 36 deletions
diff --git a/lib/forwardable.rb b/lib/forwardable.rb
index e20f5e3a31..e78b9ed1e0 100644
--- a/lib/forwardable.rb
+++ b/lib/forwardable.rb
@@ -178,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.
@@ -275,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