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:
parent
8a15e08006
commit
633fef6dec
4 changed files with 64 additions and 3 deletions
4
NEWS
4
NEWS
|
@ -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]
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
12
vm_eval.c
12
vm_eval.c
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue