mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
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
This commit is contained in:
parent
ffb1a5d801
commit
a14ba6e3d5
4 changed files with 122 additions and 43 deletions
14
ChangeLog
14
ChangeLog
|
@ -1,3 +1,17 @@
|
||||||
|
Sat Mar 25 23:35:54 2017 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
|
* 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@ruby-lang.org>
|
||||||
|
|
||||||
|
* 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@ruby-lang.org>
|
Tue Dec 27 20:43:54 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* time.c (usec2subsecx): fix return type, which is a numeric object but
|
* time.c (usec2subsecx): fix return type, which is a numeric object but
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# frozen_string_literal: false
|
||||||
#
|
#
|
||||||
# forwardable.rb -
|
# forwardable.rb -
|
||||||
# $Release Version: 1.1$
|
# $Release Version: 1.1$
|
||||||
|
@ -177,33 +178,44 @@ module Forwardable
|
||||||
# q.push 23 #=> NoMethodError
|
# q.push 23 #=> NoMethodError
|
||||||
#
|
#
|
||||||
def def_instance_delegator(accessor, method, ali = method)
|
def def_instance_delegator(accessor, method, ali = method)
|
||||||
accessor = accessor.to_s
|
gen = Forwardable._delegator_method(self, accessor, method, ali)
|
||||||
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
|
|
||||||
}
|
|
||||||
# If it's not a class or module, it's an instance
|
# If it's not a class or module, it's an instance
|
||||||
begin
|
(Module === self ? self : singleton_class).module_eval(&gen)
|
||||||
module_eval(str, __FILE__, line_no)
|
|
||||||
rescue
|
|
||||||
instance_eval(str, __FILE__, line_no)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
alias delegate instance_delegate
|
alias delegate instance_delegate
|
||||||
alias def_delegators def_instance_delegators
|
alias def_delegators def_instance_delegators
|
||||||
alias def_delegator def_instance_delegator
|
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
|
end
|
||||||
|
|
||||||
# SingleForwardable can be used to setup delegation at the object level as well.
|
# 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
|
# the method of the same name in _accessor_). If _new_name_ is
|
||||||
# provided, it is used as the name for the delegate method.
|
# provided, it is used as the name for the delegate method.
|
||||||
def def_single_delegator(accessor, method, ali = method)
|
def def_single_delegator(accessor, method, ali = method)
|
||||||
accessor = accessor.to_s
|
gen = Forwardable._delegator_method(self, accessor, method, ali)
|
||||||
if method_defined?(accessor) || private_method_defined?(accessor)
|
|
||||||
accessor = "#{accessor}()"
|
|
||||||
end
|
|
||||||
|
|
||||||
line_no = __LINE__; str = %{
|
instance_eval(&gen)
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
instance_eval(str, __FILE__, line_no)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
alias delegate single_delegate
|
alias delegate single_delegate
|
||||||
|
|
|
@ -144,7 +144,7 @@ class TestForwardable < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_def_single_delegator
|
def test_class_single_delegator
|
||||||
%i[def_delegator def_single_delegator].each do |m|
|
%i[def_delegator def_single_delegator].each do |m|
|
||||||
cls = single_forwardable_class do
|
cls = single_forwardable_class do
|
||||||
__send__ m, :@receiver, :delegated1
|
__send__ m, :@receiver, :delegated1
|
||||||
|
@ -154,7 +154,7 @@ class TestForwardable < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_def_single_delegators
|
def test_class_single_delegators
|
||||||
%i[def_delegators def_single_delegators].each do |m|
|
%i[def_delegators def_single_delegators].each do |m|
|
||||||
cls = single_forwardable_class do
|
cls = single_forwardable_class do
|
||||||
__send__ m, :@receiver, :delegated1, :delegated2
|
__send__ m, :@receiver, :delegated1, :delegated2
|
||||||
|
@ -165,7 +165,7 @@ class TestForwardable < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_single_delegate
|
def test_class_single_delegate
|
||||||
%i[delegate single_delegate].each do |m|
|
%i[delegate single_delegate].each do |m|
|
||||||
cls = single_forwardable_class do
|
cls = single_forwardable_class do
|
||||||
__send__ m, delegated1: :@receiver, delegated2: :@receiver
|
__send__ m, delegated1: :@receiver, delegated2: :@receiver
|
||||||
|
@ -183,6 +183,45 @@ class TestForwardable < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
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
|
class Foo
|
||||||
extend Forwardable
|
extend Forwardable
|
||||||
|
|
||||||
|
@ -193,6 +232,27 @@ class TestForwardable < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
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
|
private
|
||||||
|
|
||||||
def forwardable_class(
|
def forwardable_class(
|
||||||
|
@ -226,4 +286,11 @@ class TestForwardable < Test::Unit::TestCase
|
||||||
class_exec(&block)
|
class_exec(&block)
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
#define RUBY_VERSION "2.2.7"
|
#define RUBY_VERSION "2.2.7"
|
||||||
#define RUBY_RELEASE_DATE "2017-01-04"
|
#define RUBY_RELEASE_DATE "2017-03-25"
|
||||||
#define RUBY_PATCHLEVEL 418
|
#define RUBY_PATCHLEVEL 419
|
||||||
|
|
||||||
#define RUBY_RELEASE_YEAR 2017
|
#define RUBY_RELEASE_YEAR 2017
|
||||||
#define RUBY_RELEASE_MONTH 1
|
#define RUBY_RELEASE_MONTH 3
|
||||||
#define RUBY_RELEASE_DAY 4
|
#define RUBY_RELEASE_DAY 25
|
||||||
|
|
||||||
#include "ruby/version.h"
|
#include "ruby/version.h"
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue