ruby-changes:46014
From: usa <ko1@a...>
Date: Sat, 25 Mar 2017 23:43:26 +0900 (JST)
Subject: [ruby-changes:46014] usa:r58085 (ruby_2_2): merge revision(s) 53383, 55366: [Backport #12478]
usa 2017-03-25 23:43:16 +0900 (Sat, 25 Mar 2017) New Revision: 58085 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=58085 Log: 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] Modified directories: branches/ruby_2_2/ Modified files: branches/ruby_2_2/ChangeLog branches/ruby_2_2/lib/forwardable.rb branches/ruby_2_2/test/test_forwardable.rb branches/ruby_2_2/version.h Index: ruby_2_2/lib/forwardable.rb =================================================================== --- ruby_2_2/lib/forwardable.rb (revision 58084) +++ ruby_2_2/lib/forwardable.rb (revision 58085) @@ -1,3 +1,4 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_2/lib/forwardable.rb#L1 +# frozen_string_literal: false # # forwardable.rb - # $Release Version: 1.1$ @@ -177,33 +178,44 @@ module Forwardable https://github.com/ruby/ruby/blob/trunk/ruby_2_2/lib/forwardable.rb#L178 # 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 https://github.com/ruby/ruby/blob/trunk/ruby_2_2/lib/forwardable.rb#L286 # 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 Index: ruby_2_2/version.h =================================================================== --- ruby_2_2/version.h (revision 58084) +++ ruby_2_2/version.h (revision 58085) @@ -1,10 +1,10 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_2/version.h#L1 #define RUBY_VERSION "2.2.7" -#define RUBY_RELEASE_DATE "2017-01-04" -#define RUBY_PATCHLEVEL 418 +#define RUBY_RELEASE_DATE "2017-03-25" +#define RUBY_PATCHLEVEL 419 #define RUBY_RELEASE_YEAR 2017 -#define RUBY_RELEASE_MONTH 1 -#define RUBY_RELEASE_DAY 4 +#define RUBY_RELEASE_MONTH 3 +#define RUBY_RELEASE_DAY 25 #include "ruby/version.h" Index: ruby_2_2/ChangeLog =================================================================== --- ruby_2_2/ChangeLog (revision 58084) +++ ruby_2_2/ChangeLog (revision 58085) @@ -1,3 +1,17 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_2/ChangeLog#L1 +Sat Mar 25 23:35:54 2017 Nobuyoshi Nakada <nobu@r...> + + * lib/forwardable.rb (Forwardable._delegator_method): extract + method generator and deal with non-module objects. + [ruby-dev:49656] [Bug #12478] + +Sat Mar 25 23:35:54 2017 Nobuyoshi Nakada <nobu@r...> + + * 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. + Tue Dec 27 20:43:54 2016 Nobuyoshi Nakada <nobu@r...> * time.c (usec2subsecx): fix return type, which is a numeric object but Index: ruby_2_2/test/test_forwardable.rb =================================================================== --- ruby_2_2/test/test_forwardable.rb (revision 58084) +++ ruby_2_2/test/test_forwardable.rb (revision 58085) @@ -144,7 +144,7 @@ class TestForwardable < Test::Unit::Test https://github.com/ruby/ruby/blob/trunk/ruby_2_2/test/test_forwardable.rb#L144 end end - def test_def_single_delegator + def test_class_single_delegator %i[def_delegator def_single_delegator].each do |m| cls = single_forwardable_class do __send__ m, :@receiver, :delegated1 @@ -154,7 +154,7 @@ class TestForwardable < Test::Unit::Test https://github.com/ruby/ruby/blob/trunk/ruby_2_2/test/test_forwardable.rb#L154 end end - def test_def_single_delegators + def test_class_single_delegators %i[def_delegators def_single_delegators].each do |m| cls = single_forwardable_class do __send__ m, :@receiver, :delegated1, :delegated2 @@ -165,7 +165,7 @@ class TestForwardable < Test::Unit::Test https://github.com/ruby/ruby/blob/trunk/ruby_2_2/test/test_forwardable.rb#L165 end end - def test_single_delegate + def test_class_single_delegate %i[delegate single_delegate].each do |m| cls = single_forwardable_class do __send__ m, delegated1: :@receiver, delegated2: :@receiver @@ -183,6 +183,45 @@ class TestForwardable < Test::Unit::Test https://github.com/ruby/ruby/blob/trunk/ruby_2_2/test/test_forwardable.rb#L183 end end + def test_obj_single_delegator + %i[def_delegator def_single_delegator].each do |m| + obj = single_forwardable_object do + __send__ m, :@receiver, :delegated1 + end + + assert_same RETURNED1, obj.delegated1 + end + end + + def test_obj_single_delegators + %i[def_delegators def_single_delegators].each do |m| + obj = single_forwardable_object do + __send__ m, :@receiver, :delegated1, :delegated2 + end + + assert_same RETURNED1, obj.delegated1 + assert_same RETURNED2, obj.delegated2 + end + end + + def test_obj_single_delegate + %i[delegate single_delegate].each do |m| + obj = single_forwardable_object do + __send__ m, delegated1: :@receiver, delegated2: :@receiver + end + + assert_same RETURNED1, obj.delegated1 + assert_same RETURNED2, obj.delegated2 + + obj = single_forwardable_object do + __send__ m, %i[delegated1 delegated2] => :@receiver + end + + assert_same RETURNED1, obj.delegated1 + assert_same RETURNED2, obj.delegated2 + end + end + class Foo extend Forwardable @@ -193,6 +232,27 @@ class TestForwardable < Test::Unit::Test https://github.com/ruby/ruby/blob/trunk/ruby_2_2/test/test_forwardable.rb#L232 end end + def test_backtrace_adjustment + e = assert_raise(NameError) { + Foo.new.baz + } + assert_not_match(/\/forwardable\.rb/, e.backtrace[0]) + assert_equal(caller(0, 1)[0], Foo.new.c[0]) + end + + class Foo2 < BasicObject + extend ::Forwardable + + def_delegator :bar, :baz + end + + def test_basicobject_subclass + bug11616 = '[ruby-core:71176] [Bug #11616]' + assert_raise_with_message(NameError, /`bar'/, bug11616) { + Foo2.new.baz + } + end + private def forwardable_class( @@ -226,4 +286,11 @@ class TestForwardable < Test::Unit::Test https://github.com/ruby/ruby/blob/trunk/ruby_2_2/test/test_forwardable.rb#L286 class_exec(&block) end end + + def single_forwardable_object(&block) + obj = Object.new.extend SingleForwardable + obj.instance_variable_set(:@receiver, RECEIVER) + obj.instance_eval(&block) + obj + end end Property changes on: ruby_2_2 ___________________________________________________________________ Modified: svn:mergeinfo Merged /trunk:r53383 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/