diff options
author | Jeremy Evans <code@jeremyevans.net> | 2019-10-12 01:02:51 -0700 |
---|---|---|
committer | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2019-11-28 19:57:04 +0900 |
commit | a0579f3606561a74e323f6193b9504c06845236c (patch) | |
tree | 3ccff84a2cacdb455ef9259aa15d46eec376b6cb /test | |
parent | 5069c5f5214ce68df8b3954321ad9114c5368dc3 (diff) | |
download | ruby-a0579f3606561a74e323f6193b9504c06845236c.tar.gz |
Make prepending a refined module after inclusion not break refinements
After the previous commit, this was still broken. The reason it
was broken is that a refined module that hasn't been prepended to
yet keeps the refined methods in the module's method table. When
prepending, the module's method table is moved to the origin
iclass, and then the refined methods are moved from the method
table to a new method table in the module itself.
Unfortunately, that means that if a class has included the module,
prepending breaks the refinements, because when the methods are
moved from the origin iclass method table to the module method
table, they are removed from the method table from the iclass
created when the module was included earlier.
Fix this by always creating an origin class when including a
module that has any refinements, even if the refinements are
not currently used. I wasn't sure the best way to do that.
The approach I choose was to use an object flag. The flag is
set on the module when Module#refine is called, and if the
flag is present when the module is included in another module
or class, an origin iclass is created for the module.
Fixes [Bug #13446]
Diffstat (limited to 'test')
-rw-r--r-- | test/ruby/test_refinement.rb | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb index 618175f931..6fb04de5d6 100644 --- a/test/ruby/test_refinement.rb +++ b/test/ruby/test_refinement.rb @@ -2350,6 +2350,38 @@ class TestRefinement < Test::Unit::TestCase assert_equal("refine_method", Bug16242::X.new.hoge) end + module Bug13446 + module Enumerable + def sum(*args) + i = 0 + args.each { |arg| i += a } + i + end + end + + using Module.new { + refine Enumerable do + alias :orig_sum :sum + end + } + + module Enumerable + def sum(*args) + orig_sum(*args) + end + end + + class GenericEnumerable + include Enumerable + end + + Enumerable.prepend(Module.new) + end + + def test_prepend_refined_module + assert_equal(0, Bug13446::GenericEnumerable.new.sum) + end + private def eval_using(mod, s) |