mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Move spec/rubyspec to spec/ruby for consistency
* Other ruby implementations use the spec/ruby directory. [Misc #13792] [ruby-core:82287] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59979 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
75bfc6440d
commit
1d15d5f080
4370 changed files with 0 additions and 0 deletions
150
spec/ruby/core/module/alias_method_spec.rb
Normal file
150
spec/ruby/core/module/alias_method_spec.rb
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#alias_method" do
|
||||
before :each do
|
||||
@class = Class.new(ModuleSpecs::Aliasing)
|
||||
@object = @class.new
|
||||
end
|
||||
|
||||
it "makes a copy of the method" do
|
||||
@class.make_alias :uno, :public_one
|
||||
@class.make_alias :double, :public_two
|
||||
@object.uno.should == @object.public_one
|
||||
@object.double(12).should == @object.public_two(12)
|
||||
end
|
||||
|
||||
it "creates methods that are == to eachother" do
|
||||
@class.make_alias :uno, :public_one
|
||||
@object.method(:uno).should == @object.method(:public_one)
|
||||
end
|
||||
|
||||
it "preserves the arguments information of the original methods" do
|
||||
@class.make_alias :uno, :public_one
|
||||
@class.make_alias :double, :public_two
|
||||
@class.instance_method(:uno).parameters.should == @class.instance_method(:public_one).parameters
|
||||
@class.instance_method(:double).parameters.should == @class.instance_method(:public_two).parameters
|
||||
end
|
||||
|
||||
it "retains method visibility" do
|
||||
@class.make_alias :private_ichi, :private_one
|
||||
lambda { @object.private_one }.should raise_error(NameError)
|
||||
lambda { @object.private_ichi }.should raise_error(NameError)
|
||||
@class.make_alias :public_ichi, :public_one
|
||||
@object.public_ichi.should == @object.public_one
|
||||
@class.make_alias :protected_ichi, :protected_one
|
||||
lambda { @object.protected_ichi }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "handles aliasing a stub that changes visibility" do
|
||||
@class.__send__ :public, :private_one
|
||||
@class.make_alias :was_private_one, :private_one
|
||||
@object.was_private_one.should == 1
|
||||
end
|
||||
|
||||
it "fails if origin method not found" do
|
||||
lambda { @class.make_alias :ni, :san }.should raise_error(NameError) { |e|
|
||||
# a NameError and not a NoMethodError
|
||||
e.class.should == NameError
|
||||
}
|
||||
end
|
||||
|
||||
it "raises RuntimeError if frozen" do
|
||||
@class.freeze
|
||||
lambda { @class.make_alias :uno, :public_one }.should raise_error(RuntimeError)
|
||||
end
|
||||
|
||||
it "converts the names using #to_str" do
|
||||
@class.make_alias "un", "public_one"
|
||||
@class.make_alias :deux, "public_one"
|
||||
@class.make_alias "trois", :public_one
|
||||
@class.make_alias :quatre, :public_one
|
||||
name = mock('cinq')
|
||||
name.should_receive(:to_str).any_number_of_times.and_return("cinq")
|
||||
@class.make_alias name, "public_one"
|
||||
@class.make_alias "cinq", name
|
||||
end
|
||||
|
||||
it "raises a TypeError when the given name can't be converted using to_str" do
|
||||
lambda { @class.make_alias mock('x'), :public_one }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "is a private method" do
|
||||
lambda { @class.alias_method :ichi, :public_one }.should raise_error(NoMethodError)
|
||||
end
|
||||
|
||||
it "returns self" do
|
||||
@class.send(:alias_method, :checking_return_value, :public_one).should equal(@class)
|
||||
end
|
||||
|
||||
it "works in module" do
|
||||
ModuleSpecs::Allonym.new.publish.should == :report
|
||||
end
|
||||
|
||||
it "works on private module methods in a module that has been reopened" do
|
||||
ModuleSpecs::ReopeningModule.foo.should == true
|
||||
lambda { ModuleSpecs::ReopeningModule.foo2 }.should_not raise_error(NoMethodError)
|
||||
end
|
||||
|
||||
it "accesses a method defined on Object from Kernel" do
|
||||
Kernel.should_not have_public_instance_method(:module_specs_public_method_on_object)
|
||||
|
||||
Kernel.should have_public_instance_method(:module_specs_alias_on_kernel)
|
||||
Object.should have_public_instance_method(:module_specs_alias_on_kernel)
|
||||
end
|
||||
|
||||
it "can call a method with super aliased twice" do
|
||||
ModuleSpecs::AliasingSuper::Target.new.super_call(1).should == 1
|
||||
end
|
||||
|
||||
it "preserves original super call after alias redefine" do
|
||||
ModuleSpecs::AliasingSuper::RedefineAfterAlias.new.alias_super_call(1).should == 1
|
||||
end
|
||||
|
||||
describe "aliasing special methods" do
|
||||
before :all do
|
||||
@class = ModuleSpecs::Aliasing
|
||||
@subclass = ModuleSpecs::AliasingSubclass
|
||||
end
|
||||
|
||||
it "keeps initialize private when aliasing" do
|
||||
@class.make_alias(:initialize, :public_one)
|
||||
@class.private_instance_methods.include?(:initialize).should be_true
|
||||
|
||||
@subclass.make_alias(:initialize, :public_one)
|
||||
@subclass.private_instance_methods.include?(:initialize).should be_true
|
||||
end
|
||||
|
||||
it "keeps initialize_copy private when aliasing" do
|
||||
@class.make_alias(:initialize_copy, :public_one)
|
||||
@class.private_instance_methods.include?(:initialize_copy).should be_true
|
||||
|
||||
@subclass.make_alias(:initialize_copy, :public_one)
|
||||
@subclass.private_instance_methods.include?(:initialize_copy).should be_true
|
||||
end
|
||||
|
||||
it "keeps initialize_clone private when aliasing" do
|
||||
@class.make_alias(:initialize_clone, :public_one)
|
||||
@class.private_instance_methods.include?(:initialize_clone).should be_true
|
||||
|
||||
@subclass.make_alias(:initialize_clone, :public_one)
|
||||
@subclass.private_instance_methods.include?(:initialize_clone).should be_true
|
||||
end
|
||||
|
||||
it "keeps initialize_dup private when aliasing" do
|
||||
@class.make_alias(:initialize_dup, :public_one)
|
||||
@class.private_instance_methods.include?(:initialize_dup).should be_true
|
||||
|
||||
@subclass.make_alias(:initialize_dup, :public_one)
|
||||
@subclass.private_instance_methods.include?(:initialize_dup).should be_true
|
||||
end
|
||||
|
||||
it "keeps respond_to_missing? private when aliasing" do
|
||||
@class.make_alias(:respond_to_missing?, :public_one)
|
||||
@class.private_instance_methods.include?(:respond_to_missing?).should be_true
|
||||
|
||||
@subclass.make_alias(:respond_to_missing?, :public_one)
|
||||
@subclass.private_instance_methods.include?(:respond_to_missing?).should be_true
|
||||
end
|
||||
end
|
||||
end
|
||||
14
spec/ruby/core/module/allocate_spec.rb
Normal file
14
spec/ruby/core/module/allocate_spec.rb
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
|
||||
describe "Module.allocate" do
|
||||
it "returns an instance of Module" do
|
||||
mod = Module.allocate
|
||||
mod.should be_an_instance_of(Module)
|
||||
end
|
||||
|
||||
it "returns a fully-formed instance of Module" do
|
||||
mod = Module.allocate
|
||||
mod.constants.should_not == nil
|
||||
mod.methods.should_not == nil
|
||||
end
|
||||
end
|
||||
70
spec/ruby/core/module/ancestors_spec.rb
Normal file
70
spec/ruby/core/module/ancestors_spec.rb
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#ancestors" do
|
||||
it "returns a list of modules included in self (including self)" do
|
||||
BasicObject.ancestors.should == [BasicObject]
|
||||
ModuleSpecs.ancestors.should == [ModuleSpecs]
|
||||
ModuleSpecs::Basic.ancestors.should == [ModuleSpecs::Basic]
|
||||
ModuleSpecs::Super.ancestors.should == [ModuleSpecs::Super, ModuleSpecs::Basic]
|
||||
ModuleSpecs.without_test_modules(ModuleSpecs::Parent.ancestors).should ==
|
||||
[ModuleSpecs::Parent, Object, Kernel, BasicObject]
|
||||
ModuleSpecs.without_test_modules(ModuleSpecs::Child.ancestors).should ==
|
||||
[ModuleSpecs::Child, ModuleSpecs::Super, ModuleSpecs::Basic, ModuleSpecs::Parent, Object, Kernel, BasicObject]
|
||||
end
|
||||
|
||||
it "returns only modules and classes" do
|
||||
class << ModuleSpecs::Child; self; end.ancestors.should include(ModuleSpecs::Internal, Class, Module, Object, Kernel)
|
||||
end
|
||||
|
||||
it "has 1 entry per module or class" do
|
||||
ModuleSpecs::Parent.ancestors.should == ModuleSpecs::Parent.ancestors.uniq
|
||||
end
|
||||
|
||||
describe "when called on a singleton class" do
|
||||
it "includes the singleton classes of ancestors" do
|
||||
parent = Class.new
|
||||
child = Class.new(parent)
|
||||
schild = child.singleton_class
|
||||
|
||||
schild.ancestors.should include(schild,
|
||||
parent.singleton_class,
|
||||
Object.singleton_class,
|
||||
BasicObject.singleton_class,
|
||||
Class,
|
||||
Module,
|
||||
Object,
|
||||
Kernel,
|
||||
BasicObject)
|
||||
|
||||
end
|
||||
|
||||
describe 'for a standalone module' do
|
||||
it 'does not include Class' do
|
||||
s_mod = ModuleSpecs.singleton_class
|
||||
s_mod.ancestors.should_not include(Class)
|
||||
end
|
||||
|
||||
it 'does not include other singleton classes' do
|
||||
s_standalone_mod = ModuleSpecs.singleton_class
|
||||
s_module = Module.singleton_class
|
||||
s_object = Object.singleton_class
|
||||
s_basic_object = BasicObject.singleton_class
|
||||
|
||||
s_standalone_mod.ancestors.should_not include(s_module, s_object, s_basic_object)
|
||||
end
|
||||
|
||||
it 'includes its own singleton class' do
|
||||
s_mod = ModuleSpecs.singleton_class
|
||||
|
||||
s_mod.ancestors.should include(s_mod)
|
||||
end
|
||||
|
||||
it 'includes standard chain' do
|
||||
s_mod = ModuleSpecs.singleton_class
|
||||
|
||||
s_mod.ancestors.should include(Module, Object, Kernel, BasicObject)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
73
spec/ruby/core/module/append_features_spec.rb
Normal file
73
spec/ruby/core/module/append_features_spec.rb
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#append_features" do
|
||||
it "is a private method" do
|
||||
Module.should have_private_instance_method(:append_features)
|
||||
end
|
||||
|
||||
describe "on Class" do
|
||||
it "is undefined" do
|
||||
Class.should_not have_private_instance_method(:append_features, true)
|
||||
end
|
||||
|
||||
it "raises a TypeError if calling after rebinded to Class" do
|
||||
lambda {
|
||||
Module.instance_method(:append_features).bind(Class.new).call Module.new
|
||||
}.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
|
||||
it "gets called when self is included in another module/class" do
|
||||
begin
|
||||
m = Module.new do
|
||||
def self.append_features(mod)
|
||||
$appended_to = mod
|
||||
end
|
||||
end
|
||||
|
||||
c = Class.new do
|
||||
include m
|
||||
end
|
||||
|
||||
$appended_to.should == c
|
||||
ensure
|
||||
$appended_to = nil
|
||||
end
|
||||
end
|
||||
|
||||
it "raises an ArgumentError on a cyclic include" do
|
||||
lambda {
|
||||
ModuleSpecs::CyclicAppendA.send(:append_features, ModuleSpecs::CyclicAppendA)
|
||||
}.should raise_error(ArgumentError)
|
||||
|
||||
lambda {
|
||||
ModuleSpecs::CyclicAppendB.send(:append_features, ModuleSpecs::CyclicAppendA)
|
||||
}.should raise_error(ArgumentError)
|
||||
|
||||
end
|
||||
|
||||
it "copies own tainted status to the given module" do
|
||||
other = Module.new
|
||||
Module.new.taint.send :append_features, other
|
||||
other.tainted?.should be_true
|
||||
end
|
||||
|
||||
it "copies own untrusted status to the given module" do
|
||||
other = Module.new
|
||||
Module.new.untrust.send :append_features, other
|
||||
other.untrusted?.should be_true
|
||||
end
|
||||
|
||||
describe "when other is frozen" do
|
||||
before :each do
|
||||
@receiver = Module.new
|
||||
@other = Module.new.freeze
|
||||
end
|
||||
|
||||
it "raises a RuntimeError before appending self" do
|
||||
lambda { @receiver.send(:append_features, @other) }.should raise_error(RuntimeError)
|
||||
@other.ancestors.should_not include(@receiver)
|
||||
end
|
||||
end
|
||||
end
|
||||
90
spec/ruby/core/module/attr_accessor_spec.rb
Normal file
90
spec/ruby/core/module/attr_accessor_spec.rb
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#attr_accessor" do
|
||||
it "creates a getter and setter for each given attribute name" do
|
||||
c = Class.new do
|
||||
attr_accessor :a, "b"
|
||||
end
|
||||
|
||||
o = c.new
|
||||
|
||||
['a','b'].each do |x|
|
||||
o.respond_to?(x).should == true
|
||||
o.respond_to?("#{x}=").should == true
|
||||
end
|
||||
|
||||
o.a = "a"
|
||||
o.a.should == "a"
|
||||
|
||||
o.b = "b"
|
||||
o.b.should == "b"
|
||||
o.a = o.b = nil
|
||||
|
||||
o.send(:a=,"a")
|
||||
o.send(:a).should == "a"
|
||||
|
||||
o.send(:b=, "b")
|
||||
o.send(:b).should == "b"
|
||||
end
|
||||
|
||||
it "not allows creating an attr_accessor on an immediate class" do
|
||||
class TrueClass
|
||||
attr_accessor :spec_attr_accessor
|
||||
end
|
||||
|
||||
lambda { true.spec_attr_accessor = "a" }.should raise_error(RuntimeError)
|
||||
end
|
||||
|
||||
it "converts non string/symbol/fixnum names to strings using to_str" do
|
||||
(o = mock('test')).should_receive(:to_str).any_number_of_times.and_return("test")
|
||||
c = Class.new do
|
||||
attr_accessor o
|
||||
end
|
||||
|
||||
c.new.respond_to?("test").should == true
|
||||
c.new.respond_to?("test=").should == true
|
||||
end
|
||||
|
||||
it "raises a TypeError when the given names can't be converted to strings using to_str" do
|
||||
o = mock('o')
|
||||
lambda { Class.new { attr_accessor o } }.should raise_error(TypeError)
|
||||
(o = mock('123')).should_receive(:to_str).and_return(123)
|
||||
lambda { Class.new { attr_accessor o } }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "applies current visibility to methods created" do
|
||||
c = Class.new do
|
||||
protected
|
||||
attr_accessor :foo
|
||||
end
|
||||
|
||||
lambda { c.new.foo }.should raise_error(NoMethodError)
|
||||
lambda { c.new.foo=1 }.should raise_error(NoMethodError)
|
||||
end
|
||||
|
||||
it "is a private method" do
|
||||
lambda { Class.new.attr_accessor(:foo) }.should raise_error(NoMethodError)
|
||||
end
|
||||
|
||||
describe "on immediates" do
|
||||
before :each do
|
||||
class Fixnum
|
||||
attr_accessor :foobar
|
||||
end
|
||||
end
|
||||
|
||||
after :each do
|
||||
if Fixnum.method_defined?(:foobar)
|
||||
Fixnum.send(:remove_method, :foobar)
|
||||
end
|
||||
if Fixnum.method_defined?(:foobar=)
|
||||
Fixnum.send(:remove_method, :foobar=)
|
||||
end
|
||||
end
|
||||
|
||||
it "can read through the accessor" do
|
||||
1.foobar.should be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
64
spec/ruby/core/module/attr_reader_spec.rb
Normal file
64
spec/ruby/core/module/attr_reader_spec.rb
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#attr_reader" do
|
||||
it "creates a getter for each given attribute name" do
|
||||
c = Class.new do
|
||||
attr_reader :a, "b"
|
||||
|
||||
def initialize
|
||||
@a = "test"
|
||||
@b = "test2"
|
||||
end
|
||||
end
|
||||
|
||||
o = c.new
|
||||
%w{a b}.each do |x|
|
||||
o.respond_to?(x).should == true
|
||||
o.respond_to?("#{x}=").should == false
|
||||
end
|
||||
|
||||
o.a.should == "test"
|
||||
o.b.should == "test2"
|
||||
o.send(:a).should == "test"
|
||||
o.send(:b).should == "test2"
|
||||
end
|
||||
|
||||
it "not allows for adding an attr_reader to an immediate" do
|
||||
class TrueClass
|
||||
attr_reader :spec_attr_reader
|
||||
end
|
||||
|
||||
lambda { true.instance_variable_set("@spec_attr_reader", "a") }.should raise_error(RuntimeError)
|
||||
end
|
||||
|
||||
it "converts non string/symbol/fixnum names to strings using to_str" do
|
||||
(o = mock('test')).should_receive(:to_str).any_number_of_times.and_return("test")
|
||||
c = Class.new do
|
||||
attr_reader o
|
||||
end
|
||||
|
||||
c.new.respond_to?("test").should == true
|
||||
c.new.respond_to?("test=").should == false
|
||||
end
|
||||
|
||||
it "raises a TypeError when the given names can't be converted to strings using to_str" do
|
||||
o = mock('o')
|
||||
lambda { Class.new { attr_reader o } }.should raise_error(TypeError)
|
||||
(o = mock('123')).should_receive(:to_str).and_return(123)
|
||||
lambda { Class.new { attr_reader o } }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "applies current visibility to methods created" do
|
||||
c = Class.new do
|
||||
protected
|
||||
attr_reader :foo
|
||||
end
|
||||
|
||||
lambda { c.new.foo }.should raise_error(NoMethodError)
|
||||
end
|
||||
|
||||
it "is a private method" do
|
||||
lambda { Class.new.attr_reader(:foo) }.should raise_error(NoMethodError)
|
||||
end
|
||||
end
|
||||
149
spec/ruby/core/module/attr_spec.rb
Normal file
149
spec/ruby/core/module/attr_spec.rb
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#attr" do
|
||||
before :each do
|
||||
$VERBOSE, @verbose = false, $VERBOSE
|
||||
end
|
||||
|
||||
after :each do
|
||||
$VERBOSE = @verbose
|
||||
end
|
||||
|
||||
it "creates a getter for the given attribute name" do
|
||||
c = Class.new do
|
||||
attr :attr
|
||||
attr "attr3"
|
||||
|
||||
def initialize
|
||||
@attr, @attr2, @attr3 = "test", "test2", "test3"
|
||||
end
|
||||
end
|
||||
|
||||
o = c.new
|
||||
|
||||
%w{attr attr3}.each do |a|
|
||||
o.respond_to?(a).should == true
|
||||
o.respond_to?("#{a}=").should == false
|
||||
end
|
||||
|
||||
o.attr.should == "test"
|
||||
o.attr3.should == "test3"
|
||||
o.send(:attr).should == "test"
|
||||
o.send(:attr3).should == "test3"
|
||||
end
|
||||
|
||||
it "creates a setter for the given attribute name if writable is true" do
|
||||
c = Class.new do
|
||||
attr :attr, true
|
||||
attr "attr3", true
|
||||
|
||||
def initialize
|
||||
@attr, @attr2, @attr3 = "test", "test2", "test3"
|
||||
end
|
||||
end
|
||||
|
||||
o = c.new
|
||||
|
||||
%w{attr attr3}.each do |a|
|
||||
o.respond_to?(a).should == true
|
||||
o.respond_to?("#{a}=").should == true
|
||||
end
|
||||
|
||||
o.attr = "test updated"
|
||||
o.attr3 = "test3 updated"
|
||||
end
|
||||
|
||||
it "creates a getter and setter for the given attribute name if called with and without writeable is true" do
|
||||
c = Class.new do
|
||||
attr :attr, true
|
||||
attr :attr
|
||||
|
||||
attr "attr3", true
|
||||
attr "attr3"
|
||||
|
||||
def initialize
|
||||
@attr, @attr2, @attr3 = "test", "test2", "test3"
|
||||
end
|
||||
end
|
||||
|
||||
o = c.new
|
||||
|
||||
%w{attr attr3}.each do |a|
|
||||
o.respond_to?(a).should == true
|
||||
o.respond_to?("#{a}=").should == true
|
||||
end
|
||||
|
||||
o.attr.should == "test"
|
||||
o.attr = "test updated"
|
||||
o.attr.should == "test updated"
|
||||
|
||||
o.attr3.should == "test3"
|
||||
o.attr3 = "test3 updated"
|
||||
o.attr3.should == "test3 updated"
|
||||
end
|
||||
|
||||
it "applies current visibility to methods created" do
|
||||
c = Class.new do
|
||||
protected
|
||||
attr :foo, true
|
||||
end
|
||||
|
||||
lambda { c.new.foo }.should raise_error(NoMethodError)
|
||||
lambda { c.new.foo=1 }.should raise_error(NoMethodError)
|
||||
end
|
||||
|
||||
it "creates a getter but no setter for all given attribute names" do
|
||||
c = Class.new do
|
||||
attr :attr, "attr2", "attr3"
|
||||
|
||||
def initialize
|
||||
@attr, @attr2, @attr3 = "test", "test2", "test3"
|
||||
end
|
||||
end
|
||||
|
||||
o = c.new
|
||||
|
||||
%w{attr attr2 attr3}.each do |a|
|
||||
o.respond_to?(a).should == true
|
||||
o.respond_to?("#{a}=").should == false
|
||||
end
|
||||
|
||||
o.attr.should == "test"
|
||||
o.attr2.should == "test2"
|
||||
o.attr3.should == "test3"
|
||||
end
|
||||
|
||||
it "applies current visibility to methods created" do
|
||||
c = Class.new do
|
||||
protected
|
||||
attr :foo, :bar
|
||||
end
|
||||
|
||||
lambda { c.new.foo }.should raise_error(NoMethodError)
|
||||
lambda { c.new.bar }.should raise_error(NoMethodError)
|
||||
end
|
||||
|
||||
it "converts non string/symbol/fixnum names to strings using to_str" do
|
||||
(o = mock('test')).should_receive(:to_str).any_number_of_times.and_return("test")
|
||||
Class.new { attr o }.new.respond_to?("test").should == true
|
||||
end
|
||||
|
||||
it "raises a TypeError when the given names can't be converted to strings using to_str" do
|
||||
o = mock('o')
|
||||
lambda { Class.new { attr o } }.should raise_error(TypeError)
|
||||
(o = mock('123')).should_receive(:to_str).and_return(123)
|
||||
lambda { Class.new { attr o } }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "with a boolean argument emits a warning when $VERBOSE is true" do
|
||||
lambda {
|
||||
$VERBOSE = true
|
||||
Class.new { attr :foo, true }
|
||||
}.should complain(/boolean argument is obsoleted/)
|
||||
end
|
||||
|
||||
it "is a private method" do
|
||||
lambda { Class.new.attr(:foo) }.should raise_error(NoMethodError)
|
||||
end
|
||||
end
|
||||
64
spec/ruby/core/module/attr_writer_spec.rb
Normal file
64
spec/ruby/core/module/attr_writer_spec.rb
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#attr_writer" do
|
||||
it "creates a setter for each given attribute name" do
|
||||
c = Class.new do
|
||||
attr_writer :test1, "test2"
|
||||
end
|
||||
o = c.new
|
||||
|
||||
o.respond_to?("test1").should == false
|
||||
o.respond_to?("test2").should == false
|
||||
|
||||
o.respond_to?("test1=").should == true
|
||||
o.test1 = "test_1"
|
||||
o.instance_variable_get(:@test1).should == "test_1"
|
||||
|
||||
o.respond_to?("test2=").should == true
|
||||
o.test2 = "test_2"
|
||||
o.instance_variable_get(:@test2).should == "test_2"
|
||||
o.send(:test1=,"test_1 updated")
|
||||
o.instance_variable_get(:@test1).should == "test_1 updated"
|
||||
o.send(:test2=,"test_2 updated")
|
||||
o.instance_variable_get(:@test2).should == "test_2 updated"
|
||||
end
|
||||
|
||||
it "not allows for adding an attr_writer to an immediate" do
|
||||
class TrueClass
|
||||
attr_writer :spec_attr_writer
|
||||
end
|
||||
|
||||
lambda { true.spec_attr_writer = "a" }.should raise_error(RuntimeError)
|
||||
end
|
||||
|
||||
it "converts non string/symbol/fixnum names to strings using to_str" do
|
||||
(o = mock('test')).should_receive(:to_str).any_number_of_times.and_return("test")
|
||||
c = Class.new do
|
||||
attr_writer o
|
||||
end
|
||||
|
||||
c.new.respond_to?("test").should == false
|
||||
c.new.respond_to?("test=").should == true
|
||||
end
|
||||
|
||||
it "raises a TypeError when the given names can't be converted to strings using to_str" do
|
||||
o = mock('test1')
|
||||
lambda { Class.new { attr_writer o } }.should raise_error(TypeError)
|
||||
(o = mock('123')).should_receive(:to_str).and_return(123)
|
||||
lambda { Class.new { attr_writer o } }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "applies current visibility to methods created" do
|
||||
c = Class.new do
|
||||
protected
|
||||
attr_writer :foo
|
||||
end
|
||||
|
||||
lambda { c.new.foo=1 }.should raise_error(NoMethodError)
|
||||
end
|
||||
|
||||
it "is a private method" do
|
||||
lambda { Class.new.attr_writer(:foo) }.should raise_error(NoMethodError)
|
||||
end
|
||||
end
|
||||
462
spec/ruby/core/module/autoload_spec.rb
Normal file
462
spec/ruby/core/module/autoload_spec.rb
Normal file
|
|
@ -0,0 +1,462 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
require 'thread'
|
||||
|
||||
describe "Module#autoload?" do
|
||||
it "returns the name of the file that will be autoloaded" do
|
||||
ModuleSpecs::Autoload.autoload :Autoload, "autoload.rb"
|
||||
ModuleSpecs::Autoload.autoload?(:Autoload).should == "autoload.rb"
|
||||
end
|
||||
|
||||
it "returns nil if no file has been registered for a constant" do
|
||||
ModuleSpecs::Autoload.autoload?(:Manualload).should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "Module#autoload" do
|
||||
before :all do
|
||||
@non_existent = fixture __FILE__, "no_autoload.rb"
|
||||
end
|
||||
|
||||
before :each do
|
||||
@loaded_features = $".dup
|
||||
@frozen_module = Module.new.freeze
|
||||
|
||||
ScratchPad.clear
|
||||
end
|
||||
|
||||
after :each do
|
||||
$".replace @loaded_features
|
||||
end
|
||||
|
||||
it "registers a file to load the first time the named constant is accessed" do
|
||||
ModuleSpecs::Autoload.autoload :A, @non_existent
|
||||
ModuleSpecs::Autoload.autoload?(:A).should == @non_existent
|
||||
end
|
||||
|
||||
it "sets the autoload constant in the constants table" do
|
||||
ModuleSpecs::Autoload.autoload :B, @non_existent
|
||||
ModuleSpecs::Autoload.should have_constant(:B)
|
||||
end
|
||||
|
||||
it "loads the registered constant when it is accessed" do
|
||||
ModuleSpecs::Autoload.should_not have_constant(:X)
|
||||
ModuleSpecs::Autoload.autoload :X, fixture(__FILE__, "autoload_x.rb")
|
||||
ModuleSpecs::Autoload::X.should == :x
|
||||
ModuleSpecs::Autoload.send(:remove_const, :X)
|
||||
end
|
||||
|
||||
it "loads the registered constant into a dynamically created class" do
|
||||
cls = Class.new { autoload :C, fixture(__FILE__, "autoload_c.rb") }
|
||||
ModuleSpecs::Autoload::DynClass = cls
|
||||
|
||||
ScratchPad.recorded.should be_nil
|
||||
ModuleSpecs::Autoload::DynClass::C.new.loaded.should == :dynclass_c
|
||||
ScratchPad.recorded.should == :loaded
|
||||
end
|
||||
|
||||
it "loads the registered constant into a dynamically created module" do
|
||||
mod = Module.new { autoload :D, fixture(__FILE__, "autoload_d.rb") }
|
||||
ModuleSpecs::Autoload::DynModule = mod
|
||||
|
||||
ScratchPad.recorded.should be_nil
|
||||
ModuleSpecs::Autoload::DynModule::D.new.loaded.should == :dynmodule_d
|
||||
ScratchPad.recorded.should == :loaded
|
||||
end
|
||||
|
||||
it "loads the registered constant when it is opened as a class" do
|
||||
ModuleSpecs::Autoload.autoload :E, fixture(__FILE__, "autoload_e.rb")
|
||||
class ModuleSpecs::Autoload::E
|
||||
end
|
||||
ModuleSpecs::Autoload::E.new.loaded.should == :autoload_e
|
||||
end
|
||||
|
||||
it "loads the registered constant when it is opened as a module" do
|
||||
ModuleSpecs::Autoload.autoload :F, fixture(__FILE__, "autoload_f.rb")
|
||||
module ModuleSpecs::Autoload::F
|
||||
end
|
||||
ModuleSpecs::Autoload::F.loaded.should == :autoload_f
|
||||
end
|
||||
|
||||
it "loads the registered constant when it is inherited from" do
|
||||
ModuleSpecs::Autoload.autoload :G, fixture(__FILE__, "autoload_g.rb")
|
||||
class ModuleSpecs::Autoload::Gsub < ModuleSpecs::Autoload::G
|
||||
end
|
||||
ModuleSpecs::Autoload::Gsub.new.loaded.should == :autoload_g
|
||||
end
|
||||
|
||||
it "loads the registered constant when it is included" do
|
||||
ModuleSpecs::Autoload.autoload :H, fixture(__FILE__, "autoload_h.rb")
|
||||
class ModuleSpecs::Autoload::HClass
|
||||
include ModuleSpecs::Autoload::H
|
||||
end
|
||||
ModuleSpecs::Autoload::HClass.new.loaded.should == :autoload_h
|
||||
end
|
||||
|
||||
it "does not load the file when the constant is already set" do
|
||||
ModuleSpecs::Autoload.autoload :I, fixture(__FILE__, "autoload_i.rb")
|
||||
ModuleSpecs::Autoload.const_set :I, 3
|
||||
ModuleSpecs::Autoload::I.should == 3
|
||||
ScratchPad.recorded.should be_nil
|
||||
end
|
||||
|
||||
it "loads a file with .rb extension when passed the name without the extension" do
|
||||
ModuleSpecs::Autoload.autoload :J, fixture(__FILE__, "autoload_j")
|
||||
ModuleSpecs::Autoload::J.should == :autoload_j
|
||||
end
|
||||
|
||||
it "does not load the file if the file is manually required" do
|
||||
filename = fixture(__FILE__, "autoload_k.rb")
|
||||
ModuleSpecs::Autoload.autoload :KHash, filename
|
||||
|
||||
require filename
|
||||
ScratchPad.recorded.should == :loaded
|
||||
ScratchPad.clear
|
||||
|
||||
ModuleSpecs::Autoload::KHash.should be_kind_of(Class)
|
||||
ModuleSpecs::Autoload::KHash::K.should == :autoload_k
|
||||
ScratchPad.recorded.should be_nil
|
||||
end
|
||||
|
||||
it "ignores the autoload request if the file is already loaded" do
|
||||
filename = fixture(__FILE__, "autoload_s.rb")
|
||||
|
||||
require filename
|
||||
|
||||
ScratchPad.recorded.should == :loaded
|
||||
ScratchPad.clear
|
||||
|
||||
ModuleSpecs::Autoload.autoload :S, filename
|
||||
ModuleSpecs::Autoload.autoload?(:S).should be_nil
|
||||
ModuleSpecs::Autoload.send(:remove_const, :S)
|
||||
end
|
||||
|
||||
it "retains the autoload even if the request to require fails" do
|
||||
filename = fixture(__FILE__, "a_path_that_should_not_exist.rb")
|
||||
|
||||
ModuleSpecs::Autoload.autoload :NotThere, filename
|
||||
ModuleSpecs::Autoload.autoload?(:NotThere).should == filename
|
||||
|
||||
lambda {
|
||||
require filename
|
||||
}.should raise_error(LoadError)
|
||||
|
||||
ModuleSpecs::Autoload.autoload?(:NotThere).should == filename
|
||||
end
|
||||
|
||||
it "allows multiple autoload constants for a single file" do
|
||||
filename = fixture(__FILE__, "autoload_lm.rb")
|
||||
ModuleSpecs::Autoload.autoload :L, filename
|
||||
ModuleSpecs::Autoload.autoload :M, filename
|
||||
ModuleSpecs::Autoload::L.should == :autoload_l
|
||||
ModuleSpecs::Autoload::M.should == :autoload_m
|
||||
end
|
||||
|
||||
it "runs for an exception condition class and doesn't trample the exception" do
|
||||
filename = fixture(__FILE__, "autoload_ex1.rb")
|
||||
ModuleSpecs::Autoload.autoload :EX1, filename
|
||||
ModuleSpecs::Autoload.use_ex1.should == :good
|
||||
end
|
||||
|
||||
it "does not load the file when referring to the constant in defined?" do
|
||||
module ModuleSpecs::Autoload::Q
|
||||
autoload :R, fixture(__FILE__, "autoload.rb")
|
||||
defined?(R).should == "constant"
|
||||
end
|
||||
ModuleSpecs::Autoload::Q.should have_constant(:R)
|
||||
end
|
||||
|
||||
it "does not remove the constant from the constant table if load fails" do
|
||||
ModuleSpecs::Autoload.autoload :Fail, @non_existent
|
||||
ModuleSpecs::Autoload.should have_constant(:Fail)
|
||||
|
||||
lambda { ModuleSpecs::Autoload::Fail }.should raise_error(LoadError)
|
||||
ModuleSpecs::Autoload.should have_constant(:Fail)
|
||||
end
|
||||
|
||||
it "does not remove the constant from the constant table if the loaded files does not define it" do
|
||||
ModuleSpecs::Autoload.autoload :O, fixture(__FILE__, "autoload_o.rb")
|
||||
ModuleSpecs::Autoload.should have_constant(:O)
|
||||
|
||||
lambda { ModuleSpecs::Autoload::O }.should raise_error(NameError)
|
||||
ModuleSpecs::Autoload.should have_constant(:O)
|
||||
end
|
||||
|
||||
it "returns 'constant' on referring the constant with defined?()" do
|
||||
module ModuleSpecs::Autoload::Q
|
||||
autoload :R, fixture(__FILE__, "autoload.rb")
|
||||
defined?(R).should == 'constant'
|
||||
end
|
||||
ModuleSpecs::Autoload::Q.should have_constant(:R)
|
||||
end
|
||||
|
||||
it "does not load the file when removing an autoload constant" do
|
||||
module ModuleSpecs::Autoload::Q
|
||||
autoload :R, fixture(__FILE__, "autoload.rb")
|
||||
remove_const :R
|
||||
end
|
||||
ModuleSpecs::Autoload::Q.should_not have_constant(:R)
|
||||
end
|
||||
|
||||
it "does not load the file when accessing the constants table of the module" do
|
||||
ModuleSpecs::Autoload.autoload :P, @non_existent
|
||||
ModuleSpecs::Autoload.const_defined?(:P).should be_true
|
||||
end
|
||||
|
||||
it "loads the file when opening a module that is the autoloaded constant" do
|
||||
module ModuleSpecs::Autoload::U
|
||||
autoload :V, fixture(__FILE__, "autoload_v.rb")
|
||||
|
||||
class V
|
||||
X = get_value
|
||||
end
|
||||
end
|
||||
|
||||
ModuleSpecs::Autoload::U::V::X.should == :autoload_uvx
|
||||
end
|
||||
|
||||
it "loads the file that defines subclass XX::YY < YY and YY is a top level constant" do
|
||||
|
||||
module ModuleSpecs::Autoload::XX
|
||||
autoload :YY, fixture(__FILE__, "autoload_subclass.rb")
|
||||
end
|
||||
|
||||
ModuleSpecs::Autoload::XX::YY.superclass.should == YY
|
||||
end
|
||||
|
||||
|
||||
it "looks up the constant in the scope where it is referred" do
|
||||
module ModuleSpecs
|
||||
module Autoload
|
||||
autoload :QQ, fixture(__FILE__, "autoload_scope.rb")
|
||||
class PP
|
||||
QQ.new.should be_kind_of(ModuleSpecs::Autoload::PP::QQ)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "looks up the constant when in a meta class scope" do
|
||||
module ModuleSpecs
|
||||
module Autoload
|
||||
autoload :R, fixture(__FILE__, "autoload_r.rb")
|
||||
class << self
|
||||
def r
|
||||
R.new
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
ModuleSpecs::Autoload.r.should be_kind_of(ModuleSpecs::Autoload::R)
|
||||
end
|
||||
|
||||
# [ruby-core:19127] [ruby-core:29941]
|
||||
it "does NOT raise a NameError when the autoload file did not define the constant and a module is opened with the same name" do
|
||||
module ModuleSpecs::Autoload
|
||||
class W
|
||||
autoload :Y, fixture(__FILE__, "autoload_w.rb")
|
||||
|
||||
class Y
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ModuleSpecs::Autoload::W::Y.should be_kind_of(Class)
|
||||
ScratchPad.recorded.should == :loaded
|
||||
ModuleSpecs::Autoload::W.send(:remove_const, :Y)
|
||||
end
|
||||
|
||||
it "calls #to_path on non-string filenames" do
|
||||
p = mock('path')
|
||||
p.should_receive(:to_path).and_return @non_existent
|
||||
ModuleSpecs.autoload :A, p
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when an empty filename is given" do
|
||||
lambda { ModuleSpecs.autoload :A, "" }.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "raises a NameError when the constant name starts with a lower case letter" do
|
||||
lambda { ModuleSpecs.autoload "a", @non_existent }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a NameError when the constant name starts with a number" do
|
||||
lambda { ModuleSpecs.autoload "1two", @non_existent }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a NameError when the constant name has a space in it" do
|
||||
lambda { ModuleSpecs.autoload "a name", @non_existent }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "shares the autoload request across dup'ed copies of modules" do
|
||||
require fixture(__FILE__, "autoload_s.rb")
|
||||
filename = fixture(__FILE__, "autoload_t.rb")
|
||||
mod1 = Module.new { autoload :T, filename }
|
||||
lambda {
|
||||
ModuleSpecs::Autoload::S = mod1
|
||||
}.should complain(/already initialized constant/)
|
||||
mod2 = mod1.dup
|
||||
|
||||
mod1.autoload?(:T).should == filename
|
||||
mod2.autoload?(:T).should == filename
|
||||
|
||||
mod1::T.should == :autoload_t
|
||||
lambda { mod2::T }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a TypeError if opening a class with a different superclass than the class defined in the autoload file" do
|
||||
ModuleSpecs::Autoload.autoload :Z, fixture(__FILE__, "autoload_z.rb")
|
||||
class ModuleSpecs::Autoload::ZZ
|
||||
end
|
||||
|
||||
lambda do
|
||||
class ModuleSpecs::Autoload::Z < ModuleSpecs::Autoload::ZZ
|
||||
end
|
||||
end.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "raises a TypeError if not passed a String or object respodning to #to_path for the filename" do
|
||||
name = mock("autoload_name.rb")
|
||||
|
||||
lambda { ModuleSpecs::Autoload.autoload :Str, name }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "calls #to_path on non-String filename arguments" do
|
||||
name = mock("autoload_name.rb")
|
||||
name.should_receive(:to_path).and_return("autoload_name.rb")
|
||||
|
||||
lambda { ModuleSpecs::Autoload.autoload :Str, name }.should_not raise_error
|
||||
end
|
||||
|
||||
describe "on a frozen module" do
|
||||
it "raises a RuntimeError before setting the name" do
|
||||
lambda { @frozen_module.autoload :Foo, @non_existent }.should raise_error(RuntimeError)
|
||||
@frozen_module.should_not have_constant(:Foo)
|
||||
end
|
||||
end
|
||||
|
||||
describe "(concurrently)" do
|
||||
it "blocks a second thread while a first is doing the autoload" do
|
||||
ModuleSpecs::Autoload.autoload :Concur, fixture(__FILE__, "autoload_concur.rb")
|
||||
|
||||
start = false
|
||||
|
||||
ScratchPad.record []
|
||||
|
||||
t1_val = nil
|
||||
t2_val = nil
|
||||
|
||||
fin = false
|
||||
|
||||
t1 = Thread.new do
|
||||
Thread.pass until start
|
||||
t1_val = ModuleSpecs::Autoload::Concur
|
||||
ScratchPad.recorded << :t1_post
|
||||
fin = true
|
||||
end
|
||||
|
||||
t2_exc = nil
|
||||
|
||||
t2 = Thread.new do
|
||||
Thread.pass until t1 and t1[:in_autoload_rb]
|
||||
begin
|
||||
t2_val = ModuleSpecs::Autoload::Concur
|
||||
rescue Exception => e
|
||||
t2_exc = e
|
||||
else
|
||||
Thread.pass until fin
|
||||
ScratchPad.recorded << :t2_post
|
||||
end
|
||||
end
|
||||
|
||||
start = true
|
||||
|
||||
t1.join
|
||||
t2.join
|
||||
|
||||
ScratchPad.recorded.should == [:con_pre, :con_post, :t1_post, :t2_post]
|
||||
|
||||
t1_val.should == 1
|
||||
t2_val.should == t1_val
|
||||
|
||||
t2_exc.should be_nil
|
||||
|
||||
ModuleSpecs::Autoload.send(:remove_const, :Concur)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when changing $LOAD_PATH" do
|
||||
|
||||
before do
|
||||
$LOAD_PATH.unshift(File.expand_path('../fixtures/path1', __FILE__))
|
||||
end
|
||||
|
||||
after do
|
||||
$LOAD_PATH.shift
|
||||
$LOAD_PATH.shift
|
||||
end
|
||||
|
||||
it "does not reload a file due to a different load path" do
|
||||
ModuleSpecs::Autoload.autoload :LoadPath, "load_path"
|
||||
ModuleSpecs::Autoload::LoadPath.loaded.should == :autoload_load_path
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "(concurrently)" do
|
||||
ruby_bug "#10892", ""..."2.3" do
|
||||
it "blocks others threads while doing an autoload" do
|
||||
file_path = fixture(__FILE__, "repeated_concurrent_autoload.rb")
|
||||
autoload_path = file_path.sub(/\.rb\Z/, '')
|
||||
mod_count = 30
|
||||
thread_count = 16
|
||||
|
||||
mod_names = []
|
||||
mod_count.times do |i|
|
||||
mod_name = :"Mod#{i}"
|
||||
Object.autoload mod_name, autoload_path
|
||||
mod_names << mod_name
|
||||
end
|
||||
|
||||
barrier = ModuleSpecs::CyclicBarrier.new thread_count
|
||||
ScratchPad.record ModuleSpecs::ThreadSafeCounter.new
|
||||
|
||||
threads = (1..thread_count).map do
|
||||
Thread.new do
|
||||
mod_names.each do |mod_name|
|
||||
break false unless barrier.enabled?
|
||||
|
||||
was_last_one_in = barrier.await # wait for all threads to finish the iteration
|
||||
# clean up so we can autoload the same file again
|
||||
$LOADED_FEATURES.delete(file_path) if was_last_one_in && $LOADED_FEATURES.include?(file_path)
|
||||
barrier.await # get ready for race
|
||||
|
||||
begin
|
||||
Object.const_get(mod_name).foo
|
||||
rescue NoMethodError
|
||||
barrier.disable!
|
||||
break false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# check that no thread got a NoMethodError because of partially loaded module
|
||||
threads.all? {|t| t.value}.should be_true
|
||||
|
||||
# check that the autoloaded file was evaled exactly once
|
||||
ScratchPad.recorded.get.should == mod_count
|
||||
|
||||
mod_names.each do |mod_name|
|
||||
Object.send(:remove_const, mod_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "loads the registered constant even if the constant was already loaded by another thread" do
|
||||
Thread.new {
|
||||
ModuleSpecs::Autoload::FromThread::D.foo
|
||||
}.value.should == :foo
|
||||
end
|
||||
end
|
||||
31
spec/ruby/core/module/case_compare_spec.rb
Normal file
31
spec/ruby/core/module/case_compare_spec.rb
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#===" do
|
||||
it "returns true when the given Object is an instance of self or of self's descendants" do
|
||||
(ModuleSpecs::Child === ModuleSpecs::Child.new).should == true
|
||||
(ModuleSpecs::Parent === ModuleSpecs::Parent.new).should == true
|
||||
|
||||
(ModuleSpecs::Parent === ModuleSpecs::Child.new).should == true
|
||||
(Object === ModuleSpecs::Child.new).should == true
|
||||
|
||||
(ModuleSpecs::Child === String.new).should == false
|
||||
(ModuleSpecs::Child === mock('x')).should == false
|
||||
end
|
||||
|
||||
it "returns true when the given Object's class includes self or when the given Object is extended by self" do
|
||||
(ModuleSpecs::Basic === ModuleSpecs::Child.new).should == true
|
||||
(ModuleSpecs::Super === ModuleSpecs::Child.new).should == true
|
||||
(ModuleSpecs::Basic === mock('x').extend(ModuleSpecs::Super)).should == true
|
||||
(ModuleSpecs::Super === mock('y').extend(ModuleSpecs::Super)).should == true
|
||||
|
||||
(ModuleSpecs::Basic === ModuleSpecs::Parent.new).should == false
|
||||
(ModuleSpecs::Super === ModuleSpecs::Parent.new).should == false
|
||||
(ModuleSpecs::Basic === mock('z')).should == false
|
||||
(ModuleSpecs::Super === mock('a')).should == false
|
||||
end
|
||||
|
||||
it "does not let a module singleton class interfere when its on the RHS" do
|
||||
(Class === ModuleSpecs::CaseCompareOnSingleton).should == false
|
||||
end
|
||||
end
|
||||
7
spec/ruby/core/module/class_eval_spec.rb
Normal file
7
spec/ruby/core/module/class_eval_spec.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
require File.expand_path('../shared/class_eval', __FILE__)
|
||||
|
||||
describe "Module#class_eval" do
|
||||
it_behaves_like :module_class_eval, :class_eval
|
||||
end
|
||||
7
spec/ruby/core/module/class_exec_spec.rb
Normal file
7
spec/ruby/core/module/class_exec_spec.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
require File.expand_path('../shared/class_exec', __FILE__)
|
||||
|
||||
describe "Module#class_exec" do
|
||||
it_behaves_like :module_class_exec, :class_exec
|
||||
end
|
||||
72
spec/ruby/core/module/class_variable_defined_spec.rb
Normal file
72
spec/ruby/core/module/class_variable_defined_spec.rb
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#class_variable_defined?" do
|
||||
it "returns true if a class variable with the given name is defined in self" do
|
||||
c = Class.new { class_variable_set :@@class_var, "test" }
|
||||
c.class_variable_defined?(:@@class_var).should == true
|
||||
c.class_variable_defined?("@@class_var").should == true
|
||||
c.class_variable_defined?(:@@no_class_var).should == false
|
||||
c.class_variable_defined?("@@no_class_var").should == false
|
||||
ModuleSpecs::CVars.class_variable_defined?("@@cls").should == true
|
||||
end
|
||||
|
||||
it "returns true if a class variable with the given name is defined in the metaclass" do
|
||||
ModuleSpecs::CVars.class_variable_defined?("@@meta").should == true
|
||||
end
|
||||
|
||||
it "returns true if the class variable is defined in a metaclass" do
|
||||
obj = mock("metaclass class variable")
|
||||
meta = obj.singleton_class
|
||||
meta.send :class_variable_set, :@@var, 1
|
||||
meta.send(:class_variable_defined?, :@@var).should be_true
|
||||
end
|
||||
|
||||
it "returns false if the class variable is not defined in a metaclass" do
|
||||
obj = mock("metaclass class variable")
|
||||
meta = obj.singleton_class
|
||||
meta.class_variable_defined?(:@@var).should be_false
|
||||
end
|
||||
|
||||
it "returns true if a class variables with the given name is defined in an included module" do
|
||||
c = Class.new { include ModuleSpecs::MVars }
|
||||
c.class_variable_defined?("@@mvar").should == true
|
||||
end
|
||||
|
||||
it "returns false if a class variables with the given name is defined in an extended module" do
|
||||
c = Class.new
|
||||
c.extend ModuleSpecs::MVars
|
||||
c.class_variable_defined?("@@mvar").should == false
|
||||
end
|
||||
|
||||
it "raises a NameError when the given name is not allowed" do
|
||||
c = Class.new
|
||||
|
||||
lambda {
|
||||
c.class_variable_defined?(:invalid_name)
|
||||
}.should raise_error(NameError)
|
||||
|
||||
lambda {
|
||||
c.class_variable_defined?("@invalid_name")
|
||||
}.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "converts a non string/symbol/fixnum name to string using to_str" do
|
||||
c = Class.new { class_variable_set :@@class_var, "test" }
|
||||
(o = mock('@@class_var')).should_receive(:to_str).and_return("@@class_var")
|
||||
c.class_variable_defined?(o).should == true
|
||||
end
|
||||
|
||||
it "raises a TypeError when the given names can't be converted to strings using to_str" do
|
||||
c = Class.new { class_variable_set :@@class_var, "test" }
|
||||
o = mock('123')
|
||||
lambda {
|
||||
c.class_variable_defined?(o)
|
||||
}.should raise_error(TypeError)
|
||||
|
||||
o.should_receive(:to_str).and_return(123)
|
||||
lambda {
|
||||
c.class_variable_defined?(o)
|
||||
}.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
76
spec/ruby/core/module/class_variable_get_spec.rb
Normal file
76
spec/ruby/core/module/class_variable_get_spec.rb
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#class_variable_get" do
|
||||
it "returns the value of the class variable with the given name" do
|
||||
c = Class.new { class_variable_set :@@class_var, "test" }
|
||||
c.send(:class_variable_get, :@@class_var).should == "test"
|
||||
c.send(:class_variable_get, "@@class_var").should == "test"
|
||||
end
|
||||
|
||||
it "returns the value of a class variable with the given name defined in an included module" do
|
||||
c = Class.new { include ModuleSpecs::MVars }
|
||||
c.send(:class_variable_get, "@@mvar").should == :mvar
|
||||
end
|
||||
|
||||
it "raises a NameError for a class variable named '@@'" do
|
||||
c = Class.new
|
||||
lambda { c.send(:class_variable_get, "@@") }.should raise_error(NameError)
|
||||
lambda { c.send(:class_variable_get, :"@@") }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a NameError for a class variables with the given name defined in an extended module" do
|
||||
c = Class.new
|
||||
c.extend ModuleSpecs::MVars
|
||||
lambda {
|
||||
c.send(:class_variable_get, "@@mvar")
|
||||
}.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "returns class variables defined in the class body and accessed in the metaclass" do
|
||||
ModuleSpecs::CVars.cls.should == :class
|
||||
end
|
||||
|
||||
it "returns class variables defined in the metaclass and accessed by class methods" do
|
||||
ModuleSpecs::CVars.meta.should == :metainfo
|
||||
end
|
||||
|
||||
it "returns class variables defined in the metaclass and accessed by instance methods" do
|
||||
ModuleSpecs::CVars.new.meta.should == :metainfo
|
||||
end
|
||||
|
||||
it "returns a class variable defined in a metaclass" do
|
||||
obj = mock("metaclass class variable")
|
||||
meta = obj.singleton_class
|
||||
meta.send :class_variable_set, :@@var, :cvar_value
|
||||
meta.send(:class_variable_get, :@@var).should == :cvar_value
|
||||
end
|
||||
|
||||
it "raises a NameError when an uninitialized class variable is accessed" do
|
||||
c = Class.new
|
||||
[:@@no_class_var, "@@no_class_var"].each do |cvar|
|
||||
lambda { c.send(:class_variable_get, cvar) }.should raise_error(NameError)
|
||||
end
|
||||
end
|
||||
|
||||
it "raises a NameError when the given name is not allowed" do
|
||||
c = Class.new
|
||||
|
||||
lambda { c.send(:class_variable_get, :invalid_name) }.should raise_error(NameError)
|
||||
lambda { c.send(:class_variable_get, "@invalid_name") }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "converts a non string/symbol/fixnum name to string using to_str" do
|
||||
c = Class.new { class_variable_set :@@class_var, "test" }
|
||||
(o = mock('@@class_var')).should_receive(:to_str).and_return("@@class_var")
|
||||
c.send(:class_variable_get, o).should == "test"
|
||||
end
|
||||
|
||||
it "raises a TypeError when the given names can't be converted to strings using to_str" do
|
||||
c = Class.new { class_variable_set :@@class_var, "test" }
|
||||
o = mock('123')
|
||||
lambda { c.send(:class_variable_get, o) }.should raise_error(TypeError)
|
||||
o.should_receive(:to_str).and_return(123)
|
||||
lambda { c.send(:class_variable_get, o) }.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
62
spec/ruby/core/module/class_variable_set_spec.rb
Normal file
62
spec/ruby/core/module/class_variable_set_spec.rb
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#class_variable_set" do
|
||||
it "sets the class variable with the given name to the given value" do
|
||||
c = Class.new
|
||||
|
||||
c.send(:class_variable_set, :@@test, "test")
|
||||
c.send(:class_variable_set, "@@test3", "test3")
|
||||
|
||||
c.send(:class_variable_get, :@@test).should == "test"
|
||||
c.send(:class_variable_get, :@@test3).should == "test3"
|
||||
end
|
||||
|
||||
it "sets a class variable on a metaclass" do
|
||||
obj = mock("metaclass class variable")
|
||||
meta = obj.singleton_class
|
||||
meta.send(:class_variable_set, :@@var, :cvar_value).should == :cvar_value
|
||||
meta.send(:class_variable_get, :@@var).should == :cvar_value
|
||||
end
|
||||
|
||||
it "sets the value of a class variable with the given name defined in an included module" do
|
||||
c = Class.new { include ModuleSpecs::MVars.dup }
|
||||
c.send(:class_variable_set, "@@mvar", :new_mvar).should == :new_mvar
|
||||
c.send(:class_variable_get, "@@mvar").should == :new_mvar
|
||||
end
|
||||
|
||||
it "raises a RuntimeError when self is frozen" do
|
||||
lambda {
|
||||
Class.new.freeze.send(:class_variable_set, :@@test, "test")
|
||||
}.should raise_error(RuntimeError)
|
||||
lambda {
|
||||
Module.new.freeze.send(:class_variable_set, :@@test, "test")
|
||||
}.should raise_error(RuntimeError)
|
||||
end
|
||||
|
||||
it "raises a NameError when the given name is not allowed" do
|
||||
c = Class.new
|
||||
|
||||
lambda {
|
||||
c.send(:class_variable_set, :invalid_name, "test")
|
||||
}.should raise_error(NameError)
|
||||
lambda {
|
||||
c.send(:class_variable_set, "@invalid_name", "test")
|
||||
}.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "converts a non string/symbol/fixnum name to string using to_str" do
|
||||
(o = mock('@@class_var')).should_receive(:to_str).and_return("@@class_var")
|
||||
c = Class.new
|
||||
c.send(:class_variable_set, o, "test")
|
||||
c.send(:class_variable_get, :@@class_var).should == "test"
|
||||
end
|
||||
|
||||
it "raises a TypeError when the given names can't be converted to strings using to_str" do
|
||||
c = Class.new { class_variable_set :@@class_var, "test" }
|
||||
o = mock('123')
|
||||
lambda { c.send(:class_variable_set, o, "test") }.should raise_error(TypeError)
|
||||
o.should_receive(:to_str).and_return(123)
|
||||
lambda { c.send(:class_variable_set, o, "test") }.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
26
spec/ruby/core/module/class_variables_spec.rb
Normal file
26
spec/ruby/core/module/class_variables_spec.rb
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#class_variables" do
|
||||
it "returns an Array with the names of class variables of self" do
|
||||
ModuleSpecs::ClassVars::A.class_variables.should include(:@@a_cvar)
|
||||
ModuleSpecs::ClassVars::M.class_variables.should include(:@@m_cvar)
|
||||
end
|
||||
|
||||
it "returns an Array of Symbols of class variable names defined in a metaclass" do
|
||||
obj = mock("metaclass class variable")
|
||||
meta = obj.singleton_class
|
||||
meta.send :class_variable_set, :@@var, :cvar_value
|
||||
meta.class_variables.should == [:@@var]
|
||||
end
|
||||
|
||||
it "returns an Array with names of class variables defined in metaclasses" do
|
||||
ModuleSpecs::CVars.class_variables.should include(:@@cls, :@@meta)
|
||||
end
|
||||
|
||||
it "does not return class variables defined in extended modules" do
|
||||
c = Class.new
|
||||
c.extend ModuleSpecs::MVars
|
||||
c.class_variables.should_not include(:@@mvar)
|
||||
end
|
||||
end
|
||||
36
spec/ruby/core/module/comparison_spec.rb
Normal file
36
spec/ruby/core/module/comparison_spec.rb
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#<=>" do
|
||||
it "returns -1 if self is a subclass of or includes the given module" do
|
||||
(ModuleSpecs::Child <=> ModuleSpecs::Parent).should == -1
|
||||
(ModuleSpecs::Child <=> ModuleSpecs::Basic).should == -1
|
||||
(ModuleSpecs::Child <=> ModuleSpecs::Super).should == -1
|
||||
(ModuleSpecs::Super <=> ModuleSpecs::Basic).should == -1
|
||||
end
|
||||
|
||||
it "returns 0 if self is the same as the given module" do
|
||||
(ModuleSpecs::Child <=> ModuleSpecs::Child).should == 0
|
||||
(ModuleSpecs::Parent <=> ModuleSpecs::Parent).should == 0
|
||||
(ModuleSpecs::Basic <=> ModuleSpecs::Basic).should == 0
|
||||
(ModuleSpecs::Super <=> ModuleSpecs::Super).should == 0
|
||||
end
|
||||
|
||||
it "returns +1 if self is a superclas of or included by the given module" do
|
||||
(ModuleSpecs::Parent <=> ModuleSpecs::Child).should == +1
|
||||
(ModuleSpecs::Basic <=> ModuleSpecs::Child).should == +1
|
||||
(ModuleSpecs::Super <=> ModuleSpecs::Child).should == +1
|
||||
(ModuleSpecs::Basic <=> ModuleSpecs::Super).should == +1
|
||||
end
|
||||
|
||||
it "returns nil if self and the given module are not related" do
|
||||
(ModuleSpecs::Parent <=> ModuleSpecs::Basic).should == nil
|
||||
(ModuleSpecs::Parent <=> ModuleSpecs::Super).should == nil
|
||||
(ModuleSpecs::Basic <=> ModuleSpecs::Parent).should == nil
|
||||
(ModuleSpecs::Super <=> ModuleSpecs::Parent).should == nil
|
||||
end
|
||||
|
||||
it "returns nil if the argument is not a class/module" do
|
||||
(ModuleSpecs::Parent <=> mock('x')).should == nil
|
||||
end
|
||||
end
|
||||
144
spec/ruby/core/module/const_defined_spec.rb
Normal file
144
spec/ruby/core/module/const_defined_spec.rb
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
# encoding: utf-8
|
||||
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../../../fixtures/constants', __FILE__)
|
||||
require File.expand_path('../fixtures/constant_unicode', __FILE__)
|
||||
|
||||
describe "Module#const_defined?" do
|
||||
it "returns true if the given Symbol names a constant defined in the receiver" do
|
||||
ConstantSpecs.const_defined?(:CS_CONST2).should == true
|
||||
ConstantSpecs.const_defined?(:ModuleA).should == true
|
||||
ConstantSpecs.const_defined?(:ClassA).should == true
|
||||
ConstantSpecs::ContainerA.const_defined?(:ChildA).should == true
|
||||
end
|
||||
|
||||
it "returns true if the constant is defined in the reciever's superclass" do
|
||||
# CS_CONST4 is defined in the superclass of ChildA
|
||||
ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4).should be_true
|
||||
end
|
||||
|
||||
it "returns true if the constant is defined in a mixed-in module of the reciever" do
|
||||
# CS_CONST10 is defined in a module included by ChildA
|
||||
ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST10).should be_true
|
||||
end
|
||||
|
||||
it "returns true if the constant is defined in Object and the receiver is a module" do
|
||||
# CS_CONST1 is defined in Object
|
||||
ConstantSpecs::ModuleA.const_defined?(:CS_CONST1).should be_true
|
||||
end
|
||||
|
||||
it "returns true if the constant is defined in Object and the receiver is a class that has Object among its ancestors" do
|
||||
# CS_CONST1 is defined in Object
|
||||
ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST1).should be_true
|
||||
end
|
||||
|
||||
it "returns false if the constant is defined in the receiver's superclass and the inherit flag is false" do
|
||||
ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, false).should be_false
|
||||
end
|
||||
|
||||
it "returns true if the constant is defined in the receiver's superclass and the inherit flag is true" do
|
||||
ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, true).should be_true
|
||||
end
|
||||
|
||||
it "returns true if the given String names a constant defined in the receiver" do
|
||||
ConstantSpecs.const_defined?("CS_CONST2").should == true
|
||||
ConstantSpecs.const_defined?("ModuleA").should == true
|
||||
ConstantSpecs.const_defined?("ClassA").should == true
|
||||
ConstantSpecs::ContainerA.const_defined?("ChildA").should == true
|
||||
end
|
||||
|
||||
it "returns true when passed a constant name with unicode characters" do
|
||||
ConstantUnicodeSpecs.const_defined?("CS_CONSTλ").should be_true
|
||||
end
|
||||
|
||||
it "returns true when passed a constant name with EUC-JP characters" do
|
||||
str = "CS_CONSTλ".encode("euc-jp")
|
||||
ConstantSpecs.const_set str, 1
|
||||
ConstantSpecs.const_defined?(str).should be_true
|
||||
end
|
||||
|
||||
it "returns false if the constant is not defined in the receiver, its superclass, or any included modules" do
|
||||
# The following constant isn't defined at all.
|
||||
ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4726).should be_false
|
||||
# DETACHED_CONSTANT is defined in ConstantSpecs::Detached, which isn't
|
||||
# included by or inherited from ParentA
|
||||
ConstantSpecs::ParentA.const_defined?(:DETACHED_CONSTANT).should be_false
|
||||
end
|
||||
|
||||
it "does not call #const_missing if the constant is not defined in the receiver" do
|
||||
ConstantSpecs::ClassA.should_not_receive(:const_missing)
|
||||
ConstantSpecs::ClassA.const_defined?(:CS_CONSTX).should == false
|
||||
end
|
||||
|
||||
it "calls #to_str to convert the given name to a String" do
|
||||
name = mock("ClassA")
|
||||
name.should_receive(:to_str).and_return("ClassA")
|
||||
ConstantSpecs.const_defined?(name).should == true
|
||||
end
|
||||
|
||||
it "special cases Object and checks it's included Modules" do
|
||||
Object.const_defined?(:CS_CONST10).should be_true
|
||||
end
|
||||
|
||||
it "returns true for toplevel constant when the name begins with '::'" do
|
||||
ConstantSpecs.const_defined?("::Array").should be_true
|
||||
end
|
||||
|
||||
it "returns true when passed a scoped constant name" do
|
||||
ConstantSpecs.const_defined?("ClassC::CS_CONST1").should be_true
|
||||
end
|
||||
|
||||
it "returns true when passed a scoped constant name for a constant in the inheritance hierarchy and the inherited flag is default" do
|
||||
ConstantSpecs::ClassD.const_defined?("ClassE::CS_CONST2").should be_true
|
||||
end
|
||||
|
||||
it "returns true when passed a scoped constant name for a constant in the inheritance hierarchy and the inherited flag is true" do
|
||||
ConstantSpecs::ClassD.const_defined?("ClassE::CS_CONST2", true).should be_true
|
||||
end
|
||||
|
||||
it "returns false when passed a scoped constant name for a constant in the inheritance hierarchy and the inherited flag is false" do
|
||||
ConstantSpecs::ClassD.const_defined?("ClassE::CS_CONST2", false).should be_false
|
||||
end
|
||||
|
||||
it "returns false when the name begins with '::' and the toplevel constant does not exist" do
|
||||
ConstantSpecs.const_defined?("::Name").should be_false
|
||||
end
|
||||
|
||||
it "raises a NameError if the name does not start with a capital letter" do
|
||||
lambda { ConstantSpecs.const_defined? "name" }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a NameError if the name starts with '_'" do
|
||||
lambda { ConstantSpecs.const_defined? "__CONSTX__" }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a NameError if the name starts with '@'" do
|
||||
lambda { ConstantSpecs.const_defined? "@Name" }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a NameError if the name starts with '!'" do
|
||||
lambda { ConstantSpecs.const_defined? "!Name" }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "returns true or false for the nested name" do
|
||||
ConstantSpecs.const_defined?("NotExist::Name").should == false
|
||||
ConstantSpecs.const_defined?("::Name").should == false
|
||||
ConstantSpecs.const_defined?("::Object").should == true
|
||||
ConstantSpecs.const_defined?("ClassA::CS_CONST10").should == true
|
||||
ConstantSpecs.const_defined?("ClassA::CS_CONST10_").should == false
|
||||
end
|
||||
|
||||
it "raises a NameError if the name contains non-alphabetic characters except '_'" do
|
||||
ConstantSpecs.const_defined?("CS_CONSTX").should == false
|
||||
lambda { ConstantSpecs.const_defined? "Name=" }.should raise_error(NameError)
|
||||
lambda { ConstantSpecs.const_defined? "Name?" }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a TypeError if conversion to a String by calling #to_str fails" do
|
||||
name = mock('123')
|
||||
lambda { ConstantSpecs.const_defined? name }.should raise_error(TypeError)
|
||||
|
||||
name.should_receive(:to_str).and_return(123)
|
||||
lambda { ConstantSpecs.const_defined? name }.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
208
spec/ruby/core/module/const_get_spec.rb
Normal file
208
spec/ruby/core/module/const_get_spec.rb
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../../../fixtures/constants', __FILE__)
|
||||
|
||||
describe "Module#const_get" do
|
||||
it "accepts a String or Symbol name" do
|
||||
Object.const_get(:CS_CONST1).should == :const1
|
||||
Object.const_get("CS_CONST1").should == :const1
|
||||
end
|
||||
|
||||
it "raises a NameError if no constant is defined in the search path" do
|
||||
lambda { ConstantSpecs.const_get :CS_CONSTX }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a NameError with the not found constant symbol" do
|
||||
error_inspection = lambda { |e| e.name.should == :CS_CONSTX }
|
||||
lambda { ConstantSpecs.const_get :CS_CONSTX }.should raise_error(NameError, &error_inspection)
|
||||
end
|
||||
|
||||
it "raises a NameError if the name does not start with a capital letter" do
|
||||
lambda { ConstantSpecs.const_get "name" }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a NameError if the name starts with a non-alphabetic character" do
|
||||
lambda { ConstantSpecs.const_get "__CONSTX__" }.should raise_error(NameError)
|
||||
lambda { ConstantSpecs.const_get "@CS_CONST1" }.should raise_error(NameError)
|
||||
lambda { ConstantSpecs.const_get "!CS_CONST1" }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a NameError if the name contains non-alphabetic characters except '_'" do
|
||||
Object.const_get("CS_CONST1").should == :const1
|
||||
lambda { ConstantSpecs.const_get "CS_CONST1=" }.should raise_error(NameError)
|
||||
lambda { ConstantSpecs.const_get "CS_CONST1?" }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "calls #to_str to convert the given name to a String" do
|
||||
name = mock("ClassA")
|
||||
name.should_receive(:to_str).and_return("ClassA")
|
||||
ConstantSpecs.const_get(name).should == ConstantSpecs::ClassA
|
||||
end
|
||||
|
||||
it "raises a TypeError if conversion to a String by calling #to_str fails" do
|
||||
name = mock('123')
|
||||
lambda { ConstantSpecs.const_get(name) }.should raise_error(TypeError)
|
||||
|
||||
name.should_receive(:to_str).and_return(123)
|
||||
lambda { ConstantSpecs.const_get(name) }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "calls #const_missing on the receiver if unable to locate the constant" do
|
||||
ConstantSpecs::ContainerA.should_receive(:const_missing).with(:CS_CONSTX)
|
||||
ConstantSpecs::ContainerA.const_get(:CS_CONSTX)
|
||||
end
|
||||
|
||||
it "does not search the singleton class of a Class or Module" do
|
||||
lambda do
|
||||
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST14)
|
||||
end.should raise_error(NameError)
|
||||
lambda { ConstantSpecs.const_get(:CS_CONST14) }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "does not search the containing scope" do
|
||||
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST20).should == :const20_2
|
||||
lambda do
|
||||
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST5)
|
||||
end.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a NameError if the constant is defined in the receiver's supperclass and the inherit flag is false" do
|
||||
lambda do
|
||||
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST4, false)
|
||||
end.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "searches into the receiver superclasses if the inherit flag is true" do
|
||||
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST4, true).should == :const4
|
||||
end
|
||||
|
||||
it "raises a NameError when the receiver is a Module, the constant is defined at toplevel and the inherit flag is false" do
|
||||
lambda do
|
||||
ConstantSpecs::ModuleA.const_get(:CS_CONST1, false)
|
||||
end.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a NameError when the receiver is a Class, the constant is defined at toplevel and the inherit flag is false" do
|
||||
lambda do
|
||||
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST1, false)
|
||||
end.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "accepts a toplevel scope qualifier" do
|
||||
ConstantSpecs.const_get("::CS_CONST1").should == :const1
|
||||
end
|
||||
|
||||
it "accepts a scoped constant name" do
|
||||
ConstantSpecs.const_get("ClassA::CS_CONST10").should == :const10_10
|
||||
end
|
||||
|
||||
it "raises a NameError if only '::' is passed" do
|
||||
lambda { ConstantSpecs.const_get("::") }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a NameError if a Symbol has a toplevel scope qualifier" do
|
||||
lambda { ConstantSpecs.const_get(:'::CS_CONST1') }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a NameError if a Symbol is a scoped constant name" do
|
||||
lambda { ConstantSpecs.const_get(:'ClassA::CS_CONST10') }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "does read private constants" do
|
||||
ConstantSpecs.const_get(:CS_PRIVATE).should == :cs_private
|
||||
end
|
||||
|
||||
describe "with statically assigned constants" do
|
||||
it "searches the immediate class or module first" do
|
||||
ConstantSpecs::ClassA.const_get(:CS_CONST10).should == :const10_10
|
||||
ConstantSpecs::ModuleA.const_get(:CS_CONST10).should == :const10_1
|
||||
ConstantSpecs::ParentA.const_get(:CS_CONST10).should == :const10_5
|
||||
ConstantSpecs::ContainerA.const_get(:CS_CONST10).should == :const10_2
|
||||
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST10).should == :const10_3
|
||||
end
|
||||
|
||||
it "searches a module included in the immediate class before the superclass" do
|
||||
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST15).should == :const15_1
|
||||
end
|
||||
|
||||
it "searches the superclass before a module included in the superclass" do
|
||||
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST11).should == :const11_1
|
||||
end
|
||||
|
||||
it "searches a module included in the superclass" do
|
||||
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST12).should == :const12_1
|
||||
end
|
||||
|
||||
it "searches the superclass chain" do
|
||||
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST13).should == :const13
|
||||
end
|
||||
|
||||
it "returns a toplevel constant when the receiver is a Class" do
|
||||
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST1).should == :const1
|
||||
end
|
||||
|
||||
it "returns a toplevel constant when the receiver is a Module" do
|
||||
ConstantSpecs.const_get(:CS_CONST1).should == :const1
|
||||
ConstantSpecs::ModuleA.const_get(:CS_CONST1).should == :const1
|
||||
end
|
||||
end
|
||||
|
||||
describe "with dynamically assigned constants" do
|
||||
it "searches the immediate class or module first" do
|
||||
ConstantSpecs::ClassA::CS_CONST301 = :const301_1
|
||||
ConstantSpecs::ClassA.const_get(:CS_CONST301).should == :const301_1
|
||||
|
||||
ConstantSpecs::ModuleA::CS_CONST301 = :const301_2
|
||||
ConstantSpecs::ModuleA.const_get(:CS_CONST301).should == :const301_2
|
||||
|
||||
ConstantSpecs::ParentA::CS_CONST301 = :const301_3
|
||||
ConstantSpecs::ParentA.const_get(:CS_CONST301).should == :const301_3
|
||||
|
||||
ConstantSpecs::ContainerA::ChildA::CS_CONST301 = :const301_5
|
||||
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST301).should == :const301_5
|
||||
end
|
||||
|
||||
it "searches a module included in the immediate class before the superclass" do
|
||||
ConstantSpecs::ParentB::CS_CONST302 = :const302_1
|
||||
ConstantSpecs::ModuleF::CS_CONST302 = :const302_2
|
||||
ConstantSpecs::ContainerB::ChildB.const_get(:CS_CONST302).should == :const302_2
|
||||
end
|
||||
|
||||
it "searches the superclass before a module included in the superclass" do
|
||||
ConstantSpecs::ModuleE::CS_CONST303 = :const303_1
|
||||
ConstantSpecs::ParentB::CS_CONST303 = :const303_2
|
||||
ConstantSpecs::ContainerB::ChildB.const_get(:CS_CONST303).should == :const303_2
|
||||
end
|
||||
|
||||
it "searches a module included in the superclass" do
|
||||
ConstantSpecs::ModuleA::CS_CONST304 = :const304_1
|
||||
ConstantSpecs::ModuleE::CS_CONST304 = :const304_2
|
||||
ConstantSpecs::ContainerB::ChildB.const_get(:CS_CONST304).should == :const304_2
|
||||
end
|
||||
|
||||
it "searches the superclass chain" do
|
||||
ConstantSpecs::ModuleA::CS_CONST305 = :const305
|
||||
ConstantSpecs::ContainerB::ChildB.const_get(:CS_CONST305).should == :const305
|
||||
end
|
||||
|
||||
it "returns a toplevel constant when the receiver is a Class" do
|
||||
Object::CS_CONST306 = :const306
|
||||
ConstantSpecs::ContainerB::ChildB.const_get(:CS_CONST306).should == :const306
|
||||
end
|
||||
|
||||
it "returns a toplevel constant when the receiver is a Module" do
|
||||
Object::CS_CONST308 = :const308
|
||||
ConstantSpecs.const_get(:CS_CONST308).should == :const308
|
||||
ConstantSpecs::ModuleA.const_get(:CS_CONST308).should == :const308
|
||||
end
|
||||
|
||||
it "returns the updated value of a constant" do
|
||||
ConstantSpecs::ClassB::CS_CONST309 = :const309_1
|
||||
ConstantSpecs::ClassB.const_get(:CS_CONST309).should == :const309_1
|
||||
|
||||
lambda {
|
||||
ConstantSpecs::ClassB::CS_CONST309 = :const309_2
|
||||
}.should complain(/already initialized constant/)
|
||||
ConstantSpecs::ClassB.const_get(:CS_CONST309).should == :const309_2
|
||||
end
|
||||
end
|
||||
end
|
||||
27
spec/ruby/core/module/const_missing_spec.rb
Normal file
27
spec/ruby/core/module/const_missing_spec.rb
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../../../fixtures/constants', __FILE__)
|
||||
|
||||
describe "Module#const_missing" do
|
||||
it "is called when an undefined constant is referenced via literal form" do
|
||||
ConstantSpecs::ClassA::CS_CONSTX.should == :CS_CONSTX
|
||||
end
|
||||
|
||||
it "is called when an undefined constant is referenced via #const_get" do
|
||||
ConstantSpecs::ClassA.const_get(:CS_CONSTX).should == :CS_CONSTX
|
||||
end
|
||||
|
||||
it "raises NameError and includes the name of the value that wasn't found" do
|
||||
lambda {
|
||||
ConstantSpecs.const_missing("HelloMissing")
|
||||
}.should raise_error(NameError, /ConstantSpecs::HelloMissing/)
|
||||
end
|
||||
|
||||
it "raises NameError and does not include toplevel Object" do
|
||||
begin
|
||||
Object.const_missing("HelloMissing")
|
||||
rescue NameError => e
|
||||
e.message.should_not =~ / Object::/
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
86
spec/ruby/core/module/const_set_spec.rb
Normal file
86
spec/ruby/core/module/const_set_spec.rb
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../../../fixtures/constants', __FILE__)
|
||||
|
||||
describe "Module#const_set" do
|
||||
it "sets the constant specified by a String or Symbol to the given value" do
|
||||
ConstantSpecs.const_set :CS_CONST401, :const401
|
||||
ConstantSpecs::CS_CONST401.should == :const401
|
||||
|
||||
ConstantSpecs.const_set "CS_CONST402", :const402
|
||||
ConstantSpecs.const_get(:CS_CONST402).should == :const402
|
||||
end
|
||||
|
||||
it "returns the value set" do
|
||||
ConstantSpecs.const_set(:CS_CONST403, :const403).should == :const403
|
||||
end
|
||||
|
||||
it "sets the name of an anonymous module" do
|
||||
m = Module.new
|
||||
ConstantSpecs.const_set(:CS_CONST1000, m)
|
||||
m.name.should == "ConstantSpecs::CS_CONST1000"
|
||||
end
|
||||
|
||||
it "does not set the name of a module scoped by an anonymous module" do
|
||||
a, b = Module.new, Module.new
|
||||
a.const_set :B, b
|
||||
b.name.should be_nil
|
||||
end
|
||||
|
||||
it "sets the name of contained modules when assigning a toplevel anonymous module" do
|
||||
a, b, c, d = Module.new, Module.new, Module.new, Module.new
|
||||
a::B = b
|
||||
a::B::C = c
|
||||
a::B::C::E = c
|
||||
a::D = d
|
||||
|
||||
Object.const_set :ModuleSpecs_CS3, a
|
||||
a.name.should == "ModuleSpecs_CS3"
|
||||
b.name.should == "ModuleSpecs_CS3::B"
|
||||
c.name.should == "ModuleSpecs_CS3::B::C"
|
||||
d.name.should == "ModuleSpecs_CS3::D"
|
||||
end
|
||||
|
||||
it "raises a NameError if the name does not start with a capital letter" do
|
||||
lambda { ConstantSpecs.const_set "name", 1 }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a NameError if the name starts with a non-alphabetic character" do
|
||||
lambda { ConstantSpecs.const_set "__CONSTX__", 1 }.should raise_error(NameError)
|
||||
lambda { ConstantSpecs.const_set "@Name", 1 }.should raise_error(NameError)
|
||||
lambda { ConstantSpecs.const_set "!Name", 1 }.should raise_error(NameError)
|
||||
lambda { ConstantSpecs.const_set "::Name", 1 }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a NameError if the name contains non-alphabetic characters except '_'" do
|
||||
ConstantSpecs.const_set("CS_CONST404", :const404).should == :const404
|
||||
lambda { ConstantSpecs.const_set "Name=", 1 }.should raise_error(NameError)
|
||||
lambda { ConstantSpecs.const_set "Name?", 1 }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "calls #to_str to convert the given name to a String" do
|
||||
name = mock("CS_CONST405")
|
||||
name.should_receive(:to_str).and_return("CS_CONST405")
|
||||
ConstantSpecs.const_set(name, :const405).should == :const405
|
||||
ConstantSpecs::CS_CONST405.should == :const405
|
||||
end
|
||||
|
||||
it "raises a TypeError if conversion to a String by calling #to_str fails" do
|
||||
name = mock('123')
|
||||
lambda { ConstantSpecs.const_set name, 1 }.should raise_error(TypeError)
|
||||
|
||||
name.should_receive(:to_str).and_return(123)
|
||||
lambda { ConstantSpecs.const_set name, 1 }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
describe "on a frozen module" do
|
||||
before :each do
|
||||
@frozen = Module.new.freeze
|
||||
@name = :Foo
|
||||
end
|
||||
|
||||
it "raises a RuntimeError before setting the name" do
|
||||
lambda { @frozen.const_set @name, nil }.should raise_error(RuntimeError)
|
||||
@frozen.should_not have_constant(@name)
|
||||
end
|
||||
end
|
||||
end
|
||||
91
spec/ruby/core/module/constants_spec.rb
Normal file
91
spec/ruby/core/module/constants_spec.rb
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../../../fixtures/constants', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module.constants" do
|
||||
it "returns an array of the names of all toplevel constants" do
|
||||
count = Module.constants.size
|
||||
module ConstantSpecsAdded
|
||||
end
|
||||
Module.constants.size.should == count + 1
|
||||
Object.send(:remove_const, :ConstantSpecsAdded)
|
||||
end
|
||||
|
||||
it "returns an array of Symbol names" do
|
||||
# This in NOT an exhaustive list
|
||||
Module.constants.should include(:Array, :Bignum, :Class, :Comparable, :Dir,
|
||||
:Enumerable, :ENV, :Exception, :FalseClass,
|
||||
:File, :Fixnum, :Float, :Hash, :Integer, :IO,
|
||||
:Kernel, :Math, :Method, :Module, :NilClass,
|
||||
:Numeric, :Object, :Range, :Regexp, :String,
|
||||
:Symbol, :Thread, :Time, :TrueClass)
|
||||
end
|
||||
|
||||
it "returns Module's constants when given a parameter" do
|
||||
direct = Module.constants(false)
|
||||
indirect = Module.constants(true)
|
||||
module ConstantSpecsIncludedModule
|
||||
MODULE_CONSTANTS_SPECS_INDIRECT = :foo
|
||||
end
|
||||
|
||||
class Module
|
||||
MODULE_CONSTANTS_SPECS_DIRECT = :bar
|
||||
include ConstantSpecsIncludedModule
|
||||
end
|
||||
(Module.constants(false) - direct).should == [:MODULE_CONSTANTS_SPECS_DIRECT]
|
||||
(Module.constants(true) - indirect).sort.should == [:MODULE_CONSTANTS_SPECS_DIRECT, :MODULE_CONSTANTS_SPECS_INDIRECT]
|
||||
|
||||
Module.send(:remove_const, :MODULE_CONSTANTS_SPECS_DIRECT)
|
||||
ConstantSpecsIncludedModule.send(:remove_const, :MODULE_CONSTANTS_SPECS_INDIRECT)
|
||||
end
|
||||
end
|
||||
|
||||
describe "Module#constants" do
|
||||
it "returns an array of Symbol names of all constants defined in the module and all included modules" do
|
||||
ConstantSpecs::ContainerA.constants.sort.should == [
|
||||
:CS_CONST10, :CS_CONST23, :CS_CONST24, :CS_CONST5, :ChildA
|
||||
]
|
||||
end
|
||||
|
||||
it "returns all constants including inherited when passed true" do
|
||||
ConstantSpecs::ContainerA.constants(true).sort.should == [
|
||||
:CS_CONST10, :CS_CONST23, :CS_CONST24, :CS_CONST5, :ChildA
|
||||
]
|
||||
end
|
||||
|
||||
it "returns all constants including inherited when passed some object" do
|
||||
ConstantSpecs::ContainerA.constants(Object.new).sort.should == [
|
||||
:CS_CONST10, :CS_CONST23, :CS_CONST24, :CS_CONST5, :ChildA
|
||||
]
|
||||
end
|
||||
|
||||
it "doesn't returns inherited constants when passed false" do
|
||||
ConstantSpecs::ContainerA.constants(false).sort.should == [
|
||||
:CS_CONST10, :CS_CONST23, :CS_CONST5, :ChildA
|
||||
]
|
||||
end
|
||||
|
||||
it "doesn't returns inherited constants when passed nil" do
|
||||
ConstantSpecs::ContainerA.constants(nil).sort.should == [
|
||||
:CS_CONST10, :CS_CONST23, :CS_CONST5, :ChildA
|
||||
]
|
||||
end
|
||||
|
||||
it "returns only public constants" do
|
||||
ModuleSpecs::PrivConstModule.constants.should == [:PUBLIC_CONSTANT]
|
||||
end
|
||||
end
|
||||
|
||||
describe "Module#constants" do
|
||||
before :each do
|
||||
ConstantSpecs::ModuleM::CS_CONST251 = :const251
|
||||
end
|
||||
|
||||
after :each do
|
||||
ConstantSpecs::ModuleM.send(:remove_const, :CS_CONST251)
|
||||
end
|
||||
|
||||
it "includes names of constants defined after a module is included" do
|
||||
ConstantSpecs::ContainerA.constants.should include(:CS_CONST251)
|
||||
end
|
||||
end
|
||||
626
spec/ruby/core/module/define_method_spec.rb
Normal file
626
spec/ruby/core/module/define_method_spec.rb
Normal file
|
|
@ -0,0 +1,626 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
class DefineMethodSpecClass
|
||||
end
|
||||
|
||||
describe "passed { |a, b = 1| } creates a method that" do
|
||||
before :each do
|
||||
@klass = Class.new do
|
||||
define_method(:m) { |a, b = 1| return a, b }
|
||||
end
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when passed zero arguments" do
|
||||
lambda { @klass.new.m }.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "has a default value for b when passed one argument" do
|
||||
@klass.new.m(1).should == [1, 1]
|
||||
end
|
||||
|
||||
it "overrides the default argument when passed two arguments" do
|
||||
@klass.new.m(1, 2).should == [1, 2]
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when passed three arguments" do
|
||||
lambda { @klass.new.m(1, 2, 3) }.should raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
describe "Module#define_method when given an UnboundMethod" do
|
||||
it "passes the given arguments to the new method" do
|
||||
klass = Class.new do
|
||||
def test_method(arg1, arg2)
|
||||
[arg1, arg2]
|
||||
end
|
||||
define_method(:another_test_method, instance_method(:test_method))
|
||||
end
|
||||
|
||||
klass.new.another_test_method(1, 2).should == [1, 2]
|
||||
end
|
||||
|
||||
it "adds the new method to the methods list" do
|
||||
klass = Class.new do
|
||||
def test_method(arg1, arg2)
|
||||
[arg1, arg2]
|
||||
end
|
||||
define_method(:another_test_method, instance_method(:test_method))
|
||||
end
|
||||
klass.new.should have_method(:another_test_method)
|
||||
end
|
||||
|
||||
describe "defining a method on a singleton class" do
|
||||
before do
|
||||
klass = Class.new
|
||||
class << klass
|
||||
def test_method
|
||||
:foo
|
||||
end
|
||||
end
|
||||
child = Class.new(klass)
|
||||
sc = class << child; self; end
|
||||
sc.send :define_method, :another_test_method, klass.method(:test_method).unbind
|
||||
|
||||
@class = child
|
||||
end
|
||||
|
||||
it "doesn't raise TypeError when calling the method" do
|
||||
@class.another_test_method.should == :foo
|
||||
end
|
||||
end
|
||||
|
||||
it "sets the new method's visibility to the current frame's visibility" do
|
||||
foo = Class.new do
|
||||
def ziggy
|
||||
'piggy'
|
||||
end
|
||||
private :ziggy
|
||||
|
||||
# make sure frame visibility is public
|
||||
public
|
||||
|
||||
define_method :piggy, instance_method(:ziggy)
|
||||
end
|
||||
|
||||
lambda { foo.new.ziggy }.should raise_error(NoMethodError)
|
||||
foo.new.piggy.should == 'piggy'
|
||||
end
|
||||
end
|
||||
|
||||
describe "Module#define_method when name is not a special private name" do
|
||||
describe "given an UnboundMethod" do
|
||||
describe "and called from the target module" do
|
||||
it "sets the visibility of the method to the current visibility" do
|
||||
klass = Class.new do
|
||||
define_method(:bar, ModuleSpecs::EmptyFooMethod)
|
||||
private
|
||||
define_method(:baz, ModuleSpecs::EmptyFooMethod)
|
||||
end
|
||||
|
||||
klass.should have_public_instance_method(:bar)
|
||||
klass.should have_private_instance_method(:baz)
|
||||
end
|
||||
end
|
||||
|
||||
describe "and called from another module" do
|
||||
it "sets the visibility of the method to public" do
|
||||
klass = Class.new
|
||||
Class.new do
|
||||
klass.send(:define_method, :bar, ModuleSpecs::EmptyFooMethod)
|
||||
private
|
||||
klass.send(:define_method, :baz, ModuleSpecs::EmptyFooMethod)
|
||||
end
|
||||
|
||||
klass.should have_public_instance_method(:bar)
|
||||
klass.should have_public_instance_method(:baz)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "passed a block" do
|
||||
describe "and called from the target module" do
|
||||
it "sets the visibility of the method to the current visibility" do
|
||||
klass = Class.new do
|
||||
define_method(:bar) {}
|
||||
private
|
||||
define_method(:baz) {}
|
||||
end
|
||||
|
||||
klass.should have_public_instance_method(:bar)
|
||||
klass.should have_private_instance_method(:baz)
|
||||
end
|
||||
end
|
||||
|
||||
describe "and called from another module" do
|
||||
it "sets the visibility of the method to public" do
|
||||
klass = Class.new
|
||||
Class.new do
|
||||
klass.send(:define_method, :bar) {}
|
||||
private
|
||||
klass.send(:define_method, :baz) {}
|
||||
end
|
||||
|
||||
klass.should have_public_instance_method(:bar)
|
||||
klass.should have_public_instance_method(:baz)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "Module#define_method when name is :initialize" do
|
||||
describe "passed a block" do
|
||||
it "sets visibility to private when method name is :initialize" do
|
||||
klass = Class.new do
|
||||
define_method(:initialize) { }
|
||||
end
|
||||
klass.should have_private_instance_method(:initialize)
|
||||
end
|
||||
end
|
||||
|
||||
describe "given an UnboundMethod" do
|
||||
it "sets the visibility to private when method is named :initialize" do
|
||||
klass = Class.new do
|
||||
def test_method
|
||||
end
|
||||
define_method(:initialize, instance_method(:test_method))
|
||||
end
|
||||
klass.should have_private_instance_method(:initialize)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "Module#define_method" do
|
||||
it "defines the given method as an instance method with the given name in self" do
|
||||
class DefineMethodSpecClass
|
||||
def test1
|
||||
"test"
|
||||
end
|
||||
define_method(:another_test, instance_method(:test1))
|
||||
end
|
||||
|
||||
o = DefineMethodSpecClass.new
|
||||
o.test1.should == o.another_test
|
||||
end
|
||||
|
||||
it "calls #method_added after the method is added to the Module" do
|
||||
DefineMethodSpecClass.should_receive(:method_added).with(:test_ma)
|
||||
|
||||
class DefineMethodSpecClass
|
||||
define_method(:test_ma) { true }
|
||||
end
|
||||
end
|
||||
|
||||
it "defines a new method with the given name and the given block as body in self" do
|
||||
class DefineMethodSpecClass
|
||||
define_method(:block_test1) { self }
|
||||
define_method(:block_test2, &lambda { self })
|
||||
end
|
||||
|
||||
o = DefineMethodSpecClass.new
|
||||
o.block_test1.should == o
|
||||
o.block_test2.should == o
|
||||
end
|
||||
|
||||
it "raises a TypeError when the given method is no Method/Proc" do
|
||||
lambda {
|
||||
Class.new { define_method(:test, "self") }
|
||||
}.should raise_error(TypeError)
|
||||
|
||||
lambda {
|
||||
Class.new { define_method(:test, 1234) }
|
||||
}.should raise_error(TypeError)
|
||||
|
||||
lambda {
|
||||
Class.new { define_method(:test, nil) }
|
||||
}.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when no block is given" do
|
||||
lambda {
|
||||
Class.new { define_method(:test) }
|
||||
}.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
ruby_version_is "2.3" do
|
||||
it "does not use the caller block when no block is given" do
|
||||
o = Object.new
|
||||
def o.define(name)
|
||||
self.class.class_eval do
|
||||
define_method(name)
|
||||
end
|
||||
end
|
||||
|
||||
lambda {
|
||||
o.define(:foo) { raise "not used" }
|
||||
}.should raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
it "does not change the arity check style of the original proc" do
|
||||
class DefineMethodSpecClass
|
||||
prc = Proc.new { || true }
|
||||
define_method("proc_style_test", &prc)
|
||||
end
|
||||
|
||||
obj = DefineMethodSpecClass.new
|
||||
lambda { obj.proc_style_test :arg }.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "raises a RuntimeError if frozen" do
|
||||
lambda {
|
||||
Class.new { freeze; define_method(:foo) {} }
|
||||
}.should raise_error(RuntimeError)
|
||||
end
|
||||
|
||||
it "accepts a Method (still bound)" do
|
||||
class DefineMethodSpecClass
|
||||
attr_accessor :data
|
||||
def inspect_data
|
||||
"data is #{@data}"
|
||||
end
|
||||
end
|
||||
o = DefineMethodSpecClass.new
|
||||
o.data = :foo
|
||||
m = o.method(:inspect_data)
|
||||
m.should be_an_instance_of(Method)
|
||||
klass = Class.new(DefineMethodSpecClass)
|
||||
klass.send(:define_method,:other_inspect, m)
|
||||
c = klass.new
|
||||
c.data = :bar
|
||||
c.other_inspect.should == "data is bar"
|
||||
lambda{o.other_inspect}.should raise_error(NoMethodError)
|
||||
end
|
||||
|
||||
it "raises a TypeError when a Method from a singleton class is defined on another class" do
|
||||
c = Class.new do
|
||||
class << self
|
||||
def foo
|
||||
end
|
||||
end
|
||||
end
|
||||
m = c.method(:foo)
|
||||
|
||||
lambda {
|
||||
Class.new { define_method :bar, m }
|
||||
}.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "raises a TypeError when a Method from one class is defined on an unrelated class" do
|
||||
c = Class.new do
|
||||
def foo
|
||||
end
|
||||
end
|
||||
m = c.new.method(:foo)
|
||||
|
||||
lambda {
|
||||
Class.new { define_method :bar, m }
|
||||
}.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "accepts an UnboundMethod from an attr_accessor method" do
|
||||
class DefineMethodSpecClass
|
||||
attr_accessor :accessor_method
|
||||
end
|
||||
|
||||
m = DefineMethodSpecClass.instance_method(:accessor_method)
|
||||
o = DefineMethodSpecClass.new
|
||||
|
||||
DefineMethodSpecClass.send(:undef_method, :accessor_method)
|
||||
lambda { o.accessor_method }.should raise_error(NoMethodError)
|
||||
|
||||
DefineMethodSpecClass.send(:define_method, :accessor_method, m)
|
||||
|
||||
o.accessor_method = :abc
|
||||
o.accessor_method.should == :abc
|
||||
end
|
||||
|
||||
it "accepts a proc from a method" do
|
||||
class ProcFromMethod
|
||||
attr_accessor :data
|
||||
def cool_method
|
||||
"data is #{@data}"
|
||||
end
|
||||
end
|
||||
|
||||
object1 = ProcFromMethod.new
|
||||
object1.data = :foo
|
||||
|
||||
method_proc = object1.method(:cool_method).to_proc
|
||||
klass = Class.new(ProcFromMethod)
|
||||
klass.send(:define_method, :other_cool_method, &method_proc)
|
||||
|
||||
object2 = klass.new
|
||||
object2.data = :bar
|
||||
object2.other_cool_method.should == "data is foo"
|
||||
end
|
||||
|
||||
it "maintains the Proc's scope" do
|
||||
class DefineMethodByProcClass
|
||||
in_scope = true
|
||||
method_proc = proc { in_scope }
|
||||
|
||||
define_method(:proc_test, &method_proc)
|
||||
end
|
||||
|
||||
o = DefineMethodByProcClass.new
|
||||
o.proc_test.should be_true
|
||||
end
|
||||
|
||||
it "accepts a String method name" do
|
||||
klass = Class.new do
|
||||
define_method("string_test") do
|
||||
"string_test result"
|
||||
end
|
||||
end
|
||||
|
||||
klass.new.string_test.should == "string_test result"
|
||||
end
|
||||
|
||||
it "is private" do
|
||||
Module.should have_private_instance_method(:define_method)
|
||||
end
|
||||
|
||||
it "returns its symbol" do
|
||||
class DefineMethodSpecClass
|
||||
method = define_method("return_test") { true }
|
||||
method.should == :return_test
|
||||
end
|
||||
end
|
||||
|
||||
it "allows an UnboundMethod from a module to be defined on a class" do
|
||||
klass = Class.new {
|
||||
define_method :bar, ModuleSpecs::UnboundMethodTest.instance_method(:foo)
|
||||
}
|
||||
klass.new.should respond_to(:bar)
|
||||
end
|
||||
|
||||
it "allows an UnboundMethod from a parent class to be defined on a child class" do
|
||||
parent = Class.new { define_method(:foo) { :bar } }
|
||||
child = Class.new(parent) {
|
||||
define_method :baz, parent.instance_method(:foo)
|
||||
}
|
||||
child.new.should respond_to(:baz)
|
||||
end
|
||||
|
||||
it "allows an UnboundMethod from a module to be defined on another unrelated module" do
|
||||
mod = Module.new {
|
||||
define_method :bar, ModuleSpecs::UnboundMethodTest.instance_method(:foo)
|
||||
}
|
||||
klass = Class.new { include mod }
|
||||
klass.new.should respond_to(:bar)
|
||||
end
|
||||
|
||||
it "raises a TypeError when an UnboundMethod from a child class is defined on a parent class" do
|
||||
lambda {
|
||||
ParentClass = Class.new { define_method(:foo) { :bar } }
|
||||
ChildClass = Class.new(ParentClass) { define_method(:foo) { :baz } }
|
||||
ParentClass.send :define_method, :foo, ChildClass.instance_method(:foo)
|
||||
}.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "raises a TypeError when an UnboundMethod from one class is defined on an unrelated class" do
|
||||
lambda {
|
||||
DestinationClass = Class.new {
|
||||
define_method :bar, ModuleSpecs::InstanceMeth.instance_method(:foo)
|
||||
}
|
||||
}.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
|
||||
describe "Module#define_method" do
|
||||
describe "passed { } creates a method that" do
|
||||
before :each do
|
||||
@klass = Class.new do
|
||||
define_method(:m) { :called }
|
||||
end
|
||||
end
|
||||
|
||||
it "returns the value computed by the block when passed zero arguments" do
|
||||
@klass.new.m().should == :called
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when passed one argument" do
|
||||
lambda { @klass.new.m 1 }.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when passed two arguments" do
|
||||
lambda { @klass.new.m 1, 2 }.should raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
describe "passed { || } creates a method that" do
|
||||
before :each do
|
||||
@klass = Class.new do
|
||||
define_method(:m) { || :called }
|
||||
end
|
||||
end
|
||||
|
||||
it "returns the value computed by the block when passed zero arguments" do
|
||||
@klass.new.m().should == :called
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when passed one argument" do
|
||||
lambda { @klass.new.m 1 }.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when passed two arguments" do
|
||||
lambda { @klass.new.m 1, 2 }.should raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
describe "passed { |a| } creates a method that" do
|
||||
before :each do
|
||||
@klass = Class.new do
|
||||
define_method(:m) { |a| a }
|
||||
end
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when passed zero arguments" do
|
||||
lambda { @klass.new.m }.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when passed zero arguments and a block" do
|
||||
lambda { @klass.new.m { :computed } }.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when passed two arguments" do
|
||||
lambda { @klass.new.m 1, 2 }.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "receives the value passed as the argument when passed one argument" do
|
||||
@klass.new.m(1).should == 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "passed { |*a| } creates a method that" do
|
||||
before :each do
|
||||
@klass = Class.new do
|
||||
define_method(:m) { |*a| a }
|
||||
end
|
||||
end
|
||||
|
||||
it "receives an empty array as the argument when passed zero arguments" do
|
||||
@klass.new.m().should == []
|
||||
end
|
||||
|
||||
it "receives the value in an array when passed one argument" do
|
||||
@klass.new.m(1).should == [1]
|
||||
end
|
||||
|
||||
it "receives the values in an array when passed two arguments" do
|
||||
@klass.new.m(1, 2).should == [1, 2]
|
||||
end
|
||||
end
|
||||
|
||||
describe "passed { |a, *b| } creates a method that" do
|
||||
before :each do
|
||||
@klass = Class.new do
|
||||
define_method(:m) { |a, *b| return a, b }
|
||||
end
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when passed zero arguments" do
|
||||
lambda { @klass.new.m }.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "returns the value computed by the block when passed one argument" do
|
||||
@klass.new.m(1).should == [1, []]
|
||||
end
|
||||
|
||||
it "returns the value computed by the block when passed two arguments" do
|
||||
@klass.new.m(1, 2).should == [1, [2]]
|
||||
end
|
||||
|
||||
it "returns the value computed by the block when passed three arguments" do
|
||||
@klass.new.m(1, 2, 3).should == [1, [2, 3]]
|
||||
end
|
||||
end
|
||||
|
||||
describe "passed { |a, b| } creates a method that" do
|
||||
before :each do
|
||||
@klass = Class.new do
|
||||
define_method(:m) { |a, b| return a, b }
|
||||
end
|
||||
end
|
||||
|
||||
it "returns the value computed by the block when passed two arguments" do
|
||||
@klass.new.m(1, 2).should == [1, 2]
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when passed zero arguments" do
|
||||
lambda { @klass.new.m }.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when passed one argument" do
|
||||
lambda { @klass.new.m 1 }.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when passed one argument and a block" do
|
||||
lambda { @klass.new.m(1) { } }.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when passed three arguments" do
|
||||
lambda { @klass.new.m 1, 2, 3 }.should raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
describe "passed { |a, b, *c| } creates a method that" do
|
||||
before :each do
|
||||
@klass = Class.new do
|
||||
define_method(:m) { |a, b, *c| return a, b, c }
|
||||
end
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when passed zero arguments" do
|
||||
lambda { @klass.new.m }.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when passed one argument" do
|
||||
lambda { @klass.new.m 1 }.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when passed one argument and a block" do
|
||||
lambda { @klass.new.m(1) { } }.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "receives an empty array as the third argument when passed two arguments" do
|
||||
@klass.new.m(1, 2).should == [1, 2, []]
|
||||
end
|
||||
|
||||
it "receives the third argument in an array when passed three arguments" do
|
||||
@klass.new.m(1, 2, 3).should == [1, 2, [3]]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "Method#define_method when passed a Method object" do
|
||||
before :each do
|
||||
@klass = Class.new do
|
||||
def m(a, b, *c)
|
||||
:m
|
||||
end
|
||||
end
|
||||
|
||||
@obj = @klass.new
|
||||
m = @obj.method :m
|
||||
|
||||
@klass.class_exec do
|
||||
define_method :n, m
|
||||
end
|
||||
end
|
||||
|
||||
it "defines a method with the same #arity as the original" do
|
||||
@obj.method(:n).arity.should == @obj.method(:m).arity
|
||||
end
|
||||
|
||||
it "defines a method with the same #parameters as the original" do
|
||||
@obj.method(:n).parameters.should == @obj.method(:m).parameters
|
||||
end
|
||||
end
|
||||
|
||||
describe "Method#define_method when passed an UnboundMethod object" do
|
||||
before :each do
|
||||
@klass = Class.new do
|
||||
def m(a, b, *c)
|
||||
:m
|
||||
end
|
||||
end
|
||||
|
||||
@obj = @klass.new
|
||||
m = @klass.instance_method :m
|
||||
|
||||
@klass.class_exec do
|
||||
define_method :n, m
|
||||
end
|
||||
end
|
||||
|
||||
it "defines a method with the same #arity as the original" do
|
||||
@obj.method(:n).arity.should == @obj.method(:m).arity
|
||||
end
|
||||
|
||||
it "defines a method with the same #parameters as the original" do
|
||||
@obj.method(:n).parameters.should == @obj.method(:m).parameters
|
||||
end
|
||||
end
|
||||
17
spec/ruby/core/module/define_singleton_method_spec.rb
Normal file
17
spec/ruby/core/module/define_singleton_method_spec.rb
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
|
||||
describe "Module#define_singleton_method" do
|
||||
it "defines the given method as an class method with the given name in self" do
|
||||
klass = Module.new do
|
||||
define_singleton_method :a do
|
||||
42
|
||||
end
|
||||
define_singleton_method(:b, lambda {|x| 2*x })
|
||||
end
|
||||
|
||||
klass.a.should == 42
|
||||
klass.b(10).should == 20
|
||||
end
|
||||
|
||||
it "needs to be reviewed for spec completeness"
|
||||
end
|
||||
52
spec/ruby/core/module/deprecate_constant_spec.rb
Normal file
52
spec/ruby/core/module/deprecate_constant_spec.rb
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
|
||||
ruby_version_is "2.3" do
|
||||
describe "Module#deprecate_constant" do
|
||||
before :each do
|
||||
@module = Module.new
|
||||
@value = :value
|
||||
@module::PUBLIC1 = @value
|
||||
@module::PUBLIC2 = @value
|
||||
@module::PRIVATE = @value
|
||||
@module.private_constant :PRIVATE
|
||||
@module.deprecate_constant :PRIVATE
|
||||
@pattern = /deprecated/
|
||||
end
|
||||
|
||||
describe "when accessing the deprecated module" do
|
||||
it "passes the accessing" do
|
||||
@module.deprecate_constant :PUBLIC1
|
||||
|
||||
value = nil
|
||||
lambda {
|
||||
value = @module::PUBLIC1
|
||||
}.should complain(@pattern)
|
||||
value.should equal(@value)
|
||||
|
||||
lambda { @module::PRIVATE }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "warns with a message" do
|
||||
@module.deprecate_constant :PUBLIC1
|
||||
|
||||
lambda { @module::PUBLIC1 }.should complain(@pattern)
|
||||
lambda { @module.const_get :PRIVATE }.should complain(@pattern)
|
||||
end
|
||||
end
|
||||
|
||||
it "accepts multiple symbols and strings as constant names" do
|
||||
@module.deprecate_constant "PUBLIC1", :PUBLIC2
|
||||
|
||||
lambda { @module::PUBLIC1 }.should complain(@pattern)
|
||||
lambda { @module::PUBLIC2 }.should complain(@pattern)
|
||||
end
|
||||
|
||||
it "returns self" do
|
||||
@module.deprecate_constant(:PUBLIC1).should equal(@module)
|
||||
end
|
||||
|
||||
it "raises a NameError when given an undefined name" do
|
||||
lambda { @module.deprecate_constant :UNDEFINED }.should raise_error(NameError)
|
||||
end
|
||||
end
|
||||
end
|
||||
7
spec/ruby/core/module/eql_spec.rb
Normal file
7
spec/ruby/core/module/eql_spec.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
require File.expand_path('../shared/equal_value', __FILE__)
|
||||
|
||||
describe "Module#eql?" do
|
||||
it_behaves_like(:module_equal, :eql?)
|
||||
end
|
||||
7
spec/ruby/core/module/equal_spec.rb
Normal file
7
spec/ruby/core/module/equal_spec.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
require File.expand_path('../shared/equal_value', __FILE__)
|
||||
|
||||
describe "Module#equal?" do
|
||||
it_behaves_like(:module_equal, :equal?)
|
||||
end
|
||||
7
spec/ruby/core/module/equal_value_spec.rb
Normal file
7
spec/ruby/core/module/equal_value_spec.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
require File.expand_path('../shared/equal_value', __FILE__)
|
||||
|
||||
describe "Module#==" do
|
||||
it_behaves_like(:module_equal, :==)
|
||||
end
|
||||
68
spec/ruby/core/module/extend_object_spec.rb
Normal file
68
spec/ruby/core/module/extend_object_spec.rb
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#extend_object" do
|
||||
before :each do
|
||||
ScratchPad.clear
|
||||
end
|
||||
|
||||
it "is a private method" do
|
||||
Module.should have_private_instance_method(:extend_object)
|
||||
end
|
||||
|
||||
describe "on Class" do
|
||||
it "is undefined" do
|
||||
Class.should_not have_private_instance_method(:extend_object, true)
|
||||
end
|
||||
|
||||
it "raises a TypeError if calling after rebinded to Class" do
|
||||
lambda {
|
||||
Module.instance_method(:extend_object).bind(Class.new).call Object.new
|
||||
}.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
|
||||
it "is called when #extend is called on an object" do
|
||||
ModuleSpecs::ExtendObject.should_receive(:extend_object)
|
||||
obj = mock("extended object")
|
||||
obj.extend ModuleSpecs::ExtendObject
|
||||
end
|
||||
|
||||
it "extends the given object with its constants and methods by default" do
|
||||
obj = mock("extended direct")
|
||||
ModuleSpecs::ExtendObject.send :extend_object, obj
|
||||
|
||||
obj.test_method.should == "hello test"
|
||||
obj.singleton_class.const_get(:C).should == :test
|
||||
end
|
||||
|
||||
it "is called even when private" do
|
||||
obj = mock("extended private")
|
||||
obj.extend ModuleSpecs::ExtendObjectPrivate
|
||||
ScratchPad.recorded.should == :extended
|
||||
end
|
||||
|
||||
it "does not copy own tainted status to the given object" do
|
||||
other = Object.new
|
||||
Module.new.taint.send :extend_object, other
|
||||
other.tainted?.should be_false
|
||||
end
|
||||
|
||||
it "does not copy own untrusted status to the given object" do
|
||||
other = Object.new
|
||||
Module.new.untrust.send :extend_object, other
|
||||
other.untrusted?.should be_false
|
||||
end
|
||||
|
||||
describe "when given a frozen object" do
|
||||
before :each do
|
||||
@receiver = Module.new
|
||||
@object = Object.new.freeze
|
||||
end
|
||||
|
||||
it "raises a RuntimeError before extending the object" do
|
||||
lambda { @receiver.send(:extend_object, @object) }.should raise_error(RuntimeError)
|
||||
@object.should_not be_kind_of(@receiver)
|
||||
end
|
||||
end
|
||||
end
|
||||
44
spec/ruby/core/module/extended_spec.rb
Normal file
44
spec/ruby/core/module/extended_spec.rb
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#extended" do
|
||||
it "is called when an object gets extended with self" do
|
||||
begin
|
||||
m = Module.new do
|
||||
def self.extended(o)
|
||||
$extended_object = o
|
||||
end
|
||||
end
|
||||
|
||||
(o = mock('x')).extend(m)
|
||||
|
||||
$extended_object.should == o
|
||||
ensure
|
||||
$extended_object = nil
|
||||
end
|
||||
end
|
||||
|
||||
it "is called after Module#extend_object" do
|
||||
begin
|
||||
m = Module.new do
|
||||
def self.extend_object(o)
|
||||
$extended_object = nil
|
||||
end
|
||||
|
||||
def self.extended(o)
|
||||
$extended_object = o
|
||||
end
|
||||
end
|
||||
|
||||
(o = mock('x')).extend(m)
|
||||
|
||||
$extended_object.should == o
|
||||
ensure
|
||||
$extended_object = nil
|
||||
end
|
||||
end
|
||||
|
||||
it "is private in its default implementation" do
|
||||
Module.new.private_methods.should include(:extended)
|
||||
end
|
||||
end
|
||||
1
spec/ruby/core/module/fixtures/autoload.rb
Normal file
1
spec/ruby/core/module/fixtures/autoload.rb
Normal file
|
|
@ -0,0 +1 @@
|
|||
$m.const_set(:AAA, "test") unless $m.nil?
|
||||
11
spec/ruby/core/module/fixtures/autoload_abc.rb
Normal file
11
spec/ruby/core/module/fixtures/autoload_abc.rb
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
module ModuleSpecs::Autoload::FromThread
|
||||
module A
|
||||
class B
|
||||
class C
|
||||
def self.foo
|
||||
:foo
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
11
spec/ruby/core/module/fixtures/autoload_c.rb
Normal file
11
spec/ruby/core/module/fixtures/autoload_c.rb
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
module ModuleSpecs::Autoload
|
||||
class DynClass
|
||||
class C
|
||||
def loaded
|
||||
:dynclass_c
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ScratchPad.record :loaded
|
||||
9
spec/ruby/core/module/fixtures/autoload_concur.rb
Normal file
9
spec/ruby/core/module/fixtures/autoload_concur.rb
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
ScratchPad.recorded << :con_pre
|
||||
Thread.current[:in_autoload_rb] = true
|
||||
sleep 0.1
|
||||
|
||||
module ModuleSpecs::Autoload
|
||||
Concur = 1
|
||||
end
|
||||
|
||||
ScratchPad.recorded << :con_post
|
||||
11
spec/ruby/core/module/fixtures/autoload_d.rb
Normal file
11
spec/ruby/core/module/fixtures/autoload_d.rb
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
module ModuleSpecs::Autoload
|
||||
module DynModule
|
||||
class D
|
||||
def loaded
|
||||
:dynmodule_d
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ScratchPad.record :loaded
|
||||
7
spec/ruby/core/module/fixtures/autoload_e.rb
Normal file
7
spec/ruby/core/module/fixtures/autoload_e.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
module ModuleSpecs::Autoload
|
||||
class E
|
||||
def loaded
|
||||
:autoload_e
|
||||
end
|
||||
end
|
||||
end
|
||||
1
spec/ruby/core/module/fixtures/autoload_empty.rb
Normal file
1
spec/ruby/core/module/fixtures/autoload_empty.rb
Normal file
|
|
@ -0,0 +1 @@
|
|||
# This file is left empty on purpose
|
||||
16
spec/ruby/core/module/fixtures/autoload_ex1.rb
Normal file
16
spec/ruby/core/module/fixtures/autoload_ex1.rb
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
class ModuleSpecs::Autoload::EX1 < Exception
|
||||
def self.trample1
|
||||
1.times { return }
|
||||
end
|
||||
|
||||
def self.trample2
|
||||
begin
|
||||
raise "hello"
|
||||
rescue
|
||||
end
|
||||
end
|
||||
|
||||
trample1
|
||||
trample2
|
||||
end
|
||||
7
spec/ruby/core/module/fixtures/autoload_f.rb
Normal file
7
spec/ruby/core/module/fixtures/autoload_f.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
module ModuleSpecs::Autoload
|
||||
module F
|
||||
def self.loaded
|
||||
:autoload_f
|
||||
end
|
||||
end
|
||||
end
|
||||
7
spec/ruby/core/module/fixtures/autoload_g.rb
Normal file
7
spec/ruby/core/module/fixtures/autoload_g.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
module ModuleSpecs::Autoload
|
||||
class G
|
||||
def loaded
|
||||
:autoload_g
|
||||
end
|
||||
end
|
||||
end
|
||||
7
spec/ruby/core/module/fixtures/autoload_h.rb
Normal file
7
spec/ruby/core/module/fixtures/autoload_h.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
module ModuleSpecs::Autoload
|
||||
module H
|
||||
def loaded
|
||||
:autoload_h
|
||||
end
|
||||
end
|
||||
end
|
||||
5
spec/ruby/core/module/fixtures/autoload_i.rb
Normal file
5
spec/ruby/core/module/fixtures/autoload_i.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
module ModuleSpecs::Autoload
|
||||
I = :autoloaded
|
||||
end
|
||||
|
||||
ScratchPad.record :loaded
|
||||
3
spec/ruby/core/module/fixtures/autoload_j.rb
Normal file
3
spec/ruby/core/module/fixtures/autoload_j.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
module ModuleSpecs::Autoload
|
||||
J = :autoload_j
|
||||
end
|
||||
7
spec/ruby/core/module/fixtures/autoload_k.rb
Normal file
7
spec/ruby/core/module/fixtures/autoload_k.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
module ModuleSpecs::Autoload
|
||||
class KHash < Hash
|
||||
K = :autoload_k
|
||||
end
|
||||
end
|
||||
|
||||
ScratchPad.record :loaded
|
||||
4
spec/ruby/core/module/fixtures/autoload_lm.rb
Normal file
4
spec/ruby/core/module/fixtures/autoload_lm.rb
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
module ModuleSpecs::Autoload
|
||||
L = :autoload_l
|
||||
M = :autoload_m
|
||||
end
|
||||
1
spec/ruby/core/module/fixtures/autoload_o.rb
Normal file
1
spec/ruby/core/module/fixtures/autoload_o.rb
Normal file
|
|
@ -0,0 +1 @@
|
|||
# does not define ModuleSpecs::Autoload::O
|
||||
4
spec/ruby/core/module/fixtures/autoload_r.rb
Normal file
4
spec/ruby/core/module/fixtures/autoload_r.rb
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
module ModuleSpecs::Autoload
|
||||
class R
|
||||
end
|
||||
end
|
||||
5
spec/ruby/core/module/fixtures/autoload_s.rb
Normal file
5
spec/ruby/core/module/fixtures/autoload_s.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
module ModuleSpecs::Autoload
|
||||
S = :autoload_s
|
||||
end
|
||||
|
||||
ScratchPad.record :loaded
|
||||
8
spec/ruby/core/module/fixtures/autoload_scope.rb
Normal file
8
spec/ruby/core/module/fixtures/autoload_scope.rb
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
module ModuleSpecs
|
||||
module Autoload
|
||||
class PP
|
||||
class QQ
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
11
spec/ruby/core/module/fixtures/autoload_subclass.rb
Normal file
11
spec/ruby/core/module/fixtures/autoload_subclass.rb
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
class YY
|
||||
end
|
||||
|
||||
module ModuleSpecs
|
||||
module Autoload
|
||||
module XX
|
||||
class YY < YY
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
3
spec/ruby/core/module/fixtures/autoload_t.rb
Normal file
3
spec/ruby/core/module/fixtures/autoload_t.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
module ModuleSpecs::Autoload::S
|
||||
T = :autoload_t
|
||||
end
|
||||
7
spec/ruby/core/module/fixtures/autoload_v.rb
Normal file
7
spec/ruby/core/module/fixtures/autoload_v.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
module ModuleSpecs::Autoload::U
|
||||
class V
|
||||
def self.get_value
|
||||
:autoload_uvx
|
||||
end
|
||||
end
|
||||
end
|
||||
2
spec/ruby/core/module/fixtures/autoload_w.rb
Normal file
2
spec/ruby/core/module/fixtures/autoload_w.rb
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
# Fails to define ModuleSpecs::Autoload::W::Y
|
||||
ScratchPad.record :loaded
|
||||
1
spec/ruby/core/module/fixtures/autoload_w2.rb
Normal file
1
spec/ruby/core/module/fixtures/autoload_w2.rb
Normal file
|
|
@ -0,0 +1 @@
|
|||
ScratchPad.record :loaded
|
||||
3
spec/ruby/core/module/fixtures/autoload_x.rb
Normal file
3
spec/ruby/core/module/fixtures/autoload_x.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
module ModuleSpecs::Autoload
|
||||
X = :x
|
||||
end
|
||||
5
spec/ruby/core/module/fixtures/autoload_z.rb
Normal file
5
spec/ruby/core/module/fixtures/autoload_z.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
class ModuleSpecs::Autoload::YY
|
||||
end
|
||||
|
||||
class ModuleSpecs::Autoload::Z < ModuleSpecs::Autoload::YY
|
||||
end
|
||||
605
spec/ruby/core/module/fixtures/classes.rb
Normal file
605
spec/ruby/core/module/fixtures/classes.rb
Normal file
|
|
@ -0,0 +1,605 @@
|
|||
module ModuleSpecs
|
||||
def self.without_test_modules(modules)
|
||||
ignore = %w[MSpecRSpecAdapter PP::ObjectMixin ModuleSpecs::IncludedInObject MainSpecs::Module ConstantSpecs::ModuleA]
|
||||
modules.reject { |k| ignore.include?(k.name) }
|
||||
end
|
||||
|
||||
CONST = :plain_constant
|
||||
|
||||
module PrivConstModule
|
||||
PRIVATE_CONSTANT = 1
|
||||
private_constant :PRIVATE_CONSTANT
|
||||
PUBLIC_CONSTANT = 2
|
||||
end
|
||||
|
||||
class Subclass < Module
|
||||
end
|
||||
|
||||
class SubclassSpec
|
||||
end
|
||||
|
||||
class RemoveClassVariable
|
||||
end
|
||||
|
||||
module LookupModInMod
|
||||
INCS = :ethereal
|
||||
end
|
||||
|
||||
module LookupMod
|
||||
include LookupModInMod
|
||||
|
||||
MODS = :rockers
|
||||
end
|
||||
|
||||
class Lookup
|
||||
include LookupMod
|
||||
LOOKIE = :lookie
|
||||
end
|
||||
|
||||
class LookupChild < Lookup
|
||||
end
|
||||
|
||||
class Parent
|
||||
# For private_class_method spec
|
||||
def self.private_method; end
|
||||
private_class_method :private_method
|
||||
|
||||
def undefed_method() end
|
||||
undef_method :undefed_method
|
||||
|
||||
def parent_method; end
|
||||
def another_parent_method; end
|
||||
|
||||
# For public_class_method spec
|
||||
private
|
||||
def self.public_method; end
|
||||
public_class_method :public_method
|
||||
|
||||
public
|
||||
def public_parent() end
|
||||
|
||||
protected
|
||||
def protected_parent() end
|
||||
|
||||
private
|
||||
def private_parent() end
|
||||
end
|
||||
|
||||
module Basic
|
||||
def public_module() end
|
||||
|
||||
protected
|
||||
def protected_module() end
|
||||
|
||||
private
|
||||
def private_module() end
|
||||
end
|
||||
|
||||
module Super
|
||||
include Basic
|
||||
|
||||
def public_super_module() end
|
||||
|
||||
protected
|
||||
def protected_super_module() end
|
||||
|
||||
private
|
||||
def private_super_module() end
|
||||
|
||||
def super_included_method; end
|
||||
|
||||
class SuperChild
|
||||
end
|
||||
end
|
||||
|
||||
module Internal
|
||||
end
|
||||
|
||||
class Child < Parent
|
||||
include Super
|
||||
|
||||
class << self
|
||||
include Internal
|
||||
end
|
||||
attr_accessor :accessor_method
|
||||
|
||||
def public_child() end
|
||||
|
||||
undef_method :parent_method
|
||||
undef_method :another_parent_method
|
||||
|
||||
protected
|
||||
def protected_child() end
|
||||
|
||||
private
|
||||
def private_child() end
|
||||
end
|
||||
|
||||
class Grandchild < Child
|
||||
undef_method :super_included_method
|
||||
end
|
||||
|
||||
class Child2 < Parent
|
||||
attr_reader :foo
|
||||
end
|
||||
|
||||
# Be careful touching the Counts* classes as there used for testing
|
||||
# private_instance_methods, public_instance_methods, etc. So adding, removing
|
||||
# a method will break those tests.
|
||||
module CountsMixin
|
||||
def public_3; end
|
||||
public :public_3
|
||||
|
||||
def private_3; end
|
||||
private :private_3
|
||||
|
||||
def protected_3; end
|
||||
protected :protected_3
|
||||
end
|
||||
|
||||
class CountsParent
|
||||
include CountsMixin
|
||||
|
||||
def public_2; end
|
||||
|
||||
private
|
||||
def private_2; end
|
||||
|
||||
protected
|
||||
def protected_2; end
|
||||
end
|
||||
|
||||
class CountsChild < CountsParent
|
||||
def public_1; end
|
||||
|
||||
private
|
||||
def private_1; end
|
||||
|
||||
protected
|
||||
def protected_1; end
|
||||
end
|
||||
|
||||
module AddConstant
|
||||
end
|
||||
|
||||
module A
|
||||
CONSTANT_A = :a
|
||||
OVERRIDE = :a
|
||||
def ma(); :a; end
|
||||
def self.cma(); :a; end
|
||||
end
|
||||
|
||||
module B
|
||||
CONSTANT_B = :b
|
||||
OVERRIDE = :b
|
||||
include A
|
||||
def mb(); :b; end
|
||||
def self.cmb(); :b; end
|
||||
end
|
||||
|
||||
class C
|
||||
OVERRIDE = :c
|
||||
include B
|
||||
end
|
||||
|
||||
module Z
|
||||
MODULE_SPEC_TOPLEVEL_CONSTANT = 1
|
||||
end
|
||||
|
||||
module Alias
|
||||
def report() :report end
|
||||
alias publish report
|
||||
end
|
||||
|
||||
class Allonym
|
||||
include ModuleSpecs::Alias
|
||||
end
|
||||
|
||||
class Aliasing
|
||||
def self.make_alias(*a)
|
||||
alias_method(*a)
|
||||
end
|
||||
|
||||
def public_one; 1; end
|
||||
|
||||
def public_two(n); n * 2; end
|
||||
|
||||
private
|
||||
def private_one; 1; end
|
||||
|
||||
protected
|
||||
def protected_one; 1; end
|
||||
end
|
||||
|
||||
class AliasingSubclass < Aliasing
|
||||
end
|
||||
|
||||
module AliasingSuper
|
||||
|
||||
module Parent
|
||||
def super_call(arg)
|
||||
arg
|
||||
end
|
||||
end
|
||||
|
||||
module Child
|
||||
include Parent
|
||||
def super_call(arg)
|
||||
super(arg)
|
||||
end
|
||||
end
|
||||
|
||||
class Target
|
||||
include Child
|
||||
alias_method :alias_super_call, :super_call
|
||||
alias_method :super_call, :alias_super_call
|
||||
end
|
||||
|
||||
class RedefineAfterAlias
|
||||
include Parent
|
||||
|
||||
def super_call(arg)
|
||||
super(arg)
|
||||
end
|
||||
|
||||
alias_method :alias_super_call, :super_call
|
||||
|
||||
def super_call(arg)
|
||||
:wrong
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
module ReopeningModule
|
||||
def foo; true; end
|
||||
module_function :foo
|
||||
private :foo
|
||||
end
|
||||
|
||||
# Yes, we want to re-open the module
|
||||
module ReopeningModule
|
||||
alias :foo2 :foo
|
||||
module_function :foo2
|
||||
end
|
||||
|
||||
module Nesting
|
||||
@tests = {}
|
||||
def self.[](name); @tests[name]; end
|
||||
def self.[]=(name, val); @tests[name] = val; end
|
||||
def self.meta; class << self; self; end; end
|
||||
|
||||
Nesting[:basic] = Module.nesting
|
||||
|
||||
module ::ModuleSpecs
|
||||
Nesting[:open_first_level] = Module.nesting
|
||||
end
|
||||
|
||||
class << self
|
||||
Nesting[:open_meta] = Module.nesting
|
||||
end
|
||||
|
||||
def self.called_from_module_method
|
||||
Module.nesting
|
||||
end
|
||||
|
||||
class NestedClass
|
||||
Nesting[:nest_class] = Module.nesting
|
||||
|
||||
def self.called_from_class_method
|
||||
Module.nesting
|
||||
end
|
||||
|
||||
def called_from_inst_method
|
||||
Module.nesting
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Nesting[:first_level] = Module.nesting
|
||||
|
||||
module InstanceMethMod
|
||||
def bar(); :bar; end
|
||||
end
|
||||
|
||||
class InstanceMeth
|
||||
include InstanceMethMod
|
||||
def foo(); :foo; end
|
||||
end
|
||||
|
||||
class InstanceMethChild < InstanceMeth
|
||||
end
|
||||
|
||||
module ClassVars
|
||||
class A
|
||||
@@a_cvar = :a_cvar
|
||||
end
|
||||
|
||||
module M
|
||||
@@m_cvar = :m_cvar
|
||||
end
|
||||
|
||||
class B < A
|
||||
include M
|
||||
|
||||
@@b_cvar = :b_cvar
|
||||
end
|
||||
end
|
||||
|
||||
class CVars
|
||||
@@cls = :class
|
||||
|
||||
# Singleton class lexical scopes are ignored for class variables
|
||||
class << self
|
||||
def cls
|
||||
# This looks in the parent lexical scope, class CVars
|
||||
@@cls
|
||||
end
|
||||
# This actually adds it to the parent lexical scope, class CVars
|
||||
@@meta = :metainfo
|
||||
end
|
||||
|
||||
def self.meta
|
||||
@@meta
|
||||
end
|
||||
|
||||
def meta
|
||||
@@meta
|
||||
end
|
||||
end
|
||||
|
||||
module MVars
|
||||
@@mvar = :mvar
|
||||
end
|
||||
|
||||
class SubModule < Module
|
||||
attr_reader :special
|
||||
def initialize
|
||||
@special = 10
|
||||
end
|
||||
end
|
||||
|
||||
module MA; end
|
||||
module MB
|
||||
include MA
|
||||
end
|
||||
module MC; end
|
||||
|
||||
class MultipleIncludes
|
||||
include MB
|
||||
end
|
||||
|
||||
# empty modules
|
||||
module M1; end
|
||||
module M2; end
|
||||
|
||||
module Autoload
|
||||
def self.use_ex1
|
||||
begin
|
||||
begin
|
||||
raise "test exception"
|
||||
rescue ModuleSpecs::Autoload::EX1
|
||||
end
|
||||
rescue RuntimeError
|
||||
return :good
|
||||
end
|
||||
end
|
||||
|
||||
module FromThread
|
||||
module A
|
||||
autoload :B, fixture(__FILE__, "autoload_empty.rb")
|
||||
|
||||
class B
|
||||
autoload :C, fixture(__FILE__, "autoload_abc.rb")
|
||||
|
||||
def self.foo
|
||||
C.foo
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class D < A::B; end
|
||||
end
|
||||
end
|
||||
|
||||
# This class isn't inherited from or included in anywhere.
|
||||
# It exists to test the constant scoping rules.
|
||||
class Detached
|
||||
DETACHED_CONSTANT = :d
|
||||
end
|
||||
|
||||
class ParentPrivateMethodRedef
|
||||
private
|
||||
def private_method_redefined
|
||||
:before_redefinition
|
||||
end
|
||||
end
|
||||
|
||||
class ChildPrivateMethodMadePublic < ParentPrivateMethodRedef
|
||||
public :private_method_redefined
|
||||
end
|
||||
|
||||
class ParentPrivateMethodRedef
|
||||
def private_method_redefined
|
||||
:after_redefinition
|
||||
end
|
||||
end
|
||||
|
||||
module CyclicAppendA
|
||||
end
|
||||
|
||||
module CyclicAppendB
|
||||
include CyclicAppendA
|
||||
end
|
||||
|
||||
module CyclicPrepend
|
||||
end
|
||||
|
||||
module ExtendObject
|
||||
C = :test
|
||||
def test_method
|
||||
"hello test"
|
||||
end
|
||||
end
|
||||
|
||||
module ExtendObjectPrivate
|
||||
class << self
|
||||
def extend_object(obj)
|
||||
ScratchPad.record :extended
|
||||
end
|
||||
private :extend_object
|
||||
end
|
||||
end
|
||||
|
||||
class CyclicBarrier
|
||||
def initialize(count = 1)
|
||||
@count = count
|
||||
@state = 0
|
||||
@mutex = Mutex.new
|
||||
@cond = ConditionVariable.new
|
||||
end
|
||||
|
||||
def await
|
||||
@mutex.synchronize do
|
||||
@state += 1
|
||||
if @state >= @count
|
||||
@state = 0
|
||||
@cond.broadcast
|
||||
true
|
||||
else
|
||||
@cond.wait @mutex
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def enabled?
|
||||
@mutex.synchronize { @count != -1 }
|
||||
end
|
||||
|
||||
def disable!
|
||||
@mutex.synchronize do
|
||||
@count = -1
|
||||
@cond.broadcast
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ThreadSafeCounter
|
||||
def initialize(value = 0)
|
||||
@value = 0
|
||||
@mutex = Mutex.new
|
||||
end
|
||||
|
||||
def get
|
||||
@mutex.synchronize { @value }
|
||||
end
|
||||
|
||||
def increment_and_get
|
||||
@mutex.synchronize do
|
||||
prev_value = @value
|
||||
@value += 1
|
||||
prev_value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module ShadowingOuter
|
||||
module M
|
||||
SHADOW = 123
|
||||
end
|
||||
|
||||
module N
|
||||
SHADOW = 456
|
||||
end
|
||||
end
|
||||
|
||||
module UnboundMethodTest
|
||||
def foo
|
||||
'bar'
|
||||
end
|
||||
end
|
||||
|
||||
module ClassEvalTest
|
||||
def self.get_constant_from_scope
|
||||
module_eval("Lookup")
|
||||
end
|
||||
|
||||
def self.get_constant_from_scope_with_send(method)
|
||||
send(method, "Lookup")
|
||||
end
|
||||
end
|
||||
|
||||
class RecordIncludedModules
|
||||
def self.inherited(base)
|
||||
ScratchPad.record base
|
||||
end
|
||||
end
|
||||
|
||||
module SingletonOnModuleCase
|
||||
module Foo
|
||||
class << Foo
|
||||
def included(base)
|
||||
base.included_called
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Bar
|
||||
@included_called = false
|
||||
|
||||
class << self
|
||||
def included_called
|
||||
@included_called = true
|
||||
end
|
||||
|
||||
def included_called?
|
||||
@included_called
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module CaseCompareOnSingleton
|
||||
def self.===(*)
|
||||
raise 'method contents are irrelevant to test'
|
||||
end
|
||||
end
|
||||
|
||||
m = Module.new do
|
||||
def foo
|
||||
end
|
||||
private :foo
|
||||
end
|
||||
EmptyFooMethod = m.instance_method(:foo)
|
||||
end
|
||||
|
||||
class Object
|
||||
def module_specs_public_method_on_object; end
|
||||
|
||||
def module_specs_private_method_on_object; end
|
||||
private :module_specs_private_method_on_object
|
||||
|
||||
def module_specs_protected_method_on_object; end
|
||||
protected :module_specs_private_method_on_object
|
||||
|
||||
def module_specs_private_method_on_object_for_kernel_public; end
|
||||
private :module_specs_private_method_on_object_for_kernel_public
|
||||
|
||||
def module_specs_public_method_on_object_for_kernel_protected; end
|
||||
def module_specs_public_method_on_object_for_kernel_private; end
|
||||
end
|
||||
|
||||
module Kernel
|
||||
def module_specs_public_method_on_kernel; end
|
||||
|
||||
alias_method :module_specs_alias_on_kernel, :module_specs_public_method_on_object
|
||||
|
||||
public :module_specs_private_method_on_object_for_kernel_public
|
||||
protected :module_specs_public_method_on_object_for_kernel_protected
|
||||
private :module_specs_public_method_on_object_for_kernel_private
|
||||
end
|
||||
|
||||
ModuleSpecs::Nesting[:root_level] = Module.nesting
|
||||
5
spec/ruby/core/module/fixtures/constant_unicode.rb
Normal file
5
spec/ruby/core/module/fixtures/constant_unicode.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# encoding: utf-8
|
||||
|
||||
module ConstantUnicodeSpecs
|
||||
CS_CONSTλ = :const_unicode
|
||||
end
|
||||
4
spec/ruby/core/module/fixtures/module.rb
Normal file
4
spec/ruby/core/module/fixtures/module.rb
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
module ModuleSpecs
|
||||
module Anonymous
|
||||
end
|
||||
end
|
||||
10
spec/ruby/core/module/fixtures/name.rb
Normal file
10
spec/ruby/core/module/fixtures/name.rb
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
module ModuleSpecs
|
||||
class NameEncoding
|
||||
class Cß
|
||||
end
|
||||
def name
|
||||
Cß.name
|
||||
end
|
||||
end
|
||||
end
|
||||
9
spec/ruby/core/module/fixtures/path1/load_path.rb
Normal file
9
spec/ruby/core/module/fixtures/path1/load_path.rb
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
$LOAD_PATH.unshift(File.expand_path('../../path2', __FILE__))
|
||||
|
||||
module ModuleSpecs::Autoload
|
||||
module LoadPath
|
||||
def self.loaded
|
||||
:autoload_load_path
|
||||
end
|
||||
end
|
||||
end
|
||||
1
spec/ruby/core/module/fixtures/path2/load_path.rb
Normal file
1
spec/ruby/core/module/fixtures/path2/load_path.rb
Normal file
|
|
@ -0,0 +1 @@
|
|||
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
prev_value = ScratchPad.recorded.increment_and_get
|
||||
eval <<-RUBY_EVAL
|
||||
module Mod#{prev_value}
|
||||
sleep(0.05)
|
||||
def self.foo
|
||||
end
|
||||
end
|
||||
RUBY_EVAL
|
||||
6
spec/ruby/core/module/freeze_spec.rb
Normal file
6
spec/ruby/core/module/freeze_spec.rb
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#freeze" do
|
||||
it "needs to be reviewed for spec completeness"
|
||||
end
|
||||
36
spec/ruby/core/module/gt_spec.rb
Normal file
36
spec/ruby/core/module/gt_spec.rb
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#>" do
|
||||
it "returns false if self is a subclass of or includes the given module" do
|
||||
(ModuleSpecs::Child > ModuleSpecs::Parent).should be_false
|
||||
(ModuleSpecs::Child > ModuleSpecs::Basic).should be_false
|
||||
(ModuleSpecs::Child > ModuleSpecs::Super).should be_false
|
||||
(ModuleSpecs::Super > ModuleSpecs::Basic).should be_false
|
||||
end
|
||||
|
||||
it "returns true if self is a superclass of or included by the given module" do
|
||||
(ModuleSpecs::Parent > ModuleSpecs::Child).should == true
|
||||
(ModuleSpecs::Basic > ModuleSpecs::Child).should == true
|
||||
(ModuleSpecs::Super > ModuleSpecs::Child).should == true
|
||||
(ModuleSpecs::Basic > ModuleSpecs::Super).should == true
|
||||
end
|
||||
|
||||
it "returns false if self is the same as the given module" do
|
||||
(ModuleSpecs::Child > ModuleSpecs::Child).should == false
|
||||
(ModuleSpecs::Parent > ModuleSpecs::Parent).should == false
|
||||
(ModuleSpecs::Basic > ModuleSpecs::Basic).should == false
|
||||
(ModuleSpecs::Super > ModuleSpecs::Super).should == false
|
||||
end
|
||||
|
||||
it "returns nil if self is not related to the given module" do
|
||||
(ModuleSpecs::Parent > ModuleSpecs::Basic).should == nil
|
||||
(ModuleSpecs::Parent > ModuleSpecs::Super).should == nil
|
||||
(ModuleSpecs::Basic > ModuleSpecs::Parent).should == nil
|
||||
(ModuleSpecs::Super > ModuleSpecs::Parent).should == nil
|
||||
end
|
||||
|
||||
it "raises a TypeError if the argument is not a class/module" do
|
||||
lambda { ModuleSpecs::Parent > mock('x') }.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
33
spec/ruby/core/module/gte_spec.rb
Normal file
33
spec/ruby/core/module/gte_spec.rb
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#>=" do
|
||||
it "returns true if self is a superclass of, the same as or included by given module" do
|
||||
(ModuleSpecs::Parent >= ModuleSpecs::Child).should == true
|
||||
(ModuleSpecs::Basic >= ModuleSpecs::Child).should == true
|
||||
(ModuleSpecs::Super >= ModuleSpecs::Child).should == true
|
||||
(ModuleSpecs::Basic >= ModuleSpecs::Super).should == true
|
||||
(ModuleSpecs::Child >= ModuleSpecs::Child).should == true
|
||||
(ModuleSpecs::Parent >= ModuleSpecs::Parent).should == true
|
||||
(ModuleSpecs::Basic >= ModuleSpecs::Basic).should == true
|
||||
(ModuleSpecs::Super >= ModuleSpecs::Super).should == true
|
||||
end
|
||||
|
||||
it "returns nil if self is not related to the given module" do
|
||||
(ModuleSpecs::Parent >= ModuleSpecs::Basic).should == nil
|
||||
(ModuleSpecs::Parent >= ModuleSpecs::Super).should == nil
|
||||
(ModuleSpecs::Basic >= ModuleSpecs::Parent).should == nil
|
||||
(ModuleSpecs::Super >= ModuleSpecs::Parent).should == nil
|
||||
end
|
||||
|
||||
it "returns false if self is a subclass of or includes the given module" do
|
||||
(ModuleSpecs::Child >= ModuleSpecs::Parent).should == false
|
||||
(ModuleSpecs::Child >= ModuleSpecs::Basic).should == false
|
||||
(ModuleSpecs::Child >= ModuleSpecs::Super).should == false
|
||||
(ModuleSpecs::Super >= ModuleSpecs::Basic).should == false
|
||||
end
|
||||
|
||||
it "raises a TypeError if the argument is not a class/module" do
|
||||
lambda { ModuleSpecs::Parent >= mock('x') }.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
270
spec/ruby/core/module/include_spec.rb
Normal file
270
spec/ruby/core/module/include_spec.rb
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#include" do
|
||||
it "is a public method" do
|
||||
Module.should have_public_instance_method(:include, false)
|
||||
end
|
||||
|
||||
it "calls #append_features(self) in reversed order on each module" do
|
||||
$appended_modules = []
|
||||
|
||||
m = Module.new do
|
||||
def self.append_features(mod)
|
||||
$appended_modules << [ self, mod ]
|
||||
end
|
||||
end
|
||||
|
||||
m2 = Module.new do
|
||||
def self.append_features(mod)
|
||||
$appended_modules << [ self, mod ]
|
||||
end
|
||||
end
|
||||
|
||||
m3 = Module.new do
|
||||
def self.append_features(mod)
|
||||
$appended_modules << [ self, mod ]
|
||||
end
|
||||
end
|
||||
|
||||
c = Class.new { include(m, m2, m3) }
|
||||
|
||||
$appended_modules.should == [ [ m3, c], [ m2, c ], [ m, c ] ]
|
||||
end
|
||||
|
||||
it "adds all ancestor modules when a previously included module is included again" do
|
||||
ModuleSpecs::MultipleIncludes.ancestors.should include(ModuleSpecs::MA, ModuleSpecs::MB)
|
||||
ModuleSpecs::MB.include(ModuleSpecs::MC)
|
||||
ModuleSpecs::MultipleIncludes.include(ModuleSpecs::MB)
|
||||
ModuleSpecs::MultipleIncludes.ancestors.should include(ModuleSpecs::MA, ModuleSpecs::MB, ModuleSpecs::MC)
|
||||
end
|
||||
|
||||
it "raises a TypeError when the argument is not a Module" do
|
||||
lambda { ModuleSpecs::Basic.include(Class.new) }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "does not raise a TypeError when the argument is an instance of a subclass of Module" do
|
||||
lambda { ModuleSpecs::SubclassSpec.include(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "imports constants to modules and classes" do
|
||||
ModuleSpecs::A.constants.should include(:CONSTANT_A)
|
||||
ModuleSpecs::B.constants.should include(:CONSTANT_A, :CONSTANT_B)
|
||||
ModuleSpecs::C.constants.should include(:CONSTANT_A, :CONSTANT_B)
|
||||
end
|
||||
|
||||
it "shadows constants from ancestors" do
|
||||
klass = Class.new
|
||||
klass.include ModuleSpecs::ShadowingOuter::M
|
||||
klass::SHADOW.should == 123
|
||||
klass.include ModuleSpecs::ShadowingOuter::N
|
||||
klass::SHADOW.should == 456
|
||||
end
|
||||
|
||||
it "does not override existing constants in modules and classes" do
|
||||
ModuleSpecs::A::OVERRIDE.should == :a
|
||||
ModuleSpecs::B::OVERRIDE.should == :b
|
||||
ModuleSpecs::C::OVERRIDE.should == :c
|
||||
end
|
||||
|
||||
it "imports instance methods to modules and classes" do
|
||||
ModuleSpecs::A.instance_methods.should include(:ma)
|
||||
ModuleSpecs::B.instance_methods.should include(:ma,:mb)
|
||||
ModuleSpecs::C.instance_methods.should include(:ma,:mb)
|
||||
end
|
||||
|
||||
it "does not import methods to modules and classes" do
|
||||
ModuleSpecs::A.methods.include?(:cma).should == true
|
||||
ModuleSpecs::B.methods.include?(:cma).should == false
|
||||
ModuleSpecs::B.methods.include?(:cmb).should == true
|
||||
ModuleSpecs::C.methods.include?(:cma).should == false
|
||||
ModuleSpecs::C.methods.include?(:cmb).should == false
|
||||
end
|
||||
|
||||
it "attaches the module as the caller's immediate ancestor" do
|
||||
module IncludeSpecsTop
|
||||
def value; 5; end
|
||||
end
|
||||
|
||||
module IncludeSpecsMiddle
|
||||
include IncludeSpecsTop
|
||||
def value; 6; end
|
||||
end
|
||||
|
||||
class IncludeSpecsClass
|
||||
include IncludeSpecsMiddle
|
||||
end
|
||||
|
||||
IncludeSpecsClass.new.value.should == 6
|
||||
end
|
||||
|
||||
it "doesn't include module if it is included in a super class" do
|
||||
module ModuleSpecs::M1
|
||||
module M; end
|
||||
class A; include M; end
|
||||
class B < A; include M; end
|
||||
|
||||
all = [A,B,M]
|
||||
|
||||
(B.ancestors & all).should == [B, A, M]
|
||||
end
|
||||
end
|
||||
|
||||
it "recursively includes new mixins" do
|
||||
module ModuleSpecs::M1
|
||||
module U; end
|
||||
module V; end
|
||||
module W; end
|
||||
module X; end
|
||||
module Y; end
|
||||
class A; include X; end;
|
||||
class B < A; include U, V, W; end;
|
||||
|
||||
# update V
|
||||
module V; include X, U, Y; end
|
||||
|
||||
# This code used to use Array#& and then compare 2 arrays, but
|
||||
# the ordering from Array#& is undefined, as it uses Hash internally.
|
||||
#
|
||||
# Loop is more verbose, but more explicit in what we're testing.
|
||||
|
||||
anc = B.ancestors
|
||||
[B, U, V, W, A, X].each do |i|
|
||||
anc.include?(i).should be_true
|
||||
end
|
||||
|
||||
class B; include V; end
|
||||
|
||||
# the only new module is Y, it is added after U since it follows U in V mixin list:
|
||||
anc = B.ancestors
|
||||
[B, U, Y, V, W, A, X].each do |i|
|
||||
anc.include?(i).should be_true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "preserves ancestor order" do
|
||||
module ModuleSpecs::M2
|
||||
module M1; end
|
||||
module M2; end
|
||||
module M3; include M2; end
|
||||
|
||||
module M2; include M1; end
|
||||
module M3; include M2; end
|
||||
|
||||
M3.ancestors.should == [M3, M2, M1]
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
it "detects cyclic includes" do
|
||||
lambda {
|
||||
module ModuleSpecs::M
|
||||
include ModuleSpecs::M
|
||||
end
|
||||
}.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
ruby_version_is ''...'2.4' do
|
||||
it "accepts no-arguments" do
|
||||
lambda {
|
||||
Module.new do
|
||||
include
|
||||
end
|
||||
}.should_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is '2.4' do
|
||||
it "doesn't accept no-arguments" do
|
||||
lambda {
|
||||
Module.new do
|
||||
include
|
||||
end
|
||||
}.should raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
it "returns the class it's included into" do
|
||||
m = Module.new
|
||||
r = nil
|
||||
c = Class.new { r = include m }
|
||||
r.should == c
|
||||
end
|
||||
|
||||
it "ignores modules it has already included via module mutual inclusion" do
|
||||
module ModuleSpecs::AlreadyInc
|
||||
module M0
|
||||
end
|
||||
|
||||
module M
|
||||
include M0
|
||||
end
|
||||
|
||||
class K
|
||||
include M
|
||||
include M
|
||||
end
|
||||
|
||||
K.ancestors[0].should == K
|
||||
K.ancestors[1].should == M
|
||||
K.ancestors[2].should == M0
|
||||
end
|
||||
end
|
||||
|
||||
it "clears any caches" do
|
||||
module ModuleSpecs::M3
|
||||
module M1
|
||||
def foo
|
||||
:m1
|
||||
end
|
||||
end
|
||||
|
||||
module M2
|
||||
def foo
|
||||
:m2
|
||||
end
|
||||
end
|
||||
|
||||
class C
|
||||
include M1
|
||||
|
||||
def get
|
||||
foo
|
||||
end
|
||||
end
|
||||
|
||||
c = C.new
|
||||
c.get.should == :m1
|
||||
|
||||
class C
|
||||
include M2
|
||||
end
|
||||
|
||||
c.get.should == :m2
|
||||
|
||||
remove_const :C
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "Module#include?" do
|
||||
it "returns true if the given module is included by self or one of it's ancestors" do
|
||||
ModuleSpecs::Super.include?(ModuleSpecs::Basic).should == true
|
||||
ModuleSpecs::Child.include?(ModuleSpecs::Basic).should == true
|
||||
ModuleSpecs::Child.include?(ModuleSpecs::Super).should == true
|
||||
ModuleSpecs::Child.include?(Kernel).should == true
|
||||
|
||||
ModuleSpecs::Parent.include?(ModuleSpecs::Basic).should == false
|
||||
ModuleSpecs::Basic.include?(ModuleSpecs::Super).should == false
|
||||
end
|
||||
|
||||
it "returns false if given module is equal to self" do
|
||||
ModuleSpecs.include?(ModuleSpecs).should == false
|
||||
end
|
||||
|
||||
it "raises a TypeError when no module was given" do
|
||||
lambda { ModuleSpecs::Child.include?("Test") }.should raise_error(TypeError)
|
||||
lambda { ModuleSpecs::Child.include?(ModuleSpecs::Parent) }.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
12
spec/ruby/core/module/included_modules_spec.rb
Normal file
12
spec/ruby/core/module/included_modules_spec.rb
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#included_modules" do
|
||||
it "returns a list of modules included in self" do
|
||||
ModuleSpecs.included_modules.should == []
|
||||
ModuleSpecs::Child.included_modules.should include(ModuleSpecs::Super, ModuleSpecs::Basic, Kernel)
|
||||
ModuleSpecs::Parent.included_modules.should include(Kernel)
|
||||
ModuleSpecs::Basic.included_modules.should == []
|
||||
ModuleSpecs::Super.included_modules.should include(ModuleSpecs::Basic)
|
||||
end
|
||||
end
|
||||
44
spec/ruby/core/module/included_spec.rb
Normal file
44
spec/ruby/core/module/included_spec.rb
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#included" do
|
||||
it "is invoked when self is included in another module or class" do
|
||||
begin
|
||||
m = Module.new do
|
||||
def self.included(o)
|
||||
$included_by = o
|
||||
end
|
||||
end
|
||||
|
||||
c = Class.new { include m }
|
||||
|
||||
$included_by.should == c
|
||||
ensure
|
||||
$included_by = nil
|
||||
end
|
||||
end
|
||||
|
||||
it "allows extending self with the object into which it is being included" do
|
||||
m = Module.new do
|
||||
def self.included(o)
|
||||
o.extend(self)
|
||||
end
|
||||
|
||||
def test
|
||||
:passed
|
||||
end
|
||||
end
|
||||
|
||||
c = Class.new{ include(m) }
|
||||
c.test.should == :passed
|
||||
end
|
||||
|
||||
it "is private in its default implementation" do
|
||||
Module.should have_private_instance_method(:included)
|
||||
end
|
||||
|
||||
it "works with super using a singleton class" do
|
||||
ModuleSpecs::SingletonOnModuleCase::Bar.include ModuleSpecs::SingletonOnModuleCase::Foo
|
||||
ModuleSpecs::SingletonOnModuleCase::Bar.included_called?.should == true
|
||||
end
|
||||
end
|
||||
10
spec/ruby/core/module/initialize_copy_spec.rb
Normal file
10
spec/ruby/core/module/initialize_copy_spec.rb
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
|
||||
describe "Module#initialize_copy" do
|
||||
it "should retain singleton methods when duped" do
|
||||
mod = Module.new
|
||||
def mod.hello
|
||||
end
|
||||
mod.dup.methods(false).should == [:hello]
|
||||
end
|
||||
end
|
||||
18
spec/ruby/core/module/initialize_spec.rb
Normal file
18
spec/ruby/core/module/initialize_spec.rb
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#initialize" do
|
||||
it "accepts a block" do
|
||||
m = Module.new do
|
||||
const_set :A, "A"
|
||||
end
|
||||
m.const_get("A").should == "A"
|
||||
end
|
||||
|
||||
it "is called on subclasses" do
|
||||
m = ModuleSpecs::SubModule.new
|
||||
m.special.should == 10
|
||||
m.methods.should_not == nil
|
||||
m.constants.should_not == nil
|
||||
end
|
||||
end
|
||||
85
spec/ruby/core/module/instance_method_spec.rb
Normal file
85
spec/ruby/core/module/instance_method_spec.rb
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#instance_method" do
|
||||
before :all do
|
||||
@parent_um = ModuleSpecs::InstanceMeth.instance_method(:foo)
|
||||
@child_um = ModuleSpecs::InstanceMethChild.instance_method(:foo)
|
||||
@mod_um = ModuleSpecs::InstanceMethChild.instance_method(:bar)
|
||||
end
|
||||
|
||||
it "is a public method" do
|
||||
Module.should have_public_instance_method(:instance_method, false)
|
||||
end
|
||||
|
||||
it "requires an argument" do
|
||||
Module.new.method(:instance_method).arity.should == 1
|
||||
end
|
||||
|
||||
it "returns an UnboundMethod corresponding to the given name" do
|
||||
@parent_um.should be_kind_of(UnboundMethod)
|
||||
@parent_um.bind(ModuleSpecs::InstanceMeth.new).call.should == :foo
|
||||
end
|
||||
|
||||
it "returns an UnboundMethod corresponding to the given name from a superclass" do
|
||||
@child_um.should be_kind_of(UnboundMethod)
|
||||
@child_um.bind(ModuleSpecs::InstanceMethChild.new).call.should == :foo
|
||||
end
|
||||
|
||||
it "returns an UnboundMethod corresponding to the given name from an included Module" do
|
||||
@mod_um.should be_kind_of(UnboundMethod)
|
||||
@mod_um.bind(ModuleSpecs::InstanceMethChild.new).call.should == :bar
|
||||
end
|
||||
|
||||
it "returns an UnboundMethod when given a protected method name" do
|
||||
ModuleSpecs::Basic.instance_method(:protected_module).should be_an_instance_of(UnboundMethod)
|
||||
end
|
||||
|
||||
it "returns an UnboundMethod when given a private method name" do
|
||||
ModuleSpecs::Basic.instance_method(:private_module).should be_an_instance_of(UnboundMethod)
|
||||
end
|
||||
|
||||
it "gives UnboundMethod method name, Module defined in and Module extracted from" do
|
||||
@parent_um.inspect.should =~ /\bfoo\b/
|
||||
@parent_um.inspect.should =~ /\bModuleSpecs::InstanceMeth\b/
|
||||
@parent_um.inspect.should =~ /\bModuleSpecs::InstanceMeth\b/
|
||||
@child_um.inspect.should =~ /\bfoo\b/
|
||||
@child_um.inspect.should =~ /\bModuleSpecs::InstanceMeth\b/
|
||||
@child_um.inspect.should =~ /\bModuleSpecs::InstanceMethChild\b/
|
||||
@mod_um.inspect.should =~ /\bbar\b/
|
||||
@mod_um.inspect.should =~ /\bModuleSpecs::InstanceMethMod\b/
|
||||
@mod_um.inspect.should =~ /\bModuleSpecs::InstanceMethChild\b/
|
||||
end
|
||||
|
||||
it "raises a TypeError if not passed a symbol" do
|
||||
lambda { Object.instance_method([]) }.should raise_error(TypeError)
|
||||
lambda { Object.instance_method(0) }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "raises a TypeError if the given name is not a string/symbol" do
|
||||
lambda { Object.instance_method(nil) }.should raise_error(TypeError)
|
||||
lambda { Object.instance_method(mock('x')) }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "raises a NameError if the method has been undefined" do
|
||||
child = Class.new(ModuleSpecs::InstanceMeth)
|
||||
child.send :undef_method, :foo
|
||||
um = ModuleSpecs::InstanceMeth.instance_method(:foo)
|
||||
um.should == @parent_um
|
||||
lambda do
|
||||
child.instance_method(:foo)
|
||||
end.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a NameError if the method does not exist" do
|
||||
lambda { Object.instance_method(:missing) }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "sets the NameError#name attribute to the name of the missing method" do
|
||||
begin
|
||||
Object.instance_method(:missing)
|
||||
rescue NameError => e
|
||||
e.name.should == :missing
|
||||
end
|
||||
end
|
||||
end
|
||||
61
spec/ruby/core/module/instance_methods_spec.rb
Normal file
61
spec/ruby/core/module/instance_methods_spec.rb
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#instance_methods" do
|
||||
it "does not return methods undefined in a superclass" do
|
||||
methods = ModuleSpecs::Parent.instance_methods(false)
|
||||
methods.should_not include(:undefed_method)
|
||||
end
|
||||
|
||||
it "only includes module methods on an included module" do
|
||||
methods = ModuleSpecs::Basic.instance_methods(false)
|
||||
methods.should include(:public_module)
|
||||
# Child is an including class
|
||||
methods = ModuleSpecs::Child.instance_methods(false)
|
||||
methods.should include(:public_child)
|
||||
methods.should_not include(:public_module)
|
||||
end
|
||||
|
||||
it "does not return methods undefined in a subclass" do
|
||||
methods = ModuleSpecs::Grandchild.instance_methods
|
||||
methods.should_not include(:parent_method, :another_parent_method)
|
||||
end
|
||||
|
||||
it "does not return methods undefined in the current class" do
|
||||
class ModuleSpecs::Child
|
||||
def undefed_child
|
||||
end
|
||||
end
|
||||
ModuleSpecs::Child.send(:undef_method, :undefed_child)
|
||||
methods = ModuleSpecs::Child.instance_methods
|
||||
methods.should_not include(:undefed_method, :undefed_child)
|
||||
end
|
||||
|
||||
it "does not return methods from an included module that are undefined in the class" do
|
||||
ModuleSpecs::Grandchild.instance_methods.should_not include(:super_included_method)
|
||||
end
|
||||
|
||||
it "returns the public and protected methods of self if include_super is false" do
|
||||
methods = ModuleSpecs::Parent.instance_methods(false)
|
||||
methods.should include(:protected_parent, :public_parent)
|
||||
|
||||
methods = ModuleSpecs::Child.instance_methods(false)
|
||||
methods.should include(:protected_child, :public_child)
|
||||
end
|
||||
|
||||
it "returns the public and protected methods of self and it's ancestors" do
|
||||
methods = ModuleSpecs::Basic.instance_methods
|
||||
methods.should include(:protected_module, :public_module)
|
||||
|
||||
methods = ModuleSpecs::Super.instance_methods
|
||||
methods.should include(:protected_module, :protected_super_module,
|
||||
:public_module, :public_super_module)
|
||||
end
|
||||
|
||||
it "makes a private Object instance method public in Kernel" do
|
||||
methods = Kernel.instance_methods
|
||||
methods.should include(:module_specs_private_method_on_object_for_kernel_public)
|
||||
methods = Object.instance_methods
|
||||
methods.should_not include(:module_specs_private_method_on_object_for_kernel_public)
|
||||
end
|
||||
end
|
||||
36
spec/ruby/core/module/lt_spec.rb
Normal file
36
spec/ruby/core/module/lt_spec.rb
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#<" do
|
||||
it "returns true if self is a subclass of or includes the given module" do
|
||||
(ModuleSpecs::Child < ModuleSpecs::Parent).should == true
|
||||
(ModuleSpecs::Child < ModuleSpecs::Basic).should == true
|
||||
(ModuleSpecs::Child < ModuleSpecs::Super).should == true
|
||||
(ModuleSpecs::Super < ModuleSpecs::Basic).should == true
|
||||
end
|
||||
|
||||
it "returns false if self is a superclass of or included by the given module" do
|
||||
(ModuleSpecs::Parent < ModuleSpecs::Child).should be_false
|
||||
(ModuleSpecs::Basic < ModuleSpecs::Child).should be_false
|
||||
(ModuleSpecs::Super < ModuleSpecs::Child).should be_false
|
||||
(ModuleSpecs::Basic < ModuleSpecs::Super).should be_false
|
||||
end
|
||||
|
||||
it "returns false if self is the same as the given module" do
|
||||
(ModuleSpecs::Child < ModuleSpecs::Child).should == false
|
||||
(ModuleSpecs::Parent < ModuleSpecs::Parent).should == false
|
||||
(ModuleSpecs::Basic < ModuleSpecs::Basic).should == false
|
||||
(ModuleSpecs::Super < ModuleSpecs::Super).should == false
|
||||
end
|
||||
|
||||
it "returns nil if self is not related to the given module" do
|
||||
(ModuleSpecs::Parent < ModuleSpecs::Basic).should == nil
|
||||
(ModuleSpecs::Parent < ModuleSpecs::Super).should == nil
|
||||
(ModuleSpecs::Basic < ModuleSpecs::Parent).should == nil
|
||||
(ModuleSpecs::Super < ModuleSpecs::Parent).should == nil
|
||||
end
|
||||
|
||||
it "raises a TypeError if the argument is not a class/module" do
|
||||
lambda { ModuleSpecs::Parent < mock('x') }.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
33
spec/ruby/core/module/lte_spec.rb
Normal file
33
spec/ruby/core/module/lte_spec.rb
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#<=" do
|
||||
it "returns true if self is a subclass of, the same as or includes the given module" do
|
||||
(ModuleSpecs::Child <= ModuleSpecs::Parent).should == true
|
||||
(ModuleSpecs::Child <= ModuleSpecs::Basic).should == true
|
||||
(ModuleSpecs::Child <= ModuleSpecs::Super).should == true
|
||||
(ModuleSpecs::Super <= ModuleSpecs::Basic).should == true
|
||||
(ModuleSpecs::Child <= ModuleSpecs::Child).should == true
|
||||
(ModuleSpecs::Parent <= ModuleSpecs::Parent).should == true
|
||||
(ModuleSpecs::Basic <= ModuleSpecs::Basic).should == true
|
||||
(ModuleSpecs::Super <= ModuleSpecs::Super).should == true
|
||||
end
|
||||
|
||||
it "returns nil if self is not related to the given module" do
|
||||
(ModuleSpecs::Parent <= ModuleSpecs::Basic).should == nil
|
||||
(ModuleSpecs::Parent <= ModuleSpecs::Super).should == nil
|
||||
(ModuleSpecs::Basic <= ModuleSpecs::Parent).should == nil
|
||||
(ModuleSpecs::Super <= ModuleSpecs::Parent).should == nil
|
||||
end
|
||||
|
||||
it "returns false if self is a superclass of or is included by the given module" do
|
||||
(ModuleSpecs::Parent <= ModuleSpecs::Child).should == false
|
||||
(ModuleSpecs::Basic <= ModuleSpecs::Child).should == false
|
||||
(ModuleSpecs::Super <= ModuleSpecs::Child).should == false
|
||||
(ModuleSpecs::Basic <= ModuleSpecs::Super).should == false
|
||||
end
|
||||
|
||||
it "raises a TypeError if the argument is not a class/module" do
|
||||
lambda { ModuleSpecs::Parent <= mock('x') }.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
62
spec/ruby/core/module/method_added_spec.rb
Normal file
62
spec/ruby/core/module/method_added_spec.rb
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#method_added" do
|
||||
it "is a private instance method" do
|
||||
Module.should have_private_instance_method(:method_added)
|
||||
end
|
||||
|
||||
it "returns nil in the default implementation" do
|
||||
Module.new do
|
||||
method_added(:test).should == nil
|
||||
end
|
||||
end
|
||||
|
||||
it "is called when a new instance method is defined in self" do
|
||||
ScratchPad.record []
|
||||
|
||||
Module.new do
|
||||
def self.method_added(name)
|
||||
ScratchPad << name
|
||||
end
|
||||
|
||||
def test() end
|
||||
def test2() end
|
||||
def test() end
|
||||
alias_method :aliased_test, :test
|
||||
alias aliased_test2 test
|
||||
end
|
||||
|
||||
ScratchPad.recorded.should == [:test, :test2, :test, :aliased_test, :aliased_test2]
|
||||
end
|
||||
|
||||
it "is not called when a singleton method is added" do
|
||||
# obj.singleton_method_added is called instead
|
||||
ScratchPad.record []
|
||||
|
||||
klass = Class.new
|
||||
def klass.method_added(name)
|
||||
ScratchPad << name
|
||||
end
|
||||
|
||||
obj = klass.new
|
||||
def obj.new_singleton_method
|
||||
end
|
||||
|
||||
ScratchPad.recorded.should == []
|
||||
end
|
||||
|
||||
it "is not called when a method is undefined in self" do
|
||||
m = Module.new do
|
||||
def method_to_undef
|
||||
end
|
||||
|
||||
def self.method_added(name)
|
||||
fail("method_added called by undef_method")
|
||||
end
|
||||
|
||||
undef_method :method_to_undef
|
||||
end
|
||||
m.should_not have_method(:method_to_undef)
|
||||
end
|
||||
end
|
||||
49
spec/ruby/core/module/method_defined_spec.rb
Normal file
49
spec/ruby/core/module/method_defined_spec.rb
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#method_defined?" do
|
||||
it "returns true if a public or private method with the given name is defined in self, self's ancestors or one of self's included modules" do
|
||||
# Defined in Child
|
||||
ModuleSpecs::Child.method_defined?(:public_child).should == true
|
||||
ModuleSpecs::Child.method_defined?("private_child").should == false
|
||||
ModuleSpecs::Child.method_defined?(:accessor_method).should == true
|
||||
|
||||
# Defined in Parent
|
||||
ModuleSpecs::Child.method_defined?("public_parent").should == true
|
||||
ModuleSpecs::Child.method_defined?(:private_parent).should == false
|
||||
|
||||
# Defined in Module
|
||||
ModuleSpecs::Child.method_defined?(:public_module).should == true
|
||||
ModuleSpecs::Child.method_defined?(:protected_module).should == true
|
||||
ModuleSpecs::Child.method_defined?(:private_module).should == false
|
||||
|
||||
# Defined in SuperModule
|
||||
ModuleSpecs::Child.method_defined?(:public_super_module).should == true
|
||||
ModuleSpecs::Child.method_defined?(:protected_super_module).should == true
|
||||
ModuleSpecs::Child.method_defined?(:private_super_module).should == false
|
||||
end
|
||||
|
||||
# unlike alias_method, module_function, public, and friends,
|
||||
it "does not search Object or Kernel when called on a module" do
|
||||
m = Module.new
|
||||
|
||||
m.method_defined?(:module_specs_public_method_on_kernel).should be_false
|
||||
end
|
||||
|
||||
it "raises a TypeError when the given object is not a string/symbol/fixnum" do
|
||||
c = Class.new
|
||||
o = mock('123')
|
||||
|
||||
lambda { c.method_defined?(o) }.should raise_error(TypeError)
|
||||
|
||||
o.should_receive(:to_str).and_return(123)
|
||||
lambda { c.method_defined?(o) }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "converts the given name to a string using to_str" do
|
||||
c = Class.new { def test(); end }
|
||||
(o = mock('test')).should_receive(:to_str).and_return("test")
|
||||
|
||||
c.method_defined?(o).should == true
|
||||
end
|
||||
end
|
||||
33
spec/ruby/core/module/method_removed_spec.rb
Normal file
33
spec/ruby/core/module/method_removed_spec.rb
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#method_removed" do
|
||||
it "is a private instance method" do
|
||||
Module.should have_private_instance_method(:method_removed)
|
||||
end
|
||||
|
||||
it "returns nil in the default implementation" do
|
||||
Module.new do
|
||||
method_removed(:test).should == nil
|
||||
end
|
||||
end
|
||||
|
||||
it "is called when a method is removed from self" do
|
||||
begin
|
||||
Module.new do
|
||||
def self.method_removed(name)
|
||||
$method_removed = name
|
||||
end
|
||||
|
||||
def test
|
||||
"test"
|
||||
end
|
||||
remove_method :test
|
||||
end
|
||||
|
||||
$method_removed.should == :test
|
||||
ensure
|
||||
$method_removed = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
33
spec/ruby/core/module/method_undefined_spec.rb
Normal file
33
spec/ruby/core/module/method_undefined_spec.rb
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#method_undefined" do
|
||||
it "is a private instance method" do
|
||||
Module.should have_private_instance_method(:method_undefined)
|
||||
end
|
||||
|
||||
it "returns nil in the default implementation" do
|
||||
Module.new do
|
||||
method_undefined(:test).should == nil
|
||||
end
|
||||
end
|
||||
|
||||
it "is called when a method is undefined from self" do
|
||||
begin
|
||||
Module.new do
|
||||
def self.method_undefined(name)
|
||||
$method_undefined = name
|
||||
end
|
||||
|
||||
def test
|
||||
"test"
|
||||
end
|
||||
undef_method :test
|
||||
end
|
||||
|
||||
$method_undefined.should == :test
|
||||
ensure
|
||||
$method_undefined = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
7
spec/ruby/core/module/module_eval_spec.rb
Normal file
7
spec/ruby/core/module/module_eval_spec.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
require File.expand_path('../shared/class_eval', __FILE__)
|
||||
|
||||
describe "Module#module_eval" do
|
||||
it_behaves_like :module_class_eval, :module_eval
|
||||
end
|
||||
7
spec/ruby/core/module/module_exec_spec.rb
Normal file
7
spec/ruby/core/module/module_exec_spec.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
require File.expand_path('../shared/class_exec', __FILE__)
|
||||
|
||||
describe "Module#module_exec" do
|
||||
it_behaves_like :module_class_exec, :module_exec
|
||||
end
|
||||
269
spec/ruby/core/module/module_function_spec.rb
Normal file
269
spec/ruby/core/module/module_function_spec.rb
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#module_function" do
|
||||
it "is a private method" do
|
||||
Module.should have_private_instance_method(:module_function)
|
||||
end
|
||||
|
||||
describe "on Class" do
|
||||
it "is undefined" do
|
||||
Class.should_not have_private_instance_method(:module_function, true)
|
||||
end
|
||||
|
||||
it "raises a TypeError if calling after rebinded to Class" do
|
||||
lambda {
|
||||
Module.instance_method(:module_function).bind(Class.new).call
|
||||
}.should raise_error(TypeError)
|
||||
|
||||
lambda {
|
||||
Module.instance_method(:module_function).bind(Class.new).call :foo
|
||||
}.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "Module#module_function with specific method names" do
|
||||
it "creates duplicates of the given instance methods on the Module object" do
|
||||
m = Module.new do
|
||||
def test() end
|
||||
def test2() end
|
||||
def test3() end
|
||||
|
||||
module_function :test, :test2
|
||||
end
|
||||
|
||||
m.respond_to?(:test).should == true
|
||||
m.respond_to?(:test2).should == true
|
||||
m.respond_to?(:test3).should == false
|
||||
end
|
||||
|
||||
it "returns the current module" do
|
||||
x = nil
|
||||
m = Module.new do
|
||||
def test() end
|
||||
x = module_function :test
|
||||
end
|
||||
|
||||
x.should == m
|
||||
end
|
||||
|
||||
it "creates an independent copy of the method, not a redirect" do
|
||||
module Mixin
|
||||
def test
|
||||
"hello"
|
||||
end
|
||||
module_function :test
|
||||
end
|
||||
|
||||
class BaseClass
|
||||
include Mixin
|
||||
def call_test
|
||||
test
|
||||
end
|
||||
end
|
||||
|
||||
Mixin.test.should == "hello"
|
||||
c = BaseClass.new
|
||||
c.call_test.should == "hello"
|
||||
|
||||
module Mixin
|
||||
def test
|
||||
"goodbye"
|
||||
end
|
||||
end
|
||||
|
||||
Mixin.test.should == "hello"
|
||||
c.call_test.should == "goodbye"
|
||||
end
|
||||
|
||||
it "makes the instance methods private" do
|
||||
m = Module.new do
|
||||
def test() "hello" end
|
||||
module_function :test
|
||||
end
|
||||
|
||||
(o = mock('x')).extend(m)
|
||||
o.respond_to?(:test).should == false
|
||||
m.should have_private_instance_method(:test)
|
||||
o.send(:test).should == "hello"
|
||||
lambda { o.test }.should raise_error(NoMethodError)
|
||||
end
|
||||
|
||||
it "makes the new Module methods public" do
|
||||
m = Module.new do
|
||||
def test() "hello" end
|
||||
module_function :test
|
||||
end
|
||||
|
||||
m.public_methods.map {|me| me.to_s }.include?('test').should == true
|
||||
end
|
||||
|
||||
it "tries to convert the given names to strings using to_str" do
|
||||
(o = mock('test')).should_receive(:to_str).any_number_of_times.and_return("test")
|
||||
(o2 = mock('test2')).should_receive(:to_str).any_number_of_times.and_return("test2")
|
||||
|
||||
m = Module.new do
|
||||
def test() end
|
||||
def test2() end
|
||||
module_function o, o2
|
||||
end
|
||||
|
||||
m.respond_to?(:test).should == true
|
||||
m.respond_to?(:test2).should == true
|
||||
end
|
||||
|
||||
it "raises a TypeError when the given names can't be converted to string using to_str" do
|
||||
o = mock('123')
|
||||
|
||||
lambda { Module.new { module_function(o) } }.should raise_error(TypeError)
|
||||
|
||||
o.should_receive(:to_str).and_return(123)
|
||||
lambda { Module.new { module_function(o) } }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "can make accessible private methods" do # JRUBY-4214
|
||||
m = Module.new do
|
||||
module_function :require
|
||||
end
|
||||
m.respond_to?(:require).should be_true
|
||||
end
|
||||
|
||||
it "creates Module methods that super up the singleton class of the module" do
|
||||
super_m = Module.new do
|
||||
def foo
|
||||
"super_m"
|
||||
end
|
||||
end
|
||||
|
||||
m = Module.new do
|
||||
extend super_m
|
||||
module_function
|
||||
def foo
|
||||
["m", super]
|
||||
end
|
||||
end
|
||||
|
||||
m.foo.should == ["m", "super_m"]
|
||||
end
|
||||
end
|
||||
|
||||
describe "Module#module_function as a toggle (no arguments) in a Module body" do
|
||||
it "makes any subsequently defined methods module functions with the normal semantics" do
|
||||
m = Module.new {
|
||||
module_function
|
||||
def test1() end
|
||||
def test2() end
|
||||
}
|
||||
|
||||
m.respond_to?(:test1).should == true
|
||||
m.respond_to?(:test2).should == true
|
||||
end
|
||||
|
||||
it "returns the current module" do
|
||||
x = nil
|
||||
m = Module.new {
|
||||
x = module_function
|
||||
}
|
||||
|
||||
x.should == m
|
||||
end
|
||||
|
||||
it "stops creating module functions if the body encounters another toggle " \
|
||||
"like public/protected/private without arguments" do
|
||||
m = Module.new {
|
||||
module_function
|
||||
def test1() end
|
||||
def test2() end
|
||||
public
|
||||
def test3() end
|
||||
}
|
||||
|
||||
m.respond_to?(:test1).should == true
|
||||
m.respond_to?(:test2).should == true
|
||||
m.respond_to?(:test3).should == false
|
||||
end
|
||||
|
||||
it "does not stop creating module functions if the body encounters " \
|
||||
"public/protected/private WITH arguments" do
|
||||
m = Module.new {
|
||||
def foo() end
|
||||
module_function
|
||||
def test1() end
|
||||
def test2() end
|
||||
public :foo
|
||||
def test3() end
|
||||
}
|
||||
|
||||
m.respond_to?(:test1).should == true
|
||||
m.respond_to?(:test2).should == true
|
||||
m.respond_to?(:test3).should == true
|
||||
end
|
||||
|
||||
it "does not affect module_evaled method definitions also if outside the eval itself" do
|
||||
m = Module.new {
|
||||
module_function
|
||||
module_eval { def test1() end }
|
||||
module_eval " def test2() end "
|
||||
}
|
||||
|
||||
m.respond_to?(:test1).should == false
|
||||
m.respond_to?(:test2).should == false
|
||||
end
|
||||
|
||||
it "has no effect if inside a module_eval if the definitions are outside of it" do
|
||||
m = Module.new {
|
||||
module_eval { module_function }
|
||||
def test1() end
|
||||
def test2() end
|
||||
}
|
||||
|
||||
m.respond_to?(:test1).should == false
|
||||
m.respond_to?(:test2).should == false
|
||||
end
|
||||
|
||||
it "functions normally if both toggle and definitions inside a module_eval" do
|
||||
m = Module.new {
|
||||
module_eval {
|
||||
module_function
|
||||
def test1() end
|
||||
def test2() end
|
||||
}
|
||||
}
|
||||
|
||||
m.respond_to?(:test1).should == true
|
||||
m.respond_to?(:test2).should == true
|
||||
end
|
||||
|
||||
it "affects evaled method definitions also even when outside the eval itself" do
|
||||
m = Module.new {
|
||||
module_function
|
||||
eval "def test1() end"
|
||||
}
|
||||
|
||||
m.respond_to?(:test1).should == true
|
||||
end
|
||||
|
||||
it "doesn't affect definitions when inside an eval even if the definitions are outside of it" do
|
||||
m = Module.new {
|
||||
eval "module_function"
|
||||
def test1() end
|
||||
}
|
||||
|
||||
m.respond_to?(:test1).should == false
|
||||
end
|
||||
|
||||
it "functions normally if both toggle and definitions inside a eval" do
|
||||
m = Module.new {
|
||||
eval <<-CODE
|
||||
module_function
|
||||
|
||||
def test1() end
|
||||
def test2() end
|
||||
CODE
|
||||
}
|
||||
|
||||
m.respond_to?(:test1).should == true
|
||||
m.respond_to?(:test2).should == true
|
||||
end
|
||||
end
|
||||
68
spec/ruby/core/module/name_spec.rb
Normal file
68
spec/ruby/core/module/name_spec.rb
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/module', __FILE__)
|
||||
|
||||
describe "Module#name" do
|
||||
it "is nil for an anonymous module" do
|
||||
Module.new.name.should be_nil
|
||||
end
|
||||
|
||||
it "is nil when assigned to a constant in an anonymous module" do
|
||||
m = Module.new
|
||||
m::N = Module.new
|
||||
m::N.name.should be_nil
|
||||
end
|
||||
|
||||
it "is not nil for a nested module created with the module keyword" do
|
||||
m = Module.new
|
||||
module m::N; end
|
||||
m::N.name.should =~ /#<Module:0x[0-9a-f]+>::N/
|
||||
end
|
||||
|
||||
it "is set when opened with the module keyword" do
|
||||
ModuleSpecs.name.should == "ModuleSpecs"
|
||||
end
|
||||
|
||||
it "is set when a nested module is opened with the module keyword" do
|
||||
ModuleSpecs::Anonymous.name.should == "ModuleSpecs::Anonymous"
|
||||
end
|
||||
|
||||
it "is set when assigning to a constant" do
|
||||
m = Module.new
|
||||
ModuleSpecs::Anonymous::A = m
|
||||
m.name.should == "ModuleSpecs::Anonymous::A"
|
||||
end
|
||||
|
||||
it "is not modified when assigning to a new constant after it has been accessed" do
|
||||
m = Module.new
|
||||
ModuleSpecs::Anonymous::B = m
|
||||
m.name.should == "ModuleSpecs::Anonymous::B"
|
||||
ModuleSpecs::Anonymous::C = m
|
||||
m.name.should == "ModuleSpecs::Anonymous::B"
|
||||
end
|
||||
|
||||
# http://bugs.ruby-lang.org/issues/6067
|
||||
it "is set with a conditional assignment to a nested constant" do
|
||||
eval("ModuleSpecs::Anonymous::F ||= Module.new")
|
||||
ModuleSpecs::Anonymous::F.name.should == "ModuleSpecs::Anonymous::F"
|
||||
end
|
||||
|
||||
it "is set with a conditional assignment to a constant" do
|
||||
module ModuleSpecs::Anonymous
|
||||
D ||= Module.new
|
||||
end
|
||||
ModuleSpecs::Anonymous::D.name.should == "ModuleSpecs::Anonymous::D"
|
||||
end
|
||||
|
||||
# http://redmine.ruby-lang.org/issues/show/1833
|
||||
it "preserves the encoding in which the class was defined" do
|
||||
require fixture(__FILE__, "name")
|
||||
ModuleSpecs::NameEncoding.new.name.encoding.should == Encoding::UTF_8
|
||||
end
|
||||
|
||||
it "is set when the anonymous outer module name is set" do
|
||||
m = Module.new
|
||||
m::N = Module.new
|
||||
ModuleSpecs::Anonymous::E = m
|
||||
m::N.name.should == "ModuleSpecs::Anonymous::E::N"
|
||||
end
|
||||
end
|
||||
31
spec/ruby/core/module/nesting_spec.rb
Normal file
31
spec/ruby/core/module/nesting_spec.rb
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module::Nesting" do
|
||||
|
||||
it "returns the list of Modules nested at the point of call" do
|
||||
ModuleSpecs::Nesting[:root_level].should == []
|
||||
ModuleSpecs::Nesting[:first_level].should == [ModuleSpecs]
|
||||
ModuleSpecs::Nesting[:basic].should == [ModuleSpecs::Nesting, ModuleSpecs]
|
||||
ModuleSpecs::Nesting[:open_first_level].should ==
|
||||
[ModuleSpecs, ModuleSpecs::Nesting, ModuleSpecs]
|
||||
ModuleSpecs::Nesting[:open_meta].should ==
|
||||
[ModuleSpecs::Nesting.meta, ModuleSpecs::Nesting, ModuleSpecs]
|
||||
ModuleSpecs::Nesting[:nest_class].should ==
|
||||
[ModuleSpecs::Nesting::NestedClass, ModuleSpecs::Nesting, ModuleSpecs]
|
||||
end
|
||||
|
||||
it "returns the nesting for module/class declaring the called method" do
|
||||
ModuleSpecs::Nesting.called_from_module_method.should ==
|
||||
[ModuleSpecs::Nesting, ModuleSpecs]
|
||||
ModuleSpecs::Nesting::NestedClass.called_from_class_method.should ==
|
||||
[ModuleSpecs::Nesting::NestedClass, ModuleSpecs::Nesting, ModuleSpecs]
|
||||
ModuleSpecs::Nesting::NestedClass.new.called_from_inst_method.should ==
|
||||
[ModuleSpecs::Nesting::NestedClass, ModuleSpecs::Nesting, ModuleSpecs]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "Module.nesting" do
|
||||
it "needs to be reviewed for spec completeness"
|
||||
end
|
||||
31
spec/ruby/core/module/new_spec.rb
Normal file
31
spec/ruby/core/module/new_spec.rb
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module.new" do
|
||||
it "creates a new anonymous Module" do
|
||||
Module.new.is_a?(Module).should == true
|
||||
end
|
||||
|
||||
it "creates a new Module and passes it to the provided block" do
|
||||
test_mod = nil
|
||||
m = Module.new do |mod|
|
||||
mod.should_not == nil
|
||||
self.should == mod
|
||||
test_mod = mod
|
||||
mod.is_a?(Module).should == true
|
||||
Object.new # trying to return something
|
||||
end
|
||||
test_mod.should == m
|
||||
end
|
||||
|
||||
it "evaluates a passed block in the context of the module" do
|
||||
fred = Module.new do
|
||||
def hello() "hello" end
|
||||
def bye() "bye" end
|
||||
end
|
||||
|
||||
(o = mock('x')).extend(fred)
|
||||
o.hello.should == "hello"
|
||||
o.bye.should == "bye"
|
||||
end
|
||||
end
|
||||
76
spec/ruby/core/module/prepend_features_spec.rb
Normal file
76
spec/ruby/core/module/prepend_features_spec.rb
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#prepend_features" do
|
||||
it "is a private method" do
|
||||
Module.should have_private_instance_method(:prepend_features, true)
|
||||
end
|
||||
|
||||
it "gets called when self is included in another module/class" do
|
||||
ScratchPad.record []
|
||||
|
||||
m = Module.new do
|
||||
def self.prepend_features(mod)
|
||||
ScratchPad << mod
|
||||
end
|
||||
end
|
||||
|
||||
c = Class.new do
|
||||
prepend m
|
||||
end
|
||||
|
||||
ScratchPad.recorded.should == [c]
|
||||
end
|
||||
|
||||
it "raises an ArgumentError on a cyclic prepend" do
|
||||
lambda {
|
||||
ModuleSpecs::CyclicPrepend.send(:prepend_features, ModuleSpecs::CyclicPrepend)
|
||||
}.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "copies own tainted status to the given module" do
|
||||
other = Module.new
|
||||
Module.new.taint.send :prepend_features, other
|
||||
other.tainted?.should be_true
|
||||
end
|
||||
|
||||
it "copies own untrusted status to the given module" do
|
||||
other = Module.new
|
||||
Module.new.untrust.send :prepend_features, other
|
||||
other.untrusted?.should be_true
|
||||
end
|
||||
|
||||
it "clears caches of the given module" do
|
||||
parent = Class.new do
|
||||
def bar; :bar; end
|
||||
end
|
||||
|
||||
child = Class.new(parent) do
|
||||
def foo; :foo; end
|
||||
def bar; super; end
|
||||
end
|
||||
|
||||
mod = Module.new do
|
||||
def foo; :fooo; end
|
||||
end
|
||||
|
||||
child.new.foo
|
||||
child.new.bar
|
||||
|
||||
child.prepend(mod)
|
||||
|
||||
child.new.bar.should == :bar
|
||||
end
|
||||
|
||||
describe "on Class" do
|
||||
it "is undefined" do
|
||||
Class.should_not have_private_instance_method(:prepend_features, true)
|
||||
end
|
||||
|
||||
it "raises a TypeError if calling after rebinded to Class" do
|
||||
lambda {
|
||||
Module.instance_method(:prepend_features).bind(Class.new).call Module.new
|
||||
}.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
end
|
||||
361
spec/ruby/core/module/prepend_spec.rb
Normal file
361
spec/ruby/core/module/prepend_spec.rb
Normal file
|
|
@ -0,0 +1,361 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#prepend" do
|
||||
it "is a public method" do
|
||||
Module.should have_public_instance_method(:prepend, false)
|
||||
end
|
||||
|
||||
it "does not affect the superclass" do
|
||||
Class.new { prepend Module.new }.superclass.should == Object
|
||||
end
|
||||
|
||||
it "calls #prepend_features(self) in reversed order on each module" do
|
||||
ScratchPad.record []
|
||||
|
||||
m = Module.new do
|
||||
def self.prepend_features(mod)
|
||||
ScratchPad << [ self, mod ]
|
||||
end
|
||||
end
|
||||
|
||||
m2 = Module.new do
|
||||
def self.prepend_features(mod)
|
||||
ScratchPad << [ self, mod ]
|
||||
end
|
||||
end
|
||||
|
||||
m3 = Module.new do
|
||||
def self.prepend_features(mod)
|
||||
ScratchPad << [ self, mod ]
|
||||
end
|
||||
end
|
||||
|
||||
c = Class.new { prepend(m, m2, m3) }
|
||||
|
||||
ScratchPad.recorded.should == [ [ m3, c], [ m2, c ], [ m, c ] ]
|
||||
end
|
||||
|
||||
it "raises a TypeError when the argument is not a Module" do
|
||||
lambda { ModuleSpecs::Basic.prepend(Class.new) }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "does not raise a TypeError when the argument is an instance of a subclass of Module" do
|
||||
lambda { ModuleSpecs::SubclassSpec.prepend(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "imports constants" do
|
||||
m1 = Module.new
|
||||
m1::MY_CONSTANT = 1
|
||||
m2 = Module.new { prepend(m1) }
|
||||
m2.constants.should include(:MY_CONSTANT)
|
||||
end
|
||||
|
||||
it "imports instance methods" do
|
||||
Module.new { prepend ModuleSpecs::A }.instance_methods.should include(:ma)
|
||||
end
|
||||
|
||||
it "does not import methods to modules and classes" do
|
||||
Module.new { prepend ModuleSpecs::A }.methods.should_not include(:ma)
|
||||
end
|
||||
|
||||
it "allows wrapping methods" do
|
||||
m = Module.new { def calc(x) super + 3 end }
|
||||
c = Class.new { def calc(x) x*2 end }
|
||||
c.prepend(m)
|
||||
c.new.calc(1).should == 5
|
||||
end
|
||||
|
||||
it "also prepends included modules" do
|
||||
a = Module.new { def calc(x) x end }
|
||||
b = Module.new { include a }
|
||||
c = Class.new { prepend b }
|
||||
c.new.calc(1).should == 1
|
||||
end
|
||||
|
||||
it "prepends multiple modules in the right order" do
|
||||
m1 = Module.new { def chain; super << :m1; end }
|
||||
m2 = Module.new { def chain; super << :m2; end; prepend(m1) }
|
||||
c = Class.new { def chain; [:c]; end; prepend(m2) }
|
||||
c.new.chain.should == [:c, :m2, :m1]
|
||||
end
|
||||
|
||||
it "includes prepended modules in ancestors" do
|
||||
m = Module.new
|
||||
Class.new { prepend(m) }.ancestors.should include(m)
|
||||
end
|
||||
|
||||
it "reports the prepended module as the method owner" do
|
||||
m = Module.new { def meth; end }
|
||||
c = Class.new { def meth; end; prepend(m) }
|
||||
c.new.method(:meth).owner.should == m
|
||||
end
|
||||
|
||||
it "reports the prepended module as the unbound method owner" do
|
||||
m = Module.new { def meth; end }
|
||||
c = Class.new { def meth; end; prepend(m) }
|
||||
c.instance_method(:meth).owner.should == m
|
||||
c.public_instance_method(:meth).owner.should == m
|
||||
end
|
||||
|
||||
it "causes the prepended module's method to be aliased by alias_method" do
|
||||
m = Module.new { def meth; :m end }
|
||||
c = Class.new { def meth; :c end; prepend(m); alias_method :alias, :meth }
|
||||
c.new.alias.should == :m
|
||||
end
|
||||
|
||||
it "sees an instance of a prepended class as kind of the prepended module" do
|
||||
m = Module.new
|
||||
c = Class.new { prepend(m) }
|
||||
c.new.should be_kind_of(m)
|
||||
end
|
||||
|
||||
it "keeps the module in the chain when dupping the class" do
|
||||
m = Module.new
|
||||
c = Class.new { prepend(m) }
|
||||
c.dup.new.should be_kind_of(m)
|
||||
end
|
||||
|
||||
it "keeps the module in the chain when dupping an intermediate module" do
|
||||
m1 = Module.new { def calc(x) x end }
|
||||
m2 = Module.new { prepend(m1) }
|
||||
c1 = Class.new { prepend(m2) }
|
||||
m2dup = m2.dup
|
||||
m2dup.ancestors.should == [m2dup,m1,m2]
|
||||
c2 = Class.new { prepend(m2dup) }
|
||||
c1.ancestors[0,3].should == [m1,m2,c1]
|
||||
c1.new.should be_kind_of(m1)
|
||||
c2.ancestors[0,4].should == [m2dup,m1,m2,c2]
|
||||
c2.new.should be_kind_of(m1)
|
||||
end
|
||||
|
||||
it "depends on prepend_features to add the module" do
|
||||
m = Module.new { def self.prepend_features(mod) end }
|
||||
Class.new { prepend(m) }.ancestors.should_not include(m)
|
||||
end
|
||||
|
||||
it "adds the module in the subclass chains" do
|
||||
parent = Class.new { def chain; [:parent]; end }
|
||||
child = Class.new(parent) { def chain; super << :child; end }
|
||||
mod = Module.new { def chain; super << :mod; end }
|
||||
parent.prepend(mod)
|
||||
parent.ancestors[0,2].should == [mod, parent]
|
||||
child.ancestors[0,3].should == [child, mod, parent]
|
||||
|
||||
parent.new.chain.should == [:parent, :mod]
|
||||
child.new.chain.should == [:parent, :mod, :child]
|
||||
end
|
||||
|
||||
it "inserts a later prepended module into the chain" do
|
||||
m1 = Module.new { def chain; super << :m1; end }
|
||||
m2 = Module.new { def chain; super << :m2; end }
|
||||
c1 = Class.new { def chain; [:c1]; end; prepend m1 }
|
||||
c2 = Class.new(c1) { def chain; super << :c2; end }
|
||||
c2.new.chain.should == [:c1, :m1, :c2]
|
||||
c1.prepend(m2)
|
||||
c2.new.chain.should == [:c1, :m1, :m2, :c2]
|
||||
end
|
||||
|
||||
it "works with subclasses" do
|
||||
m = Module.new do
|
||||
def chain
|
||||
super << :module
|
||||
end
|
||||
end
|
||||
|
||||
c = Class.new do
|
||||
prepend m
|
||||
def chain
|
||||
[:class]
|
||||
end
|
||||
end
|
||||
|
||||
s = Class.new(c) do
|
||||
def chain
|
||||
super << :subclass
|
||||
end
|
||||
end
|
||||
|
||||
s.new.chain.should == [:class, :module, :subclass]
|
||||
end
|
||||
|
||||
it "throws a NoMethodError when there is no more superclass" do
|
||||
m = Module.new do
|
||||
def chain
|
||||
super << :module
|
||||
end
|
||||
end
|
||||
|
||||
c = Class.new do
|
||||
prepend m
|
||||
def chain
|
||||
super << :class
|
||||
end
|
||||
end
|
||||
lambda { c.new.chain }.should raise_error(NoMethodError)
|
||||
end
|
||||
|
||||
it "calls prepended after prepend_features" do
|
||||
ScratchPad.record []
|
||||
|
||||
m = Module.new do
|
||||
def self.prepend_features(klass)
|
||||
ScratchPad << [:prepend_features, klass]
|
||||
end
|
||||
def self.prepended(klass)
|
||||
ScratchPad << [:prepended, klass]
|
||||
end
|
||||
end
|
||||
|
||||
c = Class.new { prepend(m) }
|
||||
ScratchPad.recorded.should == [[:prepend_features, c], [:prepended, c]]
|
||||
end
|
||||
|
||||
it "detects cyclic prepends" do
|
||||
lambda {
|
||||
module ModuleSpecs::P
|
||||
prepend ModuleSpecs::P
|
||||
end
|
||||
}.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
ruby_version_is ''...'2.4' do
|
||||
it "accepts no-arguments" do
|
||||
lambda {
|
||||
Module.new do
|
||||
prepend
|
||||
end
|
||||
}.should_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is '2.4' do
|
||||
it "doesn't accept no-arguments" do
|
||||
lambda {
|
||||
Module.new do
|
||||
prepend
|
||||
end
|
||||
}.should raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
it "returns the class it's included into" do
|
||||
m = Module.new
|
||||
r = nil
|
||||
c = Class.new { r = prepend m }
|
||||
r.should == c
|
||||
end
|
||||
|
||||
it "clears any caches" do
|
||||
module ModuleSpecs::M3
|
||||
module PM1
|
||||
def foo
|
||||
:m1
|
||||
end
|
||||
end
|
||||
|
||||
module PM2
|
||||
def foo
|
||||
:m2
|
||||
end
|
||||
end
|
||||
|
||||
klass = Class.new do
|
||||
prepend PM1
|
||||
|
||||
def get
|
||||
foo
|
||||
end
|
||||
end
|
||||
|
||||
o = klass.new
|
||||
o.get.should == :m1
|
||||
|
||||
klass.class_eval do
|
||||
prepend PM2
|
||||
end
|
||||
|
||||
o.get.should == :m2
|
||||
end
|
||||
end
|
||||
|
||||
it "supports super when the module is prepended into a singleton class" do
|
||||
ScratchPad.record []
|
||||
|
||||
mod = Module.new do
|
||||
def self.inherited(base)
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
module_with_singleton_class_prepend = Module.new do
|
||||
singleton_class.prepend(mod)
|
||||
end
|
||||
|
||||
klass = Class.new(ModuleSpecs::RecordIncludedModules) do
|
||||
include module_with_singleton_class_prepend
|
||||
end
|
||||
|
||||
ScratchPad.recorded.should == klass
|
||||
end
|
||||
|
||||
it "supports super when the module is prepended into a singleton class with a class super" do
|
||||
ScratchPad.record []
|
||||
|
||||
base_class = Class.new(ModuleSpecs::RecordIncludedModules) do
|
||||
def self.inherited(base)
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
prepended_module = Module.new
|
||||
base_class.singleton_class.prepend(prepended_module)
|
||||
|
||||
child_class = Class.new(base_class)
|
||||
ScratchPad.recorded.should == child_class
|
||||
end
|
||||
|
||||
it "does not interfere with a define_method super in the original class" do
|
||||
base_class = Class.new do
|
||||
def foo(ary)
|
||||
ary << 1
|
||||
end
|
||||
end
|
||||
|
||||
child_class = Class.new(base_class) do
|
||||
define_method :foo do |ary|
|
||||
ary << 2
|
||||
super(ary)
|
||||
end
|
||||
end
|
||||
|
||||
prep_mod = Module.new do
|
||||
def foo(ary)
|
||||
ary << 3
|
||||
super(ary)
|
||||
end
|
||||
end
|
||||
|
||||
child_class.prepend(prep_mod)
|
||||
|
||||
ary = []
|
||||
child_class.new.foo(ary)
|
||||
ary.should == [3, 2, 1]
|
||||
end
|
||||
|
||||
describe "called on a module" do
|
||||
describe "included into a class"
|
||||
it "does not obscure the module's methods from reflective access" do
|
||||
mod = Module.new do
|
||||
def foo; end
|
||||
end
|
||||
cls = Class.new do
|
||||
include mod
|
||||
end
|
||||
pre = Module.new
|
||||
mod.prepend pre
|
||||
|
||||
cls.instance_methods.should include(:foo)
|
||||
end
|
||||
end
|
||||
end
|
||||
25
spec/ruby/core/module/prepended_spec.rb
Normal file
25
spec/ruby/core/module/prepended_spec.rb
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# -*- encoding: us-ascii -*-
|
||||
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
|
||||
describe "Module#prepended" do
|
||||
before :each do
|
||||
ScratchPad.clear
|
||||
end
|
||||
|
||||
it "is a private method" do
|
||||
Module.should have_private_instance_method(:prepended, true)
|
||||
end
|
||||
|
||||
it "is invoked when self is prepended to another module or class" do
|
||||
m = Module.new do
|
||||
def self.prepended(o)
|
||||
ScratchPad.record o
|
||||
end
|
||||
end
|
||||
|
||||
c = Class.new { prepend m }
|
||||
|
||||
ScratchPad.recorded.should == c
|
||||
end
|
||||
end
|
||||
81
spec/ruby/core/module/private_class_method_spec.rb
Normal file
81
spec/ruby/core/module/private_class_method_spec.rb
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#private_class_method" do
|
||||
before :each do
|
||||
# This is not in classes.rb because after marking a class method private it
|
||||
# will stay private.
|
||||
class << ModuleSpecs::Parent
|
||||
public
|
||||
def private_method_1; end
|
||||
def private_method_2; end
|
||||
end
|
||||
end
|
||||
|
||||
after :each do
|
||||
class << ModuleSpecs::Parent
|
||||
remove_method :private_method_1
|
||||
remove_method :private_method_2
|
||||
end
|
||||
end
|
||||
|
||||
it "makes an existing class method private" do
|
||||
ModuleSpecs::Parent.private_method_1.should == nil
|
||||
ModuleSpecs::Parent.private_class_method :private_method_1
|
||||
lambda { ModuleSpecs::Parent.private_method_1 }.should raise_error(NoMethodError)
|
||||
|
||||
# Technically above we're testing the Singleton classes, class method(right?).
|
||||
# Try a "real" class method set private.
|
||||
lambda { ModuleSpecs::Parent.private_method }.should raise_error(NoMethodError)
|
||||
end
|
||||
|
||||
it "makes an existing class method private up the inheritance tree" do
|
||||
ModuleSpecs::Child.public_class_method :private_method_1
|
||||
ModuleSpecs::Child.private_method_1.should == nil
|
||||
ModuleSpecs::Child.private_class_method :private_method_1
|
||||
|
||||
lambda { ModuleSpecs::Child.private_method_1 }.should raise_error(NoMethodError)
|
||||
lambda { ModuleSpecs::Child.private_method }.should raise_error(NoMethodError)
|
||||
end
|
||||
|
||||
it "accepts more than one method at a time" do
|
||||
ModuleSpecs::Parent.private_method_1.should == nil
|
||||
ModuleSpecs::Parent.private_method_2.should == nil
|
||||
|
||||
ModuleSpecs::Child.private_class_method :private_method_1, :private_method_2
|
||||
|
||||
lambda { ModuleSpecs::Child.private_method_1 }.should raise_error(NoMethodError)
|
||||
lambda { ModuleSpecs::Child.private_method_2 }.should raise_error(NoMethodError)
|
||||
end
|
||||
|
||||
it "raises a NameError if class method doesn't exist" do
|
||||
lambda do
|
||||
ModuleSpecs.private_class_method :no_method_here
|
||||
end.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "makes a class method private" do
|
||||
c = Class.new do
|
||||
def self.foo() "foo" end
|
||||
private_class_method :foo
|
||||
end
|
||||
lambda { c.foo }.should raise_error(NoMethodError)
|
||||
end
|
||||
|
||||
it "raises a NameError when the given name is not a method" do
|
||||
lambda do
|
||||
Class.new do
|
||||
private_class_method :foo
|
||||
end
|
||||
end.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a NameError when the given name is an instance method" do
|
||||
lambda do
|
||||
Class.new do
|
||||
def foo() "foo" end
|
||||
private_class_method :foo
|
||||
end
|
||||
end.should raise_error(NameError)
|
||||
end
|
||||
end
|
||||
32
spec/ruby/core/module/private_constant_spec.rb
Normal file
32
spec/ruby/core/module/private_constant_spec.rb
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
|
||||
describe "Module#private_constant" do
|
||||
it "can only be passed constant names defined in the target (self) module" do
|
||||
cls1 = Class.new
|
||||
cls1.const_set :Foo, true
|
||||
cls2 = Class.new(cls1)
|
||||
|
||||
lambda do
|
||||
cls2.send :private_constant, :Foo
|
||||
end.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "accepts strings as constant names" do
|
||||
cls = Class.new
|
||||
cls.const_set :Foo, true
|
||||
cls.send :private_constant, "Foo"
|
||||
|
||||
lambda { cls::Foo }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "accepts multiple names" do
|
||||
mod = Module.new
|
||||
mod.const_set :Foo, true
|
||||
mod.const_set :Bar, true
|
||||
|
||||
mod.send :private_constant, :Foo, :Bar
|
||||
|
||||
lambda {mod::Foo}.should raise_error(NameError)
|
||||
lambda {mod::Bar}.should raise_error(NameError)
|
||||
end
|
||||
end
|
||||
54
spec/ruby/core/module/private_instance_methods_spec.rb
Normal file
54
spec/ruby/core/module/private_instance_methods_spec.rb
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
require File.expand_path('../../../fixtures/reflection', __FILE__)
|
||||
|
||||
# TODO: rewrite
|
||||
describe "Module#private_instance_methods" do
|
||||
it "returns a list of private methods in module and its ancestors" do
|
||||
ModuleSpecs::CountsMixin.should have_private_instance_method(:private_3)
|
||||
|
||||
ModuleSpecs::CountsParent.should have_private_instance_method(:private_2)
|
||||
ModuleSpecs::CountsParent.should have_private_instance_method(:private_3)
|
||||
|
||||
ModuleSpecs::CountsChild.should have_private_instance_method(:private_1)
|
||||
ModuleSpecs::CountsChild.should have_private_instance_method(:private_2)
|
||||
ModuleSpecs::CountsChild.should have_private_instance_method(:private_3)
|
||||
end
|
||||
|
||||
it "when passed false as a parameter, should return only methods defined in that module" do
|
||||
ModuleSpecs::CountsMixin.should have_private_instance_method(:private_3, false)
|
||||
ModuleSpecs::CountsParent.should have_private_instance_method(:private_2, false)
|
||||
ModuleSpecs::CountsChild.should have_private_instance_method(:private_1, false)
|
||||
end
|
||||
|
||||
it "default list should be the same as passing true as an argument" do
|
||||
ModuleSpecs::CountsMixin.private_instance_methods(true).should ==
|
||||
ModuleSpecs::CountsMixin.private_instance_methods
|
||||
ModuleSpecs::CountsParent.private_instance_methods(true).should ==
|
||||
ModuleSpecs::CountsParent.private_instance_methods
|
||||
ModuleSpecs::CountsChild.private_instance_methods(true).should ==
|
||||
ModuleSpecs::CountsChild.private_instance_methods
|
||||
end
|
||||
end
|
||||
|
||||
describe :module_private_instance_methods_supers, shared: true do
|
||||
it "returns a unique list for a class including a module" do
|
||||
m = ReflectSpecs::D.private_instance_methods(*@object)
|
||||
m.select { |x| x == :pri }.sort.should == [:pri]
|
||||
end
|
||||
|
||||
it "returns a unique list for a subclass" do
|
||||
m = ReflectSpecs::E.private_instance_methods(*@object)
|
||||
m.select { |x| x == :pri }.sort.should == [:pri]
|
||||
end
|
||||
end
|
||||
|
||||
describe "Module#private_instance_methods" do
|
||||
describe "when not passed an argument" do
|
||||
it_behaves_like :module_private_instance_methods_supers, nil, []
|
||||
end
|
||||
|
||||
describe "when passed true" do
|
||||
it_behaves_like :module_private_instance_methods_supers, nil, true
|
||||
end
|
||||
end
|
||||
72
spec/ruby/core/module/private_method_defined_spec.rb
Normal file
72
spec/ruby/core/module/private_method_defined_spec.rb
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#private_method_defined?" do
|
||||
it "returns true if the named private method is defined by module or its ancestors" do
|
||||
ModuleSpecs::CountsMixin.private_method_defined?("private_3").should == true
|
||||
|
||||
ModuleSpecs::CountsParent.private_method_defined?("private_3").should == true
|
||||
ModuleSpecs::CountsParent.private_method_defined?("private_2").should == true
|
||||
|
||||
ModuleSpecs::CountsChild.private_method_defined?("private_3").should == true
|
||||
ModuleSpecs::CountsChild.private_method_defined?("private_2").should == true
|
||||
ModuleSpecs::CountsChild.private_method_defined?("private_1").should == true
|
||||
end
|
||||
|
||||
it "returns false if method is not a private method" do
|
||||
ModuleSpecs::CountsChild.private_method_defined?("public_3").should == false
|
||||
ModuleSpecs::CountsChild.private_method_defined?("public_2").should == false
|
||||
ModuleSpecs::CountsChild.private_method_defined?("public_1").should == false
|
||||
|
||||
ModuleSpecs::CountsChild.private_method_defined?("protected_3").should == false
|
||||
ModuleSpecs::CountsChild.private_method_defined?("protected_2").should == false
|
||||
ModuleSpecs::CountsChild.private_method_defined?("protected_1").should == false
|
||||
end
|
||||
|
||||
it "returns false if the named method is not defined by the module or its ancestors" do
|
||||
ModuleSpecs::CountsMixin.private_method_defined?(:private_10).should == false
|
||||
end
|
||||
|
||||
it "accepts symbols for the method name" do
|
||||
ModuleSpecs::CountsMixin.private_method_defined?(:private_3).should == true
|
||||
end
|
||||
|
||||
it "raises a TypeError if passed a Fixnum" do
|
||||
lambda do
|
||||
ModuleSpecs::CountsMixin.private_method_defined?(1)
|
||||
end.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "raises a TypeError if passed nil" do
|
||||
lambda do
|
||||
ModuleSpecs::CountsMixin.private_method_defined?(nil)
|
||||
end.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "raises a TypeError if passed false" do
|
||||
lambda do
|
||||
ModuleSpecs::CountsMixin.private_method_defined?(false)
|
||||
end.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "raises a TypeError if passed an object that does not defined #to_str" do
|
||||
lambda do
|
||||
ModuleSpecs::CountsMixin.private_method_defined?(mock('x'))
|
||||
end.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "raises a TypeError if passed an object that defines #to_sym" do
|
||||
sym = mock('symbol')
|
||||
def sym.to_sym() :private_3 end
|
||||
|
||||
lambda do
|
||||
ModuleSpecs::CountsMixin.private_method_defined?(sym)
|
||||
end.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "calls #to_str to convert an Object" do
|
||||
str = mock('string')
|
||||
def str.to_str() 'private_3' end
|
||||
ModuleSpecs::CountsMixin.private_method_defined?(str).should == true
|
||||
end
|
||||
end
|
||||
54
spec/ruby/core/module/private_spec.rb
Normal file
54
spec/ruby/core/module/private_spec.rb
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
require File.expand_path('../shared/set_visibility', __FILE__)
|
||||
|
||||
describe "Module#private" do
|
||||
it_behaves_like :set_visibility, :private
|
||||
|
||||
it "makes the target method uncallable from other types" do
|
||||
obj = Object.new
|
||||
class << obj
|
||||
def foo; true; end
|
||||
end
|
||||
|
||||
obj.foo.should == true
|
||||
|
||||
class << obj
|
||||
private :foo
|
||||
end
|
||||
|
||||
lambda { obj.foo }.should raise_error(NoMethodError)
|
||||
end
|
||||
|
||||
it "makes a public Object instance method private in a new module" do
|
||||
m = Module.new do
|
||||
private :module_specs_public_method_on_object
|
||||
end
|
||||
|
||||
m.should have_private_instance_method(:module_specs_public_method_on_object)
|
||||
|
||||
# Ensure we did not change Object's method
|
||||
Object.should_not have_private_instance_method(:module_specs_public_method_on_object)
|
||||
end
|
||||
|
||||
it "makes a public Object instance method private in Kernel" do
|
||||
Kernel.should have_private_instance_method(
|
||||
:module_specs_public_method_on_object_for_kernel_private)
|
||||
Object.should_not have_private_instance_method(
|
||||
:module_specs_public_method_on_object_for_kernel_private)
|
||||
end
|
||||
|
||||
it "returns self" do
|
||||
(class << Object.new; self; end).class_eval do
|
||||
def foo; end
|
||||
private(:foo).should equal(self)
|
||||
private.should equal(self)
|
||||
end
|
||||
end
|
||||
|
||||
it "raises a NameError when given an undefined name" do
|
||||
lambda do
|
||||
Module.new.send(:private, :undefined)
|
||||
end.should raise_error(NameError)
|
||||
end
|
||||
end
|
||||
57
spec/ruby/core/module/protected_instance_methods_spec.rb
Normal file
57
spec/ruby/core/module/protected_instance_methods_spec.rb
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
require File.expand_path('../../../fixtures/reflection', __FILE__)
|
||||
|
||||
# TODO: rewrite
|
||||
describe "Module#protected_instance_methods" do
|
||||
it "returns a list of protected methods in module and its ancestors" do
|
||||
methods = ModuleSpecs::CountsMixin.protected_instance_methods
|
||||
methods.should include(:protected_3)
|
||||
|
||||
methods = ModuleSpecs::CountsParent.protected_instance_methods
|
||||
methods.should include(:protected_3)
|
||||
methods.should include(:protected_2)
|
||||
|
||||
methods = ModuleSpecs::CountsChild.protected_instance_methods
|
||||
methods.should include(:protected_3)
|
||||
methods.should include(:protected_2)
|
||||
methods.should include(:protected_1)
|
||||
end
|
||||
|
||||
it "when passed false as a parameter, should return only methods defined in that module" do
|
||||
ModuleSpecs::CountsMixin.protected_instance_methods(false).should == [:protected_3]
|
||||
ModuleSpecs::CountsParent.protected_instance_methods(false).should == [:protected_2]
|
||||
ModuleSpecs::CountsChild.protected_instance_methods(false).should == [:protected_1]
|
||||
end
|
||||
|
||||
it "default list should be the same as passing true as an argument" do
|
||||
ModuleSpecs::CountsMixin.protected_instance_methods(true).should ==
|
||||
ModuleSpecs::CountsMixin.protected_instance_methods
|
||||
ModuleSpecs::CountsParent.protected_instance_methods(true).should ==
|
||||
ModuleSpecs::CountsParent.protected_instance_methods
|
||||
ModuleSpecs::CountsChild.protected_instance_methods(true).should ==
|
||||
ModuleSpecs::CountsChild.protected_instance_methods
|
||||
end
|
||||
end
|
||||
|
||||
describe :module_protected_instance_methods_supers, shared: true do
|
||||
it "returns a unique list for a class including a module" do
|
||||
m = ReflectSpecs::D.protected_instance_methods(*@object)
|
||||
m.select { |x| x == :pro }.sort.should == [:pro]
|
||||
end
|
||||
|
||||
it "returns a unique list for a subclass" do
|
||||
m = ReflectSpecs::E.protected_instance_methods(*@object)
|
||||
m.select { |x| x == :pro }.sort.should == [:pro]
|
||||
end
|
||||
end
|
||||
|
||||
describe "Module#protected_instance_methods" do
|
||||
describe "when not passed an argument" do
|
||||
it_behaves_like :module_protected_instance_methods_supers, nil, []
|
||||
end
|
||||
|
||||
describe "when passed true" do
|
||||
it_behaves_like :module_protected_instance_methods_supers, nil, true
|
||||
end
|
||||
end
|
||||
72
spec/ruby/core/module/protected_method_defined_spec.rb
Normal file
72
spec/ruby/core/module/protected_method_defined_spec.rb
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#protected_method_defined?" do
|
||||
it "returns true if the named protected method is defined by module or its ancestors" do
|
||||
ModuleSpecs::CountsMixin.protected_method_defined?("protected_3").should == true
|
||||
|
||||
ModuleSpecs::CountsParent.protected_method_defined?("protected_3").should == true
|
||||
ModuleSpecs::CountsParent.protected_method_defined?("protected_2").should == true
|
||||
|
||||
ModuleSpecs::CountsChild.protected_method_defined?("protected_3").should == true
|
||||
ModuleSpecs::CountsChild.protected_method_defined?("protected_2").should == true
|
||||
ModuleSpecs::CountsChild.protected_method_defined?("protected_1").should == true
|
||||
end
|
||||
|
||||
it "returns false if method is not a protected method" do
|
||||
ModuleSpecs::CountsChild.protected_method_defined?("public_3").should == false
|
||||
ModuleSpecs::CountsChild.protected_method_defined?("public_2").should == false
|
||||
ModuleSpecs::CountsChild.protected_method_defined?("public_1").should == false
|
||||
|
||||
ModuleSpecs::CountsChild.protected_method_defined?("private_3").should == false
|
||||
ModuleSpecs::CountsChild.protected_method_defined?("private_2").should == false
|
||||
ModuleSpecs::CountsChild.protected_method_defined?("private_1").should == false
|
||||
end
|
||||
|
||||
it "returns false if the named method is not defined by the module or its ancestors" do
|
||||
ModuleSpecs::CountsMixin.protected_method_defined?(:protected_10).should == false
|
||||
end
|
||||
|
||||
it "accepts symbols for the method name" do
|
||||
ModuleSpecs::CountsMixin.protected_method_defined?(:protected_3).should == true
|
||||
end
|
||||
|
||||
it "raises a TypeError if passed a Fixnum" do
|
||||
lambda do
|
||||
ModuleSpecs::CountsMixin.protected_method_defined?(1)
|
||||
end.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "raises a TypeError if passed nil" do
|
||||
lambda do
|
||||
ModuleSpecs::CountsMixin.protected_method_defined?(nil)
|
||||
end.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "raises a TypeError if passed false" do
|
||||
lambda do
|
||||
ModuleSpecs::CountsMixin.protected_method_defined?(false)
|
||||
end.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "raises a TypeError if passed an object that does not defined #to_str" do
|
||||
lambda do
|
||||
ModuleSpecs::CountsMixin.protected_method_defined?(mock('x'))
|
||||
end.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "raises a TypeError if passed an object that defines #to_sym" do
|
||||
sym = mock('symbol')
|
||||
def sym.to_sym() :protected_3 end
|
||||
|
||||
lambda do
|
||||
ModuleSpecs::CountsMixin.protected_method_defined?(sym)
|
||||
end.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "calls #to_str to convert an Object" do
|
||||
str = mock('protected_3')
|
||||
str.should_receive(:to_str).and_return("protected_3")
|
||||
ModuleSpecs::CountsMixin.protected_method_defined?(str).should == true
|
||||
end
|
||||
end
|
||||
56
spec/ruby/core/module/protected_spec.rb
Normal file
56
spec/ruby/core/module/protected_spec.rb
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
require File.expand_path('../shared/set_visibility', __FILE__)
|
||||
|
||||
describe "Module#protected" do
|
||||
before :each do
|
||||
class << ModuleSpecs::Parent
|
||||
def protected_method_1; 5; end
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like :set_visibility, :protected
|
||||
|
||||
it "makes an existing class method protected" do
|
||||
ModuleSpecs::Parent.protected_method_1.should == 5
|
||||
|
||||
class << ModuleSpecs::Parent
|
||||
protected :protected_method_1
|
||||
end
|
||||
|
||||
lambda { ModuleSpecs::Parent.protected_method_1 }.should raise_error(NoMethodError)
|
||||
end
|
||||
|
||||
it "makes a public Object instance method protected in a new module" do
|
||||
m = Module.new do
|
||||
protected :module_specs_public_method_on_object
|
||||
end
|
||||
|
||||
m.should have_protected_instance_method(:module_specs_public_method_on_object)
|
||||
|
||||
# Ensure we did not change Object's method
|
||||
Object.should_not have_protected_instance_method(:module_specs_public_method_on_object)
|
||||
end
|
||||
|
||||
it "makes a public Object instance method protected in Kernel" do
|
||||
Kernel.should have_protected_instance_method(
|
||||
:module_specs_public_method_on_object_for_kernel_protected)
|
||||
Object.should_not have_protected_instance_method(
|
||||
:module_specs_public_method_on_object_for_kernel_protected)
|
||||
end
|
||||
|
||||
it "returns self" do
|
||||
(class << Object.new; self; end).class_eval do
|
||||
def foo; end
|
||||
protected(:foo).should equal(self)
|
||||
protected.should equal(self)
|
||||
end
|
||||
end
|
||||
|
||||
it "raises a NameError when given an undefined name" do
|
||||
lambda do
|
||||
Module.new.send(:protected, :undefined)
|
||||
end.should raise_error(NameError)
|
||||
end
|
||||
end
|
||||
|
||||
80
spec/ruby/core/module/public_class_method_spec.rb
Normal file
80
spec/ruby/core/module/public_class_method_spec.rb
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#public_class_method" do
|
||||
before :each do
|
||||
class << ModuleSpecs::Parent
|
||||
private
|
||||
def public_method_1; end
|
||||
def public_method_2; end
|
||||
end
|
||||
end
|
||||
|
||||
after :each do
|
||||
class << ModuleSpecs::Parent
|
||||
remove_method :public_method_1
|
||||
remove_method :public_method_2
|
||||
end
|
||||
end
|
||||
|
||||
it "makes an existing class method public" do
|
||||
lambda { ModuleSpecs::Parent.public_method_1 }.should raise_error(NoMethodError)
|
||||
ModuleSpecs::Parent.public_class_method :public_method_1
|
||||
ModuleSpecs::Parent.public_method_1.should == nil
|
||||
|
||||
# Technically above we're testing the Singleton classes, class method(right?).
|
||||
# Try a "real" class method set public.
|
||||
ModuleSpecs::Parent.public_method.should == nil
|
||||
end
|
||||
|
||||
it "makes an existing class method public up the inheritance tree" do
|
||||
ModuleSpecs::Child.private_class_method :public_method_1
|
||||
lambda { ModuleSpecs::Child.public_method_1 }.should raise_error(NoMethodError)
|
||||
ModuleSpecs::Child.public_class_method :public_method_1
|
||||
|
||||
ModuleSpecs::Child.public_method_1.should == nil
|
||||
ModuleSpecs::Child.public_method.should == nil
|
||||
end
|
||||
|
||||
it "accepts more than one method at a time" do
|
||||
lambda { ModuleSpecs::Parent.public_method_1 }.should raise_error(NameError)
|
||||
lambda { ModuleSpecs::Parent.public_method_2 }.should raise_error(NameError)
|
||||
|
||||
ModuleSpecs::Child.public_class_method :public_method_1, :public_method_2
|
||||
|
||||
ModuleSpecs::Child.public_method_1.should == nil
|
||||
ModuleSpecs::Child.public_method_2.should == nil
|
||||
end
|
||||
|
||||
it "raises a NameError if class method doesn't exist" do
|
||||
lambda do
|
||||
ModuleSpecs.public_class_method :no_method_here
|
||||
end.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "makes a class method public" do
|
||||
c = Class.new do
|
||||
def self.foo() "foo" end
|
||||
public_class_method :foo
|
||||
end
|
||||
|
||||
c.foo.should == "foo"
|
||||
end
|
||||
|
||||
it "raises a NameError when the given name is not a method" do
|
||||
lambda do
|
||||
Class.new do
|
||||
public_class_method :foo
|
||||
end
|
||||
end.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a NameError when the given name is an instance method" do
|
||||
lambda do
|
||||
Class.new do
|
||||
def foo() "foo" end
|
||||
public_class_method :foo
|
||||
end
|
||||
end.should raise_error(NameError)
|
||||
end
|
||||
end
|
||||
38
spec/ruby/core/module/public_constant_spec.rb
Normal file
38
spec/ruby/core/module/public_constant_spec.rb
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
|
||||
describe "Module#public_constant" do
|
||||
it "can only be passed constant names defined in the target (self) module" do
|
||||
cls1 = Class.new
|
||||
cls1.const_set :Foo, true
|
||||
cls2 = Class.new(cls1)
|
||||
|
||||
lambda do
|
||||
cls2.send :public_constant, :Foo
|
||||
end.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "accepts strings as constant names" do
|
||||
cls = Class.new
|
||||
cls.const_set :Foo, true
|
||||
|
||||
cls.send :private_constant, :Foo
|
||||
cls.send :public_constant, "Foo"
|
||||
|
||||
cls::Foo.should == true
|
||||
end
|
||||
|
||||
# [ruby-list:48558]
|
||||
it "accepts multiple names" do
|
||||
mod = Module.new
|
||||
mod.const_set :Foo, true
|
||||
mod.const_set :Bar, true
|
||||
|
||||
mod.send :private_constant, :Foo
|
||||
mod.send :private_constant, :Bar
|
||||
|
||||
mod.send :public_constant, :Foo, :Bar
|
||||
|
||||
mod::Foo.should == true
|
||||
mod::Bar.should == true
|
||||
end
|
||||
end
|
||||
65
spec/ruby/core/module/public_instance_method_spec.rb
Normal file
65
spec/ruby/core/module/public_instance_method_spec.rb
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "Module#public_instance_method" do
|
||||
it "is a public method" do
|
||||
Module.should have_public_instance_method(:public_instance_method, false)
|
||||
end
|
||||
|
||||
it "requires an argument" do
|
||||
Module.new.method(:public_instance_method).arity.should == 1
|
||||
end
|
||||
|
||||
describe "when given a public method name" do
|
||||
it "returns an UnboundMethod corresponding to the defined Module" do
|
||||
ret = ModuleSpecs::Super.public_instance_method(:public_module)
|
||||
ret.should be_an_instance_of(UnboundMethod)
|
||||
ret.owner.should equal(ModuleSpecs::Basic)
|
||||
|
||||
ret = ModuleSpecs::Super.public_instance_method(:public_super_module)
|
||||
ret.should be_an_instance_of(UnboundMethod)
|
||||
ret.owner.should equal(ModuleSpecs::Super)
|
||||
end
|
||||
|
||||
it "accepts if the name is a Symbol or String" do
|
||||
ret = ModuleSpecs::Basic.public_instance_method(:public_module)
|
||||
ModuleSpecs::Basic.public_instance_method("public_module").should == ret
|
||||
end
|
||||
end
|
||||
|
||||
it "raises a TypeError when given a name is not Symbol or String" do
|
||||
lambda { Module.new.public_instance_method(nil) }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "raises a NameError when given a protected method name" do
|
||||
lambda do
|
||||
ModuleSpecs::Basic.public_instance_method(:protected_module)
|
||||
end.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a NameError if the method is private" do
|
||||
lambda do
|
||||
ModuleSpecs::Basic.public_instance_method(:private_module)
|
||||
end.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a NameError if the method has been undefined" do
|
||||
lambda do
|
||||
ModuleSpecs::Parent.public_instance_method(:undefed_method)
|
||||
end.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "raises a NameError if the method does not exist" do
|
||||
lambda do
|
||||
Module.new.public_instance_method(:missing)
|
||||
end.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "sets the NameError#name attribute to the name of the missing method" do
|
||||
begin
|
||||
Module.new.public_instance_method(:missing)
|
||||
rescue NameError => e
|
||||
e.name.should == :missing
|
||||
end
|
||||
end
|
||||
end
|
||||
61
spec/ruby/core/module/public_instance_methods_spec.rb
Normal file
61
spec/ruby/core/module/public_instance_methods_spec.rb
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
require File.expand_path('../../../fixtures/reflection', __FILE__)
|
||||
|
||||
# TODO: rewrite
|
||||
|
||||
describe "Module#public_instance_methods" do
|
||||
it "returns a list of public methods in module and its ancestors" do
|
||||
methods = ModuleSpecs::CountsMixin.public_instance_methods
|
||||
methods.should include(:public_3)
|
||||
|
||||
methods = ModuleSpecs::CountsParent.public_instance_methods
|
||||
methods.should include(:public_3)
|
||||
methods.should include(:public_2)
|
||||
|
||||
methods = ModuleSpecs::CountsChild.public_instance_methods
|
||||
methods.should include(:public_3)
|
||||
methods.should include(:public_2)
|
||||
methods.should include(:public_1)
|
||||
|
||||
methods = ModuleSpecs::Child2.public_instance_methods
|
||||
methods.should include(:foo)
|
||||
end
|
||||
|
||||
it "when passed false as a parameter, should return only methods defined in that module" do
|
||||
ModuleSpecs::CountsMixin.public_instance_methods(false).should == [:public_3]
|
||||
ModuleSpecs::CountsParent.public_instance_methods(false).should == [:public_2]
|
||||
ModuleSpecs::CountsChild.public_instance_methods(false).should == [:public_1]
|
||||
end
|
||||
|
||||
it "default list should be the same as passing true as an argument" do
|
||||
ModuleSpecs::CountsMixin.public_instance_methods(true).should ==
|
||||
ModuleSpecs::CountsMixin.public_instance_methods
|
||||
ModuleSpecs::CountsParent.public_instance_methods(true).should ==
|
||||
ModuleSpecs::CountsParent.public_instance_methods
|
||||
ModuleSpecs::CountsChild.public_instance_methods(true).should ==
|
||||
ModuleSpecs::CountsChild.public_instance_methods
|
||||
end
|
||||
end
|
||||
|
||||
describe :module_public_instance_methods_supers, shared: true do
|
||||
it "returns a unique list for a class including a module" do
|
||||
m = ReflectSpecs::D.public_instance_methods(*@object)
|
||||
m.select { |x| x == :pub }.sort.should == [:pub]
|
||||
end
|
||||
|
||||
it "returns a unique list for a subclass" do
|
||||
m = ReflectSpecs::E.public_instance_methods(*@object)
|
||||
m.select { |x| x == :pub }.sort.should == [:pub]
|
||||
end
|
||||
end
|
||||
|
||||
describe "Module#public_instance_methods" do
|
||||
describe "when not passed an argument" do
|
||||
it_behaves_like :module_public_instance_methods_supers, nil, []
|
||||
end
|
||||
|
||||
describe "when passed true" do
|
||||
it_behaves_like :module_public_instance_methods_supers, nil, true
|
||||
end
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue