diff options
Diffstat (limited to 'spec/ruby/core/refinement')
-rw-r--r-- | spec/ruby/core/refinement/append_features_spec.rb | 21 | ||||
-rw-r--r-- | spec/ruby/core/refinement/extend_object_spec.rb | 23 | ||||
-rw-r--r-- | spec/ruby/core/refinement/fixtures/classes.rb | 10 | ||||
-rw-r--r-- | spec/ruby/core/refinement/import_methods_spec.rb | 269 | ||||
-rw-r--r-- | spec/ruby/core/refinement/include_spec.rb | 27 | ||||
-rw-r--r-- | spec/ruby/core/refinement/prepend_features_spec.rb | 21 | ||||
-rw-r--r-- | spec/ruby/core/refinement/prepend_spec.rb | 27 | ||||
-rw-r--r-- | spec/ruby/core/refinement/refined_class_spec.rb | 17 |
8 files changed, 415 insertions, 0 deletions
diff --git a/spec/ruby/core/refinement/append_features_spec.rb b/spec/ruby/core/refinement/append_features_spec.rb new file mode 100644 index 0000000000..fb84f245bd --- /dev/null +++ b/spec/ruby/core/refinement/append_features_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../spec_helper' + +describe "Refinement#append_features" do + ruby_version_is "3.2" do + it "is not defined" do + Refinement.should_not have_private_instance_method(:append_features) + end + + it "is not called by Module#include" do + c = Class.new + Module.new do + refine c do + called = false + define_method(:append_features){called = true} + proc{c.include(self)}.should raise_error(TypeError) + called.should == false + end + end + end + end +end diff --git a/spec/ruby/core/refinement/extend_object_spec.rb b/spec/ruby/core/refinement/extend_object_spec.rb new file mode 100644 index 0000000000..6c2a0af4f3 --- /dev/null +++ b/spec/ruby/core/refinement/extend_object_spec.rb @@ -0,0 +1,23 @@ +require_relative '../../spec_helper' + +describe "Refinement#extend_object" do + ruby_version_is "3.2" do + it "is not defined" do + Refinement.should_not have_private_instance_method(:extend_object) + end + + it "is not called by Object#extend" do + c = Class.new + Module.new do + refine c do + called = false + define_method(:extend_object) { called = true } + -> { + c.extend(self) + }.should raise_error(TypeError) + called.should == false + end + end + end + end +end diff --git a/spec/ruby/core/refinement/fixtures/classes.rb b/spec/ruby/core/refinement/fixtures/classes.rb new file mode 100644 index 0000000000..94324db47c --- /dev/null +++ b/spec/ruby/core/refinement/fixtures/classes.rb @@ -0,0 +1,10 @@ +module RefinementSpec + + module ModuleWithAncestors + include Module.new do + def indent(level) + " " * level + self + end + end + end +end diff --git a/spec/ruby/core/refinement/import_methods_spec.rb b/spec/ruby/core/refinement/import_methods_spec.rb new file mode 100644 index 0000000000..614c54dff8 --- /dev/null +++ b/spec/ruby/core/refinement/import_methods_spec.rb @@ -0,0 +1,269 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe "Refinement#import_methods" do + ruby_version_is "3.1" do + context "when methods are defined in Ruby code" do + it "imports methods" do + str_utils = Module.new do + def indent(level) + " " * level + self + end + end + + Module.new do + refine String do + import_methods str_utils + "foo".indent(3).should == " foo" + end + end + end + + it "throws an exception when argument is not a module" do + Module.new do + refine String do + -> { + import_methods Integer + }.should raise_error(TypeError, "wrong argument type Class (expected Module)") + end + end + end + + it "imports methods from multiple modules" do + str_utils = Module.new do + def indent(level) + " " * level + self + end + end + + str_utils_fancy = Module.new do + def indent_star(level) + "*" * level + self + end + end + + Module.new do + refine String do + import_methods str_utils, str_utils_fancy + "foo".indent(3).should == " foo" + "foo".indent_star(3).should == "***foo" + end + end + end + + it "imports a method defined in the last module if method with same name is defined in multiple modules" do + str_utils = Module.new do + def indent(level) + " " * level + self + end + end + + str_utils_fancy = Module.new do + def indent(level) + "*" * level + self + end + end + + Module.new do + refine String do + import_methods str_utils, str_utils_fancy + "foo".indent(3).should == "***foo" + end + end + end + + it "still imports methods of modules listed before a module that contains method not defined in Ruby" do + str_utils = Module.new do + def indent(level) + " " * level + self + end + end + + string_refined = Module.new do + refine String do + -> { + import_methods str_utils, Kernel + }.should raise_error(ArgumentError) + end + end + + Module.new do + using string_refined + "foo".indent(3).should == " foo" + end + end + end + + it "warns if a module includes/prepends some other module" do + module1 = Module.new do + end + + module2 = Module.new do + include module1 + end + + Module.new do + refine String do + -> { + import_methods module2 + }.should complain(/warning: #<Module:\w*> has ancestors, but Refinement#import_methods doesn't import their methods/) + end + end + + Module.new do + refine String do + -> { + import_methods RefinementSpec::ModuleWithAncestors + }.should complain(/warning: RefinementSpec::ModuleWithAncestors has ancestors, but Refinement#import_methods doesn't import their methods/) + end + end + end + + it "doesn't import methods from included/prepended modules" do + Module.new do + refine String do + suppress_warning { import_methods RefinementSpec::ModuleWithAncestors } + end + + using self + -> { + "foo".indent(3) + }.should raise_error(NoMethodError, /undefined method [`']indent' for ("foo":String|an instance of String)/) + end + end + + it "doesn't import any methods if one of the arguments is not a module" do + str_utils = Module.new do + def indent(level) + " " * level + self + end + end + + string_refined = Module.new do + refine String do + -> { + import_methods str_utils, Integer + }.should raise_error(TypeError) + end + end + + Module.new do + using string_refined + -> { + "foo".indent(3) + }.should raise_error(NoMethodError) + end + end + + it "imports methods from multiple modules so that methods see other's module's methods" do + str_utils = Module.new do + def indent(level) + " " * level + self + end + end + + str_utils_normal = Module.new do + def indent_normal(level) + self.indent(level) + end + end + + Module.new do + refine String do + import_methods str_utils, str_utils_normal + end + + using self + "foo".indent_normal(3).should == " foo" + end + end + + it "imports methods from module so that methods can see each other" do + str_utils = Module.new do + def indent(level) + " " * level + self + end + + def indent_with_dot(level) + self.indent(level) + "." + end + end + + Module.new do + refine String do + import_methods str_utils + end + + using self + "foo".indent_with_dot(3).should == " foo." + end + end + + it "doesn't import module's class methods" do + str_utils = Module.new do + def self.indent(level) + " " * level + self + end + end + + Module.new do + refine String do + import_methods str_utils + end + + using self + -> { + String.indent(3) + }.should raise_error(NoMethodError, /undefined method [`']indent' for (String:Class|class String)/) + end + end + + it "imports module methods with super" do + class_to_refine = Class.new do + def foo(number) + 2 * number + end + end + + extension = Module.new do + def foo(number) + super * 2 + end + end + + refinement = Module.new do + refine class_to_refine do + import_methods extension + end + end + + Module.new do + using refinement + class_to_refine.new.foo(2).should == 8 + end + end + + context "when methods are not defined in Ruby code" do + it "raises ArgumentError" do + Module.new do + refine String do + -> { + import_methods Kernel + }.should raise_error(ArgumentError) + end + end + end + + it "raises ArgumentError when importing methods from C extension" do + require 'zlib' + Module.new do + refine String do + -> { + import_methods Zlib + }.should raise_error(ArgumentError, /Can't import method which is not defined with Ruby code: Zlib#*/) + end + end + end + end + end +end diff --git a/spec/ruby/core/refinement/include_spec.rb b/spec/ruby/core/refinement/include_spec.rb new file mode 100644 index 0000000000..25a53f0ec7 --- /dev/null +++ b/spec/ruby/core/refinement/include_spec.rb @@ -0,0 +1,27 @@ +require_relative '../../spec_helper' + +describe "Refinement#include" do + ruby_version_is "3.1"..."3.2" do + it "warns about deprecation" do + Module.new do + refine String do + -> { + include Module.new + }.should complain(/warning: Refinement#include is deprecated and will be removed in Ruby 3.2/) + end + end + end + end + + ruby_version_is "3.2" do + it "raises a TypeError" do + Module.new do + refine String do + -> { + include Module.new + }.should raise_error(TypeError, "Refinement#include has been removed") + end + end + end + end +end diff --git a/spec/ruby/core/refinement/prepend_features_spec.rb b/spec/ruby/core/refinement/prepend_features_spec.rb new file mode 100644 index 0000000000..9fdea199a2 --- /dev/null +++ b/spec/ruby/core/refinement/prepend_features_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../spec_helper' + +describe "Refinement#prepend_features" do + ruby_version_is "3.2" do + it "is not defined" do + Refinement.should_not have_private_instance_method(:prepend_features) + end + + it "is not called by Module#prepend" do + c = Class.new + Module.new do + refine c do + called = false + define_method(:prepend_features){called = true} + proc{c.prepend(self)}.should raise_error(TypeError) + called.should == false + end + end + end + end +end diff --git a/spec/ruby/core/refinement/prepend_spec.rb b/spec/ruby/core/refinement/prepend_spec.rb new file mode 100644 index 0000000000..27b70d392a --- /dev/null +++ b/spec/ruby/core/refinement/prepend_spec.rb @@ -0,0 +1,27 @@ +require_relative '../../spec_helper' + +describe "Refinement#prepend" do + ruby_version_is "3.1"..."3.2" do + it "warns about deprecation" do + Module.new do + refine String do + -> { + prepend Module.new + }.should complain(/warning: Refinement#prepend is deprecated and will be removed in Ruby 3.2/) + end + end + end + end + + ruby_version_is "3.2" do + it "raises a TypeError" do + Module.new do + refine String do + -> { + prepend Module.new + }.should raise_error(TypeError, "Refinement#prepend has been removed") + end + end + end + end +end diff --git a/spec/ruby/core/refinement/refined_class_spec.rb b/spec/ruby/core/refinement/refined_class_spec.rb new file mode 100644 index 0000000000..00b65d0895 --- /dev/null +++ b/spec/ruby/core/refinement/refined_class_spec.rb @@ -0,0 +1,17 @@ +require_relative '../../spec_helper' + +describe "Refinement#refined_class" do + ruby_version_is "3.2"..."3.3" do + it "returns the class refined by the receiver" do + refinement_int = nil + + Module.new do + refine Integer do + refinement_int = self + end + end + + refinement_int.refined_class.should == Integer + end + end +end |