File: //usr/local/rvm/src/ruby-2.5.9/spec/ruby/core/module/module_function_spec.rb
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