Skip to content

Commit

Permalink
Let on_dir_autoloaded be reentrant
Browse files Browse the repository at this point in the history
  • Loading branch information
fxn committed Aug 2, 2023
1 parent 25042c6 commit ffd4d0e
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 6 deletions.
12 changes: 7 additions & 5 deletions lib/zeitwerk/loader.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# frozen_string_literal: true

require "monitor"
require "set"

module Zeitwerk
Expand Down Expand Up @@ -91,9 +92,9 @@ class Loader
attr_reader :mutex
private :mutex

# @sig Mutex
attr_reader :mutex2
private :mutex2
# @sig Monitor
attr_reader :dirs_autoload_monitor
private :dirs_autoload_monitor

def initialize
super
Expand All @@ -103,11 +104,12 @@ def initialize
@to_unload = {}
@namespace_dirs = Hash.new { |h, cpath| h[cpath] = [] }
@shadowed_files = Set.new
@mutex = Mutex.new
@mutex2 = Mutex.new
@setup = false
@eager_loaded = false

@mutex = Mutex.new
@dirs_autoload_monitor = Monitor.new

Registry.register_loader(self)
end

Expand Down
2 changes: 1 addition & 1 deletion lib/zeitwerk/loader/callbacks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def on_dir_autoloaded(dir)
# That not only would reassign the constant (undesirable per se) but, worse,
# the module object created by t2 wouldn't have any of the autoloads for its
# children, since t1 would have correctly deleted its namespace_dirs entry.
mutex2.synchronize do
dirs_autoload_monitor.synchronize do
if cref = autoloads.delete(dir)
autovivified_module = cref[0].const_set(cref[1], Module.new)
cpath = autovivified_module.name
Expand Down
11 changes: 11 additions & 0 deletions test/lib/zeitwerk/test_on_load.rb
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,15 @@ class TestOnLoad < LoaderTest
assert loader.send(:on_load_callbacks).empty?
end
end

test "on_load is reentrant for implicit namespaces" do
files = [["m/x.rb", "M::X = true"], ["n/x.rb", "N::X = true"]]
with_setup(files) do
loaded = false
loader.on_load("M") { loaded = N }

assert M
assert loaded
end
end
end

0 comments on commit ffd4d0e

Please sign in to comment.