aboutsummaryrefslogtreecommitdiffstats
path: root/spec/ruby/core/module/autoload_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/core/module/autoload_spec.rb')
-rw-r--r--spec/ruby/core/module/autoload_spec.rb92
1 files changed, 69 insertions, 23 deletions
diff --git a/spec/ruby/core/module/autoload_spec.rb b/spec/ruby/core/module/autoload_spec.rb
index 224d5fd57b..918eb61764 100644
--- a/spec/ruby/core/module/autoload_spec.rb
+++ b/spec/ruby/core/module/autoload_spec.rb
@@ -16,17 +16,28 @@ end
describe "Module#autoload" do
before :all do
@non_existent = fixture __FILE__, "no_autoload.rb"
+
+ # Require RubyGems eagerly, to ensure #require is already the RubyGems
+ # version, before starting #autoload specs which snapshot #require, and
+ # could end up redefining #require as the original core Kernel#require.
+ begin
+ require "rubygems"
+ rescue LoadError
+ end
end
before :each do
@loaded_features = $".dup
- @frozen_module = Module.new.freeze
ScratchPad.clear
+ @remove = []
end
after :each do
$".replace @loaded_features
+ @remove.each { |const|
+ ModuleSpecs::Autoload.send :remove_const, const
+ }
end
it "registers a file to load the first time the named constant is accessed" do
@@ -39,16 +50,29 @@ describe "Module#autoload" do
ModuleSpecs::Autoload.should have_constant(:B)
end
+ it "can be overridden with a second autoload on the same constant" do
+ ModuleSpecs::Autoload.autoload :Overridden, @non_existent
+ @remove << :Overridden
+ ModuleSpecs::Autoload.autoload?(:Overridden).should == @non_existent
+
+ path = fixture(__FILE__, "autoload_overridden.rb")
+ ModuleSpecs::Autoload.autoload :Overridden, path
+ ModuleSpecs::Autoload.autoload?(:Overridden).should == path
+
+ ModuleSpecs::Autoload::Overridden.should == :overridden
+ 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")
+ @remove << :X
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
+ @remove << :DynClass
ScratchPad.recorded.should be_nil
ModuleSpecs::Autoload::DynClass::C.new.loaded.should == :dynclass_c
@@ -58,6 +82,7 @@ describe "Module#autoload" do
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
+ @remove << :DynModule
ScratchPad.recorded.should be_nil
ModuleSpecs::Autoload::DynModule::D.new.loaded.should == :dynmodule_d
@@ -95,6 +120,7 @@ describe "Module#autoload" do
it "does not load the file when the constant is already set" do
ModuleSpecs::Autoload.autoload :I, fixture(__FILE__, "autoload_i.rb")
+ @remove << :I
ModuleSpecs::Autoload.const_set :I, 3
ModuleSpecs::Autoload::I.should == 3
ScratchPad.recorded.should be_nil
@@ -116,6 +142,7 @@ describe "Module#autoload" do
it "does not load the file if the file is manually required" do
filename = fixture(__FILE__, "autoload_k.rb")
ModuleSpecs::Autoload.autoload :KHash, filename
+ @remove << :KHash
require filename
ScratchPad.recorded.should == :loaded
@@ -135,8 +162,8 @@ describe "Module#autoload" do
ScratchPad.clear
ModuleSpecs::Autoload.autoload :S, filename
+ @remove << :S
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
@@ -182,11 +209,10 @@ describe "Module#autoload" do
module ModuleSpecs::Autoload
autoload :GoodParent, fixture(__FILE__, "autoload_nested.rb")
end
+ @remove << :GoodParent
defined?(ModuleSpecs::Autoload::GoodParent::Nested).should == 'constant'
ScratchPad.recorded.should == :loaded
-
- ModuleSpecs::Autoload.send(:remove_const, :GoodParent)
end
it "returns nil when it fails to load an autoloaded parent when referencing a nested constant" do
@@ -199,11 +225,12 @@ describe "Module#autoload" do
end
end
- describe "the autoload is removed when the same file is required directly without autoload" do
+ describe "the autoload is triggered when the same file is required directly" do
before :each do
module ModuleSpecs::Autoload
autoload :RequiredDirectly, fixture(__FILE__, "autoload_required_directly.rb")
end
+ @remove << :RequiredDirectly
@path = fixture(__FILE__, "autoload_required_directly.rb")
@check = -> {
[
@@ -214,10 +241,6 @@ describe "Module#autoload" do
ScratchPad.record @check
end
- after :each do
- ModuleSpecs::Autoload.send(:remove_const, :RequiredDirectly)
- end
-
it "with a full path" do
@check.call.should == ["constant", @path]
require @path
@@ -242,7 +265,7 @@ describe "Module#autoload" do
nested_require = -> {
result = nil
ScratchPad.record -> {
- result = [@check.call, Thread.new { @check.call }.value]
+ result = @check.call
}
require nested
result
@@ -251,24 +274,41 @@ describe "Module#autoload" do
@check.call.should == ["constant", @path]
require @path
- cur, other = ScratchPad.recorded
- cur.should == [nil, nil]
- other.should == [nil, nil]
+ ScratchPad.recorded.should == [nil, nil]
@check.call.should == ["constant", nil]
end
end
+ describe "after the autoload is triggered by require" do
+ before :each do
+ @path = tmp("autoload.rb")
+ end
+
+ after :each do
+ rm_r @path
+ end
+
+ it "the mapping feature to autoload is removed, and a new autoload with the same path is considered" do
+ ModuleSpecs::Autoload.autoload :RequireMapping1, @path
+ touch(@path) { |f| f.puts "ModuleSpecs::Autoload::RequireMapping1 = 1" }
+ ModuleSpecs::Autoload::RequireMapping1.should == 1
+
+ $LOADED_FEATURES.delete(@path)
+ ModuleSpecs::Autoload.autoload :RequireMapping2, @path[0...-3]
+ @remove << :RequireMapping2
+ touch(@path) { |f| f.puts "ModuleSpecs::Autoload::RequireMapping2 = 2" }
+ ModuleSpecs::Autoload::RequireMapping2.should == 2
+ end
+ end
+
describe "during the autoload before the constant is assigned" do
before :each do
@path = fixture(__FILE__, "autoload_during_autoload.rb")
ModuleSpecs::Autoload.autoload :DuringAutoload, @path
+ @remove << :DuringAutoload
raise unless ModuleSpecs::Autoload.autoload?(:DuringAutoload) == @path
end
- after :each do
- ModuleSpecs::Autoload.send(:remove_const, :DuringAutoload)
- end
-
def check_before_during_thread_after(&check)
before = check.call
to_autoload_thread, from_autoload_thread = Queue.new, Queue.new
@@ -419,6 +459,7 @@ describe "Module#autoload" do
X = get_value
end
end
+ @remove << :U
ModuleSpecs::Autoload::U::V::X.should == :autoload_uvx
end
@@ -474,6 +515,7 @@ describe "Module#autoload" do
end
it "and fails when finding the undefined autoload constant in the the current scope when declared in current and defined in parent" do
+ @remove << :DeclaredInCurrentDefinedInParent
module ModuleSpecs::Autoload
ScratchPad.record -> {
DeclaredInCurrentDefinedInParent = :declared_in_current_defined_in_parent
@@ -494,6 +536,7 @@ describe "Module#autoload" do
end
it "in the included modules" do
+ @remove << :DefinedInIncludedModule
module ModuleSpecs::Autoload
ScratchPad.record -> {
module DefinedInIncludedModule
@@ -507,6 +550,7 @@ describe "Module#autoload" do
end
it "in the included modules of the superclass" do
+ @remove << :DefinedInSuperclassIncludedModule
module ModuleSpecs::Autoload
class LookupAfterAutoloadSuper
end
@@ -528,6 +572,7 @@ describe "Module#autoload" do
end
it "in the prepended modules" do
+ @remove << :DefinedInPrependedModule
module ModuleSpecs::Autoload
ScratchPad.record -> {
module DefinedInPrependedModule
@@ -567,10 +612,10 @@ describe "Module#autoload" do
end
end
end
+ @remove << :W
ModuleSpecs::Autoload::W::Y.should be_kind_of(Class)
ScratchPad.recorded.should == :loaded
- ModuleSpecs::Autoload::W.send(:remove_const, :Y)
end
it "does not call #require a second time and does not warn if already loading the same feature with #require" do
@@ -611,6 +656,7 @@ describe "Module#autoload" do
it "shares the autoload request across dup'ed copies of modules" do
require fixture(__FILE__, "autoload_s.rb")
+ @remove << :S
filename = fixture(__FILE__, "autoload_t.rb")
mod1 = Module.new { autoload :T, filename }
lambda {
@@ -651,8 +697,9 @@ describe "Module#autoload" do
describe "on a frozen module" do
it "raises a #{frozen_error_class} before setting the name" do
- lambda { @frozen_module.autoload :Foo, @non_existent }.should raise_error(frozen_error_class)
- @frozen_module.should_not have_constant(:Foo)
+ frozen_module = Module.new.freeze
+ lambda { frozen_module.autoload :Foo, @non_existent }.should raise_error(frozen_error_class)
+ frozen_module.should_not have_constant(:Foo)
end
end
@@ -675,6 +722,7 @@ describe "Module#autoload" do
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")
+ @remove << :Concur
start = false
@@ -717,8 +765,6 @@ describe "Module#autoload" do
t2_val.should == t1_val
t2_exc.should be_nil
-
- ModuleSpecs::Autoload.send(:remove_const, :Concur)
end
# https://bugs.ruby-lang.org/issues/10892