summaryrefslogtreecommitdiff
path: root/spec/ruby/core/module/refine_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/core/module/refine_spec.rb')
-rw-r--r--spec/ruby/core/module/refine_spec.rb482
1 files changed, 269 insertions, 213 deletions
diff --git a/spec/ruby/core/module/refine_spec.rb b/spec/ruby/core/module/refine_spec.rb
index ca7db0c2b6..d0fc7015f8 100644
--- a/spec/ruby/core/module/refine_spec.rb
+++ b/spec/ruby/core/module/refine_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/refine', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/refine'
describe "Module#refine" do
it "runs its block in an anonymous module" do
@@ -11,7 +11,7 @@ describe "Module#refine" do
end
mod.should_not == inner_self
- inner_self.should be_kind_of(Module)
+ inner_self.should.is_a?(Module)
inner_self.name.should == nil
end
@@ -43,7 +43,7 @@ describe "Module#refine" do
end
end
- inner_self.public_instance_methods.should include(:blah)
+ inner_self.public_instance_methods.should.include?(:blah)
end
it "returns created anonymous module" do
@@ -59,54 +59,65 @@ describe "Module#refine" do
end
it "raises ArgumentError if not passed an argument" do
- lambda do
+ -> do
Module.new do
refine {}
end
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "raises TypeError if not passed a class" do
- lambda do
+ -> do
Module.new do
refine("foo") {}
end
- end.should raise_error(TypeError)
+ end.should.raise(TypeError, "wrong argument type String (expected Class or Module)")
end
- ruby_version_is "" ... "2.4" do
- it "raises TypeError if passed a module" do
- lambda do
- Module.new do
- refine(Enumerable) {}
+ it "accepts a module as argument" do
+ inner_self = nil
+ Module.new do
+ refine(Enumerable) do
+ def blah
end
- end.should raise_error(TypeError)
+ inner_self = self
+ end
end
+
+ inner_self.public_instance_methods.should.include?(:blah)
end
- quarantine! do # https://bugs.ruby-lang.org/issues/14070
- ruby_version_is "2.4" do
- it "accepts a module as argument" do
- inner_self = nil
- Module.new do
- refine(Enumerable) do
- def blah
- end
- inner_self = self
- end
+ it "applies refinements to the module" do
+ refinement = Module.new do
+ refine(Enumerable) do
+ def foo?
+ self.any? ? "yes" : "no"
end
+ end
+ end
- inner_self.public_instance_methods.should include(:blah)
+ foo = Class.new do
+ using refinement
+
+ def initialize(items)
+ @items = items
+ end
+
+ def result
+ @items.foo?
end
end
+
+ foo.new([]).result.should == "no"
+ foo.new([1]).result.should == "yes"
end
it "raises ArgumentError if not given a block" do
- lambda do
+ -> do
Module.new do
refine String
end
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "applies refinements to calls in the refine block" do
@@ -123,9 +134,9 @@ describe "Module#refine" do
it "doesn't apply refinements outside the refine block" do
Module.new do
refine(String) {def foo; "foo"; end}
- -> () {
+ -> {
"hello".foo
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
end
@@ -134,7 +145,7 @@ describe "Module#refine" do
refine(String) {def foo; 'foo'; end}
end
- lambda {"hello".foo}.should raise_error(NoMethodError)
+ -> {"hello".foo}.should.raise(NoMethodError)
end
# When defining multiple refinements in the same module,
@@ -191,14 +202,14 @@ describe "Module#refine" do
result = nil
- -> () {
+ -> {
Module.new do
using refinery_integer
using refinery_array
[1, 2].to_json_format
end
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
# method lookup:
@@ -210,8 +221,10 @@ describe "Module#refine" do
# * The included modules of C
describe "method lookup" do
it "looks in the object singleton class first" do
+ refined_class = ModuleSpecs.build_refined_class
+
refinement = Module.new do
- refine ModuleSpecs::ClassWithFoo do
+ refine refined_class do
def foo; "foo from refinement"; end
end
end
@@ -220,7 +233,7 @@ describe "Module#refine" do
Module.new do
using refinement
- obj = ModuleSpecs::ClassWithFoo.new
+ obj = refined_class.new
class << obj
def foo; "foo from singleton class"; end
end
@@ -230,68 +243,48 @@ describe "Module#refine" do
result.should == "foo from singleton class"
end
- it "looks in prepended modules from the refinement first" do
- refinement = Module.new do
- refine ModuleSpecs::ClassWithFoo do
- include ModuleSpecs::IncludedModule
- prepend ModuleSpecs::PrependedModule
-
- def foo; "foo from refinement"; end
+ it "looks in later included modules of the refined module first" do
+ a = Module.new do
+ def foo
+ "foo from A"
end
end
- result = nil
- Module.new do
- using refinement
- result = ModuleSpecs::ClassWithFoo.new.foo
- end
-
- result.should == "foo from prepended module"
- end
-
- it "looks in refinement then" do
- refinement = Module.new do
- refine(ModuleSpecs::ClassWithFoo) do
- include ModuleSpecs::IncludedModule
-
- def foo; "foo from refinement"; end
+ include_me_later = Module.new do
+ def foo
+ "foo from IncludeMeLater"
end
end
- result = nil
- Module.new do
- using refinement
- result = ModuleSpecs::ClassWithFoo.new.foo
+ c = Class.new do
+ include a
end
- result.should == "foo from refinement"
- end
-
- it "looks in included modules from the refinement then" do
refinement = Module.new do
- refine ModuleSpecs::ClassWithFoo do
- include ModuleSpecs::IncludedModule
- end
- end
+ refine c do; end
+ end
result = nil
Module.new do
using refinement
- result = ModuleSpecs::ClassWithFoo.new.foo
+ c.include include_me_later
+ result = c.new.foo
end
- result.should == "foo from included module"
+ result.should == "foo from IncludeMeLater"
end
it "looks in the class then" do
+ refined_class = ModuleSpecs.build_refined_class
+
refinement = Module.new do
- refine(ModuleSpecs::ClassWithFoo) { }
+ refine(refined_class) { }
end
result = nil
Module.new do
using refinement
- result = ModuleSpecs::ClassWithFoo.new.foo
+ result = refined_class.new.foo
end
result.should == "foo"
@@ -301,12 +294,14 @@ describe "Module#refine" do
# methods in a subclass have priority over refinements in a superclass
it "does not override methods in subclasses" do
- subclass = Class.new(ModuleSpecs::ClassWithFoo) do
+ refined_class = ModuleSpecs.build_refined_class
+
+ subclass = Class.new(refined_class) do
def foo; "foo from subclass"; end
end
refinement = Module.new do
- refine ModuleSpecs::ClassWithFoo do
+ refine refined_class do
def foo; "foo from refinement"; end
end
end
@@ -321,148 +316,94 @@ describe "Module#refine" do
end
context "for methods accessed indirectly" do
- ruby_version_is "" ... "2.4" do
- it "is not honored by Kernel#send" do
- refinement = Module.new do
- refine ModuleSpecs::ClassWithFoo do
- def foo; "foo from refinement"; end
- end
- end
+ it "is honored by Kernel#send" do
+ refined_class = ModuleSpecs.build_refined_class
- result = nil
- Module.new do
- using refinement
- result = ModuleSpecs::ClassWithFoo.new.send :foo
+ refinement = Module.new do
+ refine refined_class do
+ def foo; "foo from refinement"; end
end
-
- result.should == "foo"
end
- it "is not honored by BasicObject#__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.__send__ :foo
- end
-
- result.should == "foo"
+ result = nil
+ Module.new do
+ using refinement
+ result = refined_class.new.send :foo
end
- it "is not honored by Symbol#to_proc" do
- refinement = Module.new do
- refine Integer do
- def to_s
- "(#{super})"
- end
- end
- end
-
- result = nil
- Module.new do
- using refinement
- result = [1, 2, 3].map(&:to_s)
- end
-
- result.should == ["1", "2", "3"]
- end
+ result.should == "foo from refinement"
end
- ruby_version_is "2.4" do
- it "is honored by Kernel#send" do
- refinement = Module.new do
- refine ModuleSpecs::ClassWithFoo do
- def foo; "foo from refinement"; end
- end
- end
+ it "is honored by BasicObject#__send__" do
+ refined_class = ModuleSpecs.build_refined_class
- result = nil
- Module.new do
- using refinement
- result = ModuleSpecs::ClassWithFoo.new.send :foo
+ refinement = Module.new do
+ refine refined_class do
+ def foo; "foo from refinement"; end
end
-
- result.should == "foo from refinement"
end
- it "is honored by BasicObject#__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.__send__ :foo
- end
-
- result.should == "foo from refinement"
+ result = nil
+ Module.new do
+ using refinement
+ result = refined_class.new.__send__ :foo
end
- it "is honored by Symbol#to_proc" do
- refinement = Module.new do
- refine Integer do
- def to_s
- "(#{super})"
- end
- end
- end
+ result.should == "foo from refinement"
+ end
- result = nil
- Module.new do
- using refinement
- result = [1, 2, 3].map(&:to_s)
+ it "is honored by Symbol#to_proc" do
+ refinement = Module.new do
+ refine Integer do
+ def to_s
+ "(#{super})"
+ end
end
+ end
- result.should == ["(1)", "(2)", "(3)"]
+ result = nil
+ Module.new do
+ using refinement
+ result = [1, 2, 3].map(&:to_s)
end
+
+ result.should == ["(1)", "(2)", "(3)"]
end
- ruby_version_is "" ... "2.5" do
- it "is not honored by string interpolation" do
- refinement = Module.new do
- refine Integer do
- def to_s
- "foo"
- end
- end
- end
+ it "is honored by Kernel#public_send" do
+ refined_class = ModuleSpecs.build_refined_class
- result = nil
- Module.new do
- using refinement
- result = "#{1}"
+ refinement = Module.new do
+ refine refined_class do
+ def foo; "foo from refinement"; end
end
+ end
- result.should == "1"
+ result = nil
+ Module.new do
+ using refinement
+ result = refined_class.new.public_send :foo
end
+
+ result.should == "foo from refinement"
end
- ruby_version_is "2.5" do
- it "is honored by string interpolation" do
- refinement = Module.new do
- refine Integer do
- def to_s
- "foo"
- end
+ it "is honored by string interpolation" do
+ refinement = Module.new do
+ refine Integer do
+ def to_s
+ "foo"
end
end
+ end
- result = nil
- Module.new do
- using refinement
- result = "#{1}"
- end
-
- result.should == "foo"
+ result = nil
+ Module.new do
+ using refinement
+ result = "#{1}"
end
+
+ result.should == "foo"
end
it "is honored by Kernel#binding" do
@@ -490,7 +431,7 @@ describe "Module#refine" do
result.should == "hello from refinement"
end
- it "is not honored by Kernel#method" do
+ it "is honored by Kernel#method" do
klass = Class.new
refinement = Module.new do
refine klass do
@@ -498,15 +439,33 @@ describe "Module#refine" do
end
end
- -> {
- Module.new do
- using refinement
- klass.new.method(:foo)
+ result = nil
+ Module.new do
+ using refinement
+ result = klass.new.method(:foo).class
+ end
+
+ result.should == Method
+ end
+
+ it "is honored by Kernel#public_method" do
+ klass = Class.new
+ refinement = Module.new do
+ refine klass do
+ def foo; end
end
- }.should raise_error(NameError, /undefined method `foo'/)
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ result = klass.new.public_method(:foo).class
+ end
+
+ result.should == Method
end
- it "is not honored by Kernel#respond_to?" do
+ it "is honored by Kernel#instance_method" do
klass = Class.new
refinement = Module.new do
refine klass do
@@ -517,21 +476,34 @@ describe "Module#refine" do
result = nil
Module.new do
using refinement
- result = klass.new.respond_to?(:foo)
+ result = klass.instance_method(:foo).class
end
- result.should == false
+ result.should == UnboundMethod
end
- end
- context "when super is called in a refinement" do
- it "looks in the included to refinery module" do
+ it "is honored by Kernel#respond_to?" do
+ klass = Class.new
refinement = Module.new do
- refine ModuleSpecs::ClassWithFoo do
- include ModuleSpecs::IncludedModule
+ refine klass do
+ def foo; end
+ end
+ end
- def foo
- super
+ result = nil
+ Module.new do
+ using refinement
+ result = klass.new.respond_to?(:foo)
+ end
+
+ result.should == true
+ end
+
+ it "is honored by &" do
+ refinement = Module.new do
+ refine String do
+ def to_proc(*args)
+ -> * { 'foo' }
end
end
end
@@ -539,15 +511,19 @@ describe "Module#refine" do
result = nil
Module.new do
using refinement
- result = ModuleSpecs::ClassWithFoo.new.foo
+ result = ["hola"].map(&"upcase")
end
- result.should == "foo from included module"
+ result.should == ['foo']
end
+ end
+ context "when super is called in a refinement" do
it "looks in the refined class" do
+ refined_class = ModuleSpecs.build_refined_class
+
refinement = Module.new do
- refine ModuleSpecs::ClassWithFoo do
+ refine refined_class do
def foo
super
end
@@ -557,7 +533,7 @@ describe "Module#refine" do
result = nil
Module.new do
using refinement
- result = ModuleSpecs::ClassWithFoo.new.foo
+ result = refined_class.new.foo
end
result.should == "foo"
@@ -566,19 +542,21 @@ describe "Module#refine" do
# super in a method of a refinement invokes the method in the refined
# class even if there is another refinement which has been activated
# in the same context.
- it "looks in the refined class even if there is another active refinement" do
+ it "looks in the refined class first if called from refined method" do
+ refined_class = ModuleSpecs.build_refined_class(for_super: true)
+
refinement = Module.new do
- refine ModuleSpecs::ClassWithFoo do
+ refine refined_class do
def foo
- "foo from refinement"
+ [:R1]
end
end
end
refinement_with_super = Module.new do
- refine ModuleSpecs::ClassWithFoo do
+ refine refined_class do
def foo
- super
+ [:R2] + super
end
end
end
@@ -587,11 +565,75 @@ describe "Module#refine" do
Module.new do
using refinement
using refinement_with_super
- result = ModuleSpecs::ClassWithFoo.new.foo
+ result = refined_class.new.foo
end
- result.should == "foo"
+ result.should == [:R2, :C]
end
+
+ it "looks only in the refined class even if there is another active refinement" do
+ refined_class = ModuleSpecs.build_refined_class(for_super: true)
+
+ refinement = Module.new do
+ refine refined_class do
+ def bar
+ "you cannot see me from super because I belong to another active R"
+ end
+ end
+ end
+
+ refinement_with_super = Module.new do
+ refine refined_class do
+ def bar
+ super
+ end
+ end
+ end
+
+
+ Module.new do
+ using refinement
+ using refinement_with_super
+ -> {
+ refined_class.new.bar
+ }.should.raise(NoMethodError)
+ end
+ end
+ end
+
+ it 'and alias aliases a method within a refinement module, but not outside it' do
+ Module.new do
+ using Module.new {
+ refine Array do
+ alias :orig_count :count
+ end
+ }
+ [1,2].orig_count.should == 2
+ end
+ -> { [1,2].orig_count }.should.raise(NoMethodError)
+ end
+
+ it 'and alias_method aliases a method within a refinement module, but not outside it' do
+ Module.new do
+ using Module.new {
+ refine Array do
+ alias_method :orig_count, :count
+ end
+ }
+ [1,2].orig_count.should == 2
+ end
+ -> { [1,2].orig_count }.should.raise(NoMethodError)
+ end
+
+ it "and instance_methods returns a list of methods including those of the refined module" do
+ methods = Array.instance_methods
+ methods_2 = []
+ Module.new do
+ refine Array do
+ methods_2 = instance_methods
+ end
+ end
+ methods.should == methods_2
end
# Refinements are inherited by module inclusion.
@@ -654,4 +696,18 @@ describe "Module#refine" do
result.should == "hello from refinement"
end
end
+
+ it 'does not list methods defined only in refinement' do
+ refine_object = Module.new do
+ refine Object do
+ def refinement_only_method
+ end
+ end
+ end
+ klass = Class.new { instance_methods.should_not.include?(:refinement_only_method) }
+ instance = klass.new
+ instance.methods.should_not.include? :refinement_only_method
+ instance.respond_to?(:refinement_only_method).should == false
+ -> { instance.method :refinement_only_method }.should.raise(NameError)
+ end
end