module Zeitwerk::Loader::Callbacks

def on_dir_autoloaded(dir)

@sig (String) -> void

autoloaded.
Invoked from our decorated Kernel#require when a managed directory is
def on_dir_autoloaded(dir)
e#autoload does not serialize concurrent requires in CRuby < 3.2, and
ndle directories ourselves without going through Kernel#require, so
allback needs to account for concurrency.
-threading would introduce a race condition here in which thread t1
ivifies the module, and while autoloads for its children are being
thread t2 autoloads the same namespace.
ut the mutex and subsequent delete call, t2 would reset the module.
not only would reassign the constant (undesirable per se) but, worse,
odule object created by t2 wouldn't have any of the autoloads for its
ren, since t1 would have correctly deleted its namespace_dirs entry.
toload_monitor.synchronize do
ef = autoloads.delete(dir)
licit_namespace = cref.set(Module.new)
th = implicit_namespace.name
("module #{cpath} autovivified from directory #{dir}") if logger
unload[cpath] = [dir, cref] if reloading_enabled?
e don't unregister `dir` in the registry because concurrent threads
ouldn't find a loader associated to it in Kernel#require and would
ry to require the directory. Instead, we are going to keep track of
hese to be able to unregister later if eager loading.
oloaded_dirs << dir
namespace_loaded(implicit_namespace)
_on_load_callbacks(cpath, implicit_namespace, dir) unless on_load_callbacks.empty?

def on_file_autoloaded(file)

@sig (String) -> void

Invoked from our decorated Kernel#require when a managed file is autoloaded.
def on_file_autoloaded(file)
autoloads.delete(file)
k::Registry.unregister_autoload(file)
.defined?
constant #{cref.path} loaded from file #{file}") if logger
load[cref.path] = [file, cref] if reloading_enabled?
n_load_callbacks(cref.path, cref.get, file) unless on_load_callbacks.empty?
 "expected file #{file} to define constant #{cref.path}, but didn't"
sg) if logger
y still keeps the autoload defined, but we remove it because the
tract in Zeitwerk is more strict.
remove
ce the expected constant was not defined, there is nothing to unload.
ever, if the exception is rescued and reloading is enabled, we still
d to deleted the file from $LOADED_FEATURES.
load[cref.path] = [file, cref] if reloading_enabled?
 Zeitwerk::NameError.new(msg, cref.cname)

def on_namespace_loaded(namespace)

Other tags:
    Private: -
def on_namespace_loaded(namespace)
  if dirs = namespace_dirs.delete(real_mod_name(namespace))
    dirs.each do |dir|
      define_autoloads_for_dir(dir, namespace)
    end
  end
end

def run_on_load_callbacks(cpath, value, abspath)

@sig (String, Object) -> void
def run_on_load_callbacks(cpath, value, abspath)
  # Order matters. If present, run the most specific one.
  callbacks = reloading_enabled? ? on_load_callbacks[cpath] : on_load_callbacks.delete(cpath)
  callbacks&.each { |c| c.call(value, abspath) }
  callbacks = on_load_callbacks[:ANY]
  callbacks&.each { |c| c.call(cpath, value, abspath) }
end