lib/zeitwerk/loader/callbacks.rb in zeitwerk-2.0.0 vs lib/zeitwerk/loader/callbacks.rb in zeitwerk-2.1.0
- old
+ new
@@ -3,14 +3,14 @@
#
# @private
# @param file [String]
# @return [void]
def on_file_autoloaded(file)
- parent, cname = cref_autoloaded_from(file)
- loaded_cpaths.add(cpath(parent, cname))
+ cref = autoloads.delete(file)
+ to_unload[cpath(*cref)] = [file, cref] if reloading_enabled?
Zeitwerk::Registry.unregister_autoload(file)
- log("constant #{cpath(parent, cname)} loaded from file #{file}") if logger
+ log("constant #{cpath(*cref)} loaded from file #{file}") if logger
end
# Invoked from our decorated Kernel#require when a managed directory is
# autoloaded.
#
@@ -23,27 +23,29 @@
#
# Multi-threading would introduce a race condition here in which thread t1
# autovivifies the module, and while autoloads for its children are being
# set, thread t2 autoloads the same namespace.
#
- # Without the mutex and short-circuiting break, t2 would reset the module.
+ # Without the mutex and subsequent delete call, t2 would reset the module.
# 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 lazy_subdirs entry.
mutex2.synchronize do
- parent, cname = cref_autoloaded_from(dir)
- # If reloading is disabled and there are several threads autoloading the
- # same namespace at the same time, the parent is going to bbe nil for all
- # except the first one.
- break if parent.nil? || loaded_cpaths.include?(cpath(parent, cname))
+ if cref = autoloads.delete(dir)
+ autovivified_module = cref[0].const_set(cref[1], Module.new)
+ log("module #{autovivified_module.name} autovivified from directory #{dir}") if logger
- autovivified_module = parent.const_set(cname, Module.new)
- log("module #{autovivified_module.name} autovivified from directory #{dir}") if logger
+ to_unload[autovivified_module.name] = [dir, cref] if reloading_enabled?
- loaded_cpaths.add(autovivified_module.name)
- autoloaded_dirs << dir
- on_namespace_loaded(autovivified_module)
+ # We don't unregister `dir` in the registry because concurrent threads
+ # wouldn't find a loader associated to it in Kernel#require and would
+ # try to require the directory. Instead, we are going to keep track of
+ # these to be able to unregister later if eager loading.
+ autoloaded_dirs << dir
+
+ on_namespace_loaded(autovivified_module)
+ end
end
end
# Invoked when a class or module is created or reopened, either from the
# tracer or from module autovivification. If the namespace has matching
@@ -56,13 +58,7 @@
if subdirs = lazy_subdirs.delete(namespace.name)
subdirs.each do |subdir|
set_autoloads_in_dir(subdir, namespace)
end
end
- end
-
- # @private
- # @return [(Module, String)]
- def cref_autoloaded_from(path)
- reloading_enabled? ? autoloads[path] : autoloads.delete(path)
end
end