diff options
Diffstat (limited to 'spec/ruby/core/module/autoload_spec.rb')
-rw-r--r-- | spec/ruby/core/module/autoload_spec.rb | 92 |
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 |