1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Enable refinements to public_send.

[Feature #15326] [Fix GH-2019]

From: manga_osyo <manga.osyo@gmail.com>

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@65919 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2018-11-22 07:53:07 +00:00
parent 8a15e08006
commit 633fef6dec
4 changed files with 64 additions and 3 deletions

4
NEWS
View file

@ -16,7 +16,9 @@ sufficient information, see the ChangeLog file or Redmine
* <code>$SAFE</code> is a process global state and we can set 0 again. [Feature #14250] * <code>$SAFE</code> is a process global state and we can set 0 again. [Feature #14250]
* refinements take place at block passing. [Feature #14223] * refinements takes place at block passing. [Feature #14223]
* refinements takes place at Kernel#public_send. [Feature #15326]
* +else+ without +rescue+ now causes a syntax error. [EXPERIMENTAL] * +else+ without +rescue+ now causes a syntax error. [EXPERIMENTAL]

View file

@ -425,6 +425,24 @@ describe "Module#refine" do
end end
end end
ruby_version_is "2.6" do
it "is honored by Kernel#public_send" do
refinement = Module.new do
refine ModuleSpecs::ClassWithFoo do
def foo; "foo from refinement"; end
end
end
result = nil
Module.new do
using refinement
result = ModuleSpecs::ClassWithFoo.new.public_send :foo
end
result.should == "foo from refinement"
end
end
ruby_version_is "" ... "2.5" do ruby_version_is "" ... "2.5" do
it "is not honored by string interpolation" do it "is not honored by string interpolation" do
refinement = Module.new do refinement = Module.new do

View file

@ -19,6 +19,10 @@ class TestRefinement < Test::Unit::TestCase
return "Foo#a" return "Foo#a"
end end
def b
return "Foo#b"
end
def call_x def call_x
return x return x
end end
@ -41,6 +45,10 @@ class TestRefinement < Test::Unit::TestCase
def a def a
return "FooExt#a" return "FooExt#a"
end end
private def b
return "FooExt#b"
end
end end
end end
@ -94,6 +102,18 @@ class TestRefinement < Test::Unit::TestCase
return foo.send(:z) return foo.send(:z)
end end
def self.send_b_on(foo)
return foo.send(:b)
end
def self.public_send_z_on(foo)
return foo.public_send(:z)
end
def self.public_send_b_on(foo)
return foo.public_send(:b)
end
def self.method_z(foo) def self.method_z(foo)
return foo.method(:z) return foo.method(:z)
end end
@ -179,11 +199,20 @@ class TestRefinement < Test::Unit::TestCase
foo = Foo.new foo = Foo.new
assert_raise(NoMethodError) { foo.send(:z) } assert_raise(NoMethodError) { foo.send(:z) }
assert_equal("FooExt#z", FooExtClient.send_z_on(foo)) assert_equal("FooExt#z", FooExtClient.send_z_on(foo))
assert_equal("FooExt#b", FooExtClient.send_b_on(foo))
assert_raise(NoMethodError) { foo.send(:z) } assert_raise(NoMethodError) { foo.send(:z) }
assert_equal(true, RespondTo::Sub.new.respond_to?(:foo)) assert_equal(true, RespondTo::Sub.new.respond_to?(:foo))
end end
def test_public_send_should_use_refinements
foo = Foo.new
assert_raise(NoMethodError) { foo.public_send(:z) }
assert_equal("FooExt#z", FooExtClient.public_send_z_on(foo))
assert_equal("Foo#b", foo.public_send(:b))
assert_raise(NoMethodError) { FooExtClient.public_send_b_on(foo) }
end
def test_method_should_not_use_refinements def test_method_should_not_use_refinements
foo = Foo.new foo = Foo.new
assert_raise(NameError) { foo.method(:z) } assert_raise(NameError) { foo.method(:z) }
@ -907,6 +936,10 @@ class TestRefinement < Test::Unit::TestCase
return foo.send(:z) return foo.send(:z)
end end
def self.public_send_z_on(foo)
return foo.public_send(:z)
end
def self.method_z(foo) def self.method_z(foo)
return foo.method(:z) return foo.method(:z)
end end

View file

@ -290,8 +290,16 @@ rb_call0(rb_execution_context_t *ec,
VALUE recv, ID mid, int argc, const VALUE *argv, VALUE recv, ID mid, int argc, const VALUE *argv,
call_type scope, VALUE self) call_type scope, VALUE self)
{ {
const rb_callable_method_entry_t *me = rb_search_method_entry(recv, mid); const rb_callable_method_entry_t *me;
enum method_missing_reason call_status = rb_method_call_status(ec, me, scope, self); enum method_missing_reason call_status;
if (scope == CALL_PUBLIC) {
me = rb_callable_method_entry_with_refinements(CLASS_OF(recv), mid, NULL);
}
else {
me = rb_search_method_entry(recv, mid);
}
call_status = rb_method_call_status(ec, me, scope, self);
if (call_status != MISSING_NONE) { if (call_status != MISSING_NONE) {
return method_missing(recv, mid, argc, argv, call_status); return method_missing(recv, mid, argc, argv, call_status);