mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
forwardable.rb: fix for non-module objects
* 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/trunk@55366 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
10174c295b
commit
b661824e75
3 changed files with 87 additions and 48 deletions
|
@ -1,3 +1,9 @@
|
|||
Fri Jun 10 21:54:24 2016 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]
|
||||
|
||||
Fri Jun 10 17:35:11 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
|
||||
|
||||
* string.c: Special-case :ascii option in rb_str_capitalize_bang and
|
||||
|
|
|
@ -178,38 +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
|
||||
|
||||
line_no = __LINE__; str = %{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}
|
||||
|
||||
gen = RubyVM::InstructionSequence
|
||||
.compile(str, __FILE__, __FILE__, line_no,
|
||||
trace_instruction: false,
|
||||
tailcall_optimization: true)
|
||||
.eval
|
||||
gen = Forwardable._delegator_method(self, accessor, method, ali)
|
||||
|
||||
# If it's not a class or module, it's an instance
|
||||
begin
|
||||
module_eval(&gen)
|
||||
rescue
|
||||
instance_eval(&gen)
|
||||
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.
|
||||
|
@ -280,26 +286,7 @@ 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 = %{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}
|
||||
|
||||
gen = RubyVM::InstructionSequence
|
||||
.compile(str, __FILE__, __FILE__, line_no,
|
||||
trace_instruction: false,
|
||||
tailcall_optimization: true)
|
||||
.eval
|
||||
gen = Forwardable._delegator_method(self, accessor, method, ali)
|
||||
|
||||
instance_eval(&gen)
|
||||
end
|
||||
|
|
|
@ -144,7 +144,7 @@ class TestForwardable < Test::Unit::TestCase
|
|||
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::TestCase
|
|||
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::TestCase
|
|||
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::TestCase
|
|||
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
|
||||
|
||||
|
@ -247,4 +286,11 @@ class TestForwardable < Test::Unit::TestCase
|
|||
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
|
||||
|
|
Loading…
Reference in a new issue