diff options
author | usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2014-04-30 06:32:24 +0000 |
---|---|---|
committer | usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2014-04-30 06:32:24 +0000 |
commit | 292d506856ad0a3a0e22df29a1b1118015f3ddc1 (patch) | |
tree | e21bb20156fbf9780c0fa1aa188446afafa541cc | |
parent | bb479d71b7811e7705574fd5b0d6d88108707d20 (diff) | |
download | ruby-292d506856ad0a3a0e22df29a1b1118015f3ddc1.tar.gz |
merge revision(s) 43682,43727,43752,43759: [Backport #9560]
* lib/delegate.rb (Delegator#send): override to get rid of global function interference.
[Fixes GH-449]
* lib/delegate.rb (Delegator#send): separate from method_missing so
that super calls proper method.
* lib/delegate.rb (Delegator#method_missing): try private methods defined in
Kernel after the target. [Fixes GH-449]
* lib/delegate.rb (SimpleDelegator#__getobj__): target object must be set.
* lib/delegate.rb (DelegateClass#__getobj__): ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_0_0@45747 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 21 | ||||
-rw-r--r-- | lib/delegate.rb | 27 | ||||
-rw-r--r-- | test/ruby/envutil.rb | 23 | ||||
-rw-r--r-- | test/test_delegate.rb | 36 | ||||
-rw-r--r-- | version.h | 2 |
5 files changed, 102 insertions, 7 deletions
@@ -1,3 +1,24 @@ +Wed Apr 30 15:20:44 2014 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * lib/delegate.rb (SimpleDelegator#__getobj__): target object must be set. + + * lib/delegate.rb (DelegateClass#__getobj__): ditto. + +Wed Apr 30 15:20:44 2014 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * lib/delegate.rb (Delegator#method_missing): try private methods defined in + Kernel after the target. [Fixes GH-449] + +Wed Apr 30 15:20:44 2014 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * lib/delegate.rb (Delegator#send): separate from method_missing so + that super calls proper method. + +Wed Apr 30 15:20:44 2014 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * lib/delegate.rb (Delegator#send): override to get rid of global function interference. + [Fixes GH-449] + Wed Apr 30 15:04:25 2014 Nobuyoshi Nakada <nobu@ruby-lang.org> * ext/readline/extconf.rb: fix typo, `$defs` not `$DEFS`. diff --git a/lib/delegate.rb b/lib/delegate.rb index e46e4f8c23..b4d495edea 100644 --- a/lib/delegate.rb +++ b/lib/delegate.rb @@ -43,9 +43,16 @@ class Delegator < BasicObject kernel = ::Kernel.dup kernel.class_eval do + alias __raise__ raise [:to_s,:inspect,:=~,:!~,:===,:<=>,:eql?,:hash].each do |m| undef_method m end + private_instance_methods.each do |m| + if /\Ablock_given\?\z|iterator\?\z|\A__raise__\z/ =~ m + next + end + undef_method m + end end include kernel @@ -69,9 +76,15 @@ class Delegator < BasicObject def method_missing(m, *args, &block) target = self.__getobj__ begin - target.respond_to?(m) ? target.__send__(m, *args, &block) : super(m, *args, &block) + if target.respond_to?(m) + target.__send__(m, *args, &block) + elsif ::Kernel.respond_to?(m, true) + ::Kernel.instance_method(m).bind(self).(*args, &block) + else + super(m, *args, &block) + end ensure - $@.delete_if {|t| %r"\A#{Regexp.quote(__FILE__)}:#{__LINE__-2}:"o =~ t} if $@ + $@.delete_if {|t| %r"\A#{Regexp.quote(__FILE__)}:(?:#{[__LINE__-7, __LINE__-5, __LINE__-3].join('|')}):"o =~ t} if $@ end end @@ -142,7 +155,7 @@ class Delegator < BasicObject # method calls are being delegated to. # def __getobj__ - raise NotImplementedError, "need to define `__getobj__'" + __raise__ ::NotImplementedError, "need to define `__getobj__'" end # @@ -150,7 +163,7 @@ class Delegator < BasicObject # to _obj_. # def __setobj__(obj) - raise NotImplementedError, "need to define `__setobj__'" + __raise__ ::NotImplementedError, "need to define `__setobj__'" end # @@ -265,6 +278,7 @@ end class SimpleDelegator<Delegator # Returns the current object method calls are being delegated to. def __getobj__ + __raise__ ::ArgumentError, "not delegated" unless defined?(@delegate_sd_obj) @delegate_sd_obj end @@ -283,7 +297,7 @@ class SimpleDelegator<Delegator # puts names[1] # => Sinclair # def __setobj__(obj) - raise ArgumentError, "cannot delegate to self" if self.equal?(obj) + __raise__ ::ArgumentError, "cannot delegate to self" if self.equal?(obj) @delegate_sd_obj = obj end end @@ -339,10 +353,11 @@ def DelegateClass(superclass) methods -= [:to_s,:inspect,:=~,:!~,:===] klass.module_eval do def __getobj__ # :nodoc: + __raise__ ::ArgumentError, "not delegated" unless defined?(@delegate_dc_obj) @delegate_dc_obj end def __setobj__(obj) # :nodoc: - raise ArgumentError, "cannot delegate to self" if self.equal?(obj) + __raise__ ::ArgumentError, "cannot delegate to self" if self.equal?(obj) @delegate_dc_obj = obj end methods.each do |method| diff --git a/test/ruby/envutil.rb b/test/ruby/envutil.rb index 948cbc25bc..cfc16d1d86 100644 --- a/test/ruby/envutil.rb +++ b/test/ruby/envutil.rb @@ -379,6 +379,29 @@ eom AssertFile end + def assert_raise_with_message(exception, expected, msg = nil, &block) + case expected + when String + assert = :assert_equal + when Regexp + assert = :assert_match + else + raise TypeError, "Expected #{expected.inspect} to be a kind of String or Regexp, not #{expected.class}" + end + + ex = assert_raise(exception, *msg) {yield} + msg = message(msg, "") {"Expected Exception(#{exception}) was raised, but the message doesn't match"} + + if assert == :assert_equal + assert_equal(expected, ex.message, msg) + else + msg = message(msg) { "Expected #{mu_pp expected} to match #{mu_pp ex.message}" } + assert expected =~ ex.message, msg + block.binding.eval("proc{|_|$~=_}").call($~) + end + ex + end + class << (AssertFile = Struct.new(:message).new) include Assertions def assert_file_predicate(predicate, *args) diff --git a/test/test_delegate.rb b/test/test_delegate.rb index a09451b88f..dfe9f1db10 100644 --- a/test/test_delegate.rb +++ b/test/test_delegate.rb @@ -1,5 +1,6 @@ require 'test/unit' require 'delegate' +require_relative 'ruby/envutil' class TestDelegateClass < Test::Unit::TestCase module M @@ -133,4 +134,39 @@ class TestDelegateClass < Test::Unit::TestCase assert_raise(NoMethodError, '[ruby-dev:40314]#4') {d.delegate_test_private} assert_raise(NoMethodError, '[ruby-dev:40314]#5') {d.send(:delegate_test_private)} end + + def test_global_function + klass = Class.new do + def open + end + end + obj = klass.new + d = SimpleDelegator.new(obj) + assert_nothing_raised(ArgumentError) {obj.open} + assert_nothing_raised(ArgumentError) {d.open} + assert_nothing_raised(ArgumentError) {d.send(:open)} + end + + def test_send_method_in_delegator + d = Class.new(SimpleDelegator) do + def foo + "foo" + end + end.new(Object.new) + assert_equal("foo", d.send(:foo)) + end + + def test_unset_simple_delegator + d = SimpleDelegator.allocate + assert_raise_with_message(ArgumentError, /not delegated/) { + d.__getobj__ + } + end + + def test_unset_delegate_class + d = IV.allocate + assert_raise_with_message(ArgumentError, /not delegated/) { + d.__getobj__ + } + end end @@ -1,6 +1,6 @@ #define RUBY_VERSION "2.0.0" #define RUBY_RELEASE_DATE "2014-04-30" -#define RUBY_PATCHLEVEL 467 +#define RUBY_PATCHLEVEL 468 #define RUBY_RELEASE_YEAR 2014 #define RUBY_RELEASE_MONTH 4 |