diff options
author | shugo <shugo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-12-10 16:05:45 +0000 |
---|---|---|
committer | shugo <shugo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-12-10 16:05:45 +0000 |
commit | 7ef16d224a80a6e1e8c01b5b45ac7e2315a04e4c (patch) | |
tree | c0ac99c10c8f3d5a9e9529de1460575ae8f4d401 /test/ruby/test_refinement.rb | |
parent | fa7c4ab4084ac6d5ad615d133ab0dcaca2c817fb (diff) | |
download | ruby-7ef16d224a80a6e1e8c01b5b45ac7e2315a04e4c.tar.gz |
* fix the behavior when a module is included into a refinement.
This change is a little tricky, so it might be better to prohibit
module inclusion to refinements.
* include/ruby/ruby.h (RMODULE_INCLUDED_INTO_REFINEMENT): new flag
to represent that a module (iclass) is included into a refinement.
* class.c (include_modules_at): set RMODULE_INCLUDED_INTO_REFINEMENT
if klass is a refinement.
* eval.c (rb_mod_refine): set the superclass of a refinement to the
refined class for super.
* eval.c (rb_using_refinement): skip the above superclass (the
refined class) when creating iclasses for refinements. Otherwise,
`using Refinement1; using Refinement2' creates iclasses:
<Refinement2> -> <RefinedClass> -> <Refinement1> -> RefinedClass,
where <Module> is an iclass for Module, so RefinedClass is
searched before Refinement1. The correct iclasses should be
<Refinement2> -> <Refinement1> -> RefinedClass.
* vm_insnhelper.c (vm_search_normal_superclass): if klass is an
iclass for a refinement, use the refinement's superclass instead
of the iclass's superclass. Otherwise, multiple refinements are
searched by super. For example, if a refinement Refinement2
includes a module M (i.e., Refinement2 -> <M> -> RefinedClass,
and if refinements iclasses are <Refinement2> -> <M>' ->
<Refinement1> -> RefinedClass, then super in <Refinement2> should
use Refinement2's superclass <M> instead of <Refinement2>'s
superclass <M>'.
* vm_insnhelper.c (vm_search_super_method): do not raise a
NotImplementError if current_defind_class is a module included
into a refinement. Because of the change of
vm_search_normal_superclass(), the receiver might not be an
instance of the module('s iclass).
* test/ruby/test_refinement.rb: related test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38298 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'test/ruby/test_refinement.rb')
-rw-r--r-- | test/ruby/test_refinement.rb | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb index 17896eb01d..d572413def 100644 --- a/test/ruby/test_refinement.rb +++ b/test/ruby/test_refinement.rb @@ -13,6 +13,10 @@ class TestRefinement < Test::Unit::TestCase return "Foo#y" end + def a + return "Foo#a" + end + def call_x return x end @@ -31,6 +35,10 @@ class TestRefinement < Test::Unit::TestCase def z return "FooExt#z" end + + def a + return "FooExt#a" + end end end @@ -98,6 +106,10 @@ class TestRefinement < Test::Unit::TestCase def self.invoke_y_on(foo) return foo.y end + + def self.invoke_a_on(foo) + return foo.a + end end EOF @@ -122,6 +134,13 @@ class TestRefinement < Test::Unit::TestCase assert_equal("Foo#y", foo.y) end + def test_using_same_class_refinements + foo = Foo.new + assert_equal("Foo#a", foo.a) + assert_equal("FooExt#a", FooExtClient2.invoke_a_on(foo)) + assert_equal("Foo#a", foo.a) + end + def test_new_method foo = Foo.new assert_raise(NoMethodError) { foo.z } @@ -610,6 +629,69 @@ class TestRefinement < Test::Unit::TestCase end end + module IncludeIntoRefinement + class C + def bar + return "C#bar" + end + + def baz + return "C#baz" + end + end + + module Mixin + def foo + return "Mixin#foo" + end + + def bar + return super << " Mixin#bar" + end + + def baz + return super << " Mixin#baz" + end + end + + module M + refine C do + include Mixin + + def baz + return super << " M#baz" + end + end + end + end + + eval <<-EOF, TOPLEVEL_BINDING + using TestRefinement::IncludeIntoRefinement::M + + module TestRefinement::IncludeIntoRefinement::User + def self.invoke_foo_on(x) + x.foo + end + + def self.invoke_bar_on(x) + x.bar + end + + def self.invoke_baz_on(x) + x.baz + end + end + EOF + + def test_include_into_refinement + x = IncludeIntoRefinement::C.new + assert_equal("Mixin#foo", IncludeIntoRefinement::User.invoke_foo_on(x)) + assert_equal("C#bar Mixin#bar", + IncludeIntoRefinement::User.invoke_bar_on(x)) + assert_equal("C#baz Mixin#baz M#baz", + IncludeIntoRefinement::User.invoke_baz_on(x)) + end + private def eval_using(mod, s) |