* eval.c (rb_using_module): activate refinements in the ancestors of

the argument module to support refinement inheritance by
  Module#include.  [ruby-core:55671] [Feature #8571]

* test/ruby/test_refinement.rb: related test.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@41719 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
shugo 2013-07-01 03:57:16 +00:00
Родитель 551fe2bddc
Коммит 72d3e2b102
4 изменённых файлов: 95 добавлений и 4 удалений

Просмотреть файл

@ -1,3 +1,11 @@
Mon Jul 1 12:56:41 2013 Shugo Maeda <shugo@ruby-lang.org>
* eval.c (rb_using_module): activate refinements in the ancestors of
the argument module to support refinement inheritance by
Module#include. [ruby-core:55671] [Feature #8571]
* test/ruby/test_refinement.rb: related test.
Mon Jul 1 12:02:39 2013 Tanaka Akira <akr@fsij.org> Mon Jul 1 12:02:39 2013 Tanaka Akira <akr@fsij.org>
* bignum.c (rb_cstr_to_inum): Skip leading zeros. * bignum.c (rb_cstr_to_inum): Skip leading zeros.

5
NEWS
Просмотреть файл

@ -46,6 +46,11 @@ with all sufficient information, see the ChangeLog file.
* pack/unpack (Array/String) * pack/unpack (Array/String)
* Q! and q! directives for long long type if platform has the type. * Q! and q! directives for long long type if platform has the type.
* toplevel
* extended methods:
* main.using activates refinements in the ancestors of the argument
module to support refinement inheritance by Module#include.
=== Core classes compatibility issues (excluding feature bug fixes) === Core classes compatibility issues (excluding feature bug fixes)
* IO * IO

32
eval.c
Просмотреть файл

@ -1118,19 +1118,43 @@ using_refinement(VALUE klass, VALUE module, VALUE arg)
return ST_CONTINUE; return ST_CONTINUE;
} }
void static void
rb_using_module(NODE *cref, VALUE module) using_module_recursive(NODE *cref, VALUE klass)
{ {
ID id_refinements; ID id_refinements;
VALUE refinements; VALUE super, module, refinements;
Check_Type(module, T_MODULE); super = RCLASS_SUPER(klass);
if (super) {
using_module_recursive(cref, super);
}
switch (BUILTIN_TYPE(klass)) {
case T_MODULE:
module = klass;
break;
case T_ICLASS:
module = RBASIC(klass)->klass;
break;
default:
rb_raise(rb_eTypeError, "wrong argument type %s (expected Module)",
rb_obj_classname(klass));
break;
}
CONST_ID(id_refinements, "__refinements__"); CONST_ID(id_refinements, "__refinements__");
refinements = rb_attr_get(module, id_refinements); refinements = rb_attr_get(module, id_refinements);
if (NIL_P(refinements)) return; if (NIL_P(refinements)) return;
rb_hash_foreach(refinements, using_refinement, (VALUE) cref); rb_hash_foreach(refinements, using_refinement, (VALUE) cref);
} }
void
rb_using_module(NODE *cref, VALUE module)
{
Check_Type(module, T_MODULE);
using_module_recursive(cref, module);
}
VALUE rb_refinement_module_get_refined_class(VALUE module) VALUE rb_refinement_module_get_refined_class(VALUE module)
{ {
ID id_refined_class; ID id_refined_class;

Просмотреть файл

@ -875,6 +875,60 @@ class TestRefinement < Test::Unit::TestCase
end end
end end
class Bar
end
module BarExt
refine Bar do
def x
return "BarExt#x"
end
end
end
module FooBarExt
include FooExt
include BarExt
end
module FooBarExtClient
using FooBarExt
def self.invoke_x_on(foo)
return foo.x
end
end
def test_module_inclusion
foo = Foo.new
assert_equal("FooExt#x", FooBarExtClient.invoke_x_on(foo))
bar = Bar.new
assert_equal("BarExt#x", FooBarExtClient.invoke_x_on(bar))
end
module FooFoo2Ext
include FooExt
include FooExt2
end
module FooFoo2ExtClient
using FooFoo2Ext
def self.invoke_x_on(foo)
return foo.x
end
def self.invoke_y_on(foo)
return foo.y
end
end
def test_module_inclusion2
foo = Foo.new
assert_equal("FooExt2#x", FooFoo2ExtClient.invoke_x_on(foo))
assert_equal("FooExt2#y Foo#y", FooFoo2ExtClient.invoke_y_on(foo))
end
private private
def eval_using(mod, s) def eval_using(mod, s)