diff options
Diffstat (limited to 'spec/ruby/core/refinement')
| -rw-r--r-- | spec/ruby/core/refinement/append_features_spec.rb | 19 | ||||
| -rw-r--r-- | spec/ruby/core/refinement/extend_object_spec.rb | 21 | ||||
| -rw-r--r-- | spec/ruby/core/refinement/fixtures/classes.rb | 10 | ||||
| -rw-r--r-- | spec/ruby/core/refinement/import_methods_spec.rb | 267 | ||||
| -rw-r--r-- | spec/ruby/core/refinement/include_spec.rb | 13 | ||||
| -rw-r--r-- | spec/ruby/core/refinement/prepend_features_spec.rb | 19 | ||||
| -rw-r--r-- | spec/ruby/core/refinement/prepend_spec.rb | 13 | ||||
| -rw-r--r-- | spec/ruby/core/refinement/refined_class_spec.rb | 38 | ||||
| -rw-r--r-- | spec/ruby/core/refinement/shared/target.rb | 13 | ||||
| -rw-r--r-- | spec/ruby/core/refinement/target_spec.rb | 8 |
10 files changed, 421 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..f7e5f32bc1 --- /dev/null +++ b/spec/ruby/core/refinement/append_features_spec.rb @@ -0,0 +1,19 @@ +require_relative '../../spec_helper' + +describe "Refinement#append_features" 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 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..4da8b359cc --- /dev/null +++ b/spec/ruby/core/refinement/extend_object_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../spec_helper' + +describe "Refinement#extend_object" 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 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..13c0b1004c --- /dev/null +++ b/spec/ruby/core/refinement/import_methods_spec.rb @@ -0,0 +1,267 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe "Refinement#import_methods" 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 diff --git a/spec/ruby/core/refinement/include_spec.rb b/spec/ruby/core/refinement/include_spec.rb new file mode 100644 index 0000000000..57451bd9bc --- /dev/null +++ b/spec/ruby/core/refinement/include_spec.rb @@ -0,0 +1,13 @@ +require_relative '../../spec_helper' + +describe "Refinement#include" 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 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..fbc431bbd2 --- /dev/null +++ b/spec/ruby/core/refinement/prepend_features_spec.rb @@ -0,0 +1,19 @@ +require_relative '../../spec_helper' + +describe "Refinement#prepend_features" 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 diff --git a/spec/ruby/core/refinement/prepend_spec.rb b/spec/ruby/core/refinement/prepend_spec.rb new file mode 100644 index 0000000000..64cf7cd17f --- /dev/null +++ b/spec/ruby/core/refinement/prepend_spec.rb @@ -0,0 +1,13 @@ +require_relative '../../spec_helper' + +describe "Refinement#prepend" 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 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..60a58380cc --- /dev/null +++ b/spec/ruby/core/refinement/refined_class_spec.rb @@ -0,0 +1,38 @@ +require_relative "../../spec_helper" +require_relative 'shared/target' + +describe "Refinement#refined_class" do + ruby_version_is ""..."3.3" do + it_behaves_like :refinement_target, :refined_class + end + + ruby_version_is "3.3"..."3.4" do + it "has been deprecated in favour of Refinement#target" do + refinement_int = nil + + Module.new do + refine Integer do + refinement_int = self + end + end + + -> { + refinement_int.refined_class + }.should complain(/warning: Refinement#refined_class is deprecated and will be removed in Ruby 3.4; use Refinement#target instead/) + end + end + + ruby_version_is "3.4" do + it "has been removed" do + refinement_int = nil + + Module.new do + refine Integer do + refinement_int = self + end + end + + refinement_int.should_not.respond_to?(:refined_class) + end + end +end diff --git a/spec/ruby/core/refinement/shared/target.rb b/spec/ruby/core/refinement/shared/target.rb new file mode 100644 index 0000000000..79557bea0b --- /dev/null +++ b/spec/ruby/core/refinement/shared/target.rb @@ -0,0 +1,13 @@ +describe :refinement_target, shared: true 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.send(@method).should == Integer + end +end diff --git a/spec/ruby/core/refinement/target_spec.rb b/spec/ruby/core/refinement/target_spec.rb new file mode 100644 index 0000000000..fee9588a96 --- /dev/null +++ b/spec/ruby/core/refinement/target_spec.rb @@ -0,0 +1,8 @@ +require_relative "../../spec_helper" +require_relative 'shared/target' + +describe "Refinement#target" do + ruby_version_is "3.3" do + it_behaves_like :refinement_target, :target + end +end |
