module Zeitwerk
Constants
- VERSION
Public Class Methods
with_loader() { |loader| ... }
click to toggle source
This is a dangerous method.
@experimental @sig () -> void
# File lib/zeitwerk.rb, line 18 def self.with_loader loader = Zeitwerk::Loader.new yield loader ensure loader.unregister end
Public Instance Methods
autoload_file(parent, cname, file)
click to toggle source
@sig (Module, Symbol, String) -> void
# File lib/zeitwerk/loader.rb, line 398 def autoload_file(parent, cname, file) if autoload_path = strict_autoload_path(parent, cname) || Registry.inception?(cpath(parent, cname)) # First autoload for a Ruby file wins, just ignore subsequent ones. if ruby?(autoload_path) log("file #{file} is ignored because #{autoload_path} has precedence") if logger else promote_namespace_from_implicit_to_explicit( dir: autoload_path, file: file, parent: parent, cname: cname ) end elsif cdef?(parent, cname) log("file #{file} is ignored because #{cpath(parent, cname)} is already defined") if logger else set_autoload(parent, cname, file) end end
autoload_path_set_by_me_for?(parent, cname)
click to toggle source
@sig (Module, Symbol) -> String?
# File lib/zeitwerk/loader.rb, line 454 def autoload_path_set_by_me_for?(parent, cname) if autoload_path = strict_autoload_path(parent, cname) autoload_path if autoloads.key?(autoload_path) else Registry.inception?(cpath(parent, cname)) end end
autoload_subdir(parent, cname, subdir)
click to toggle source
@sig (Module, Symbol, String) -> void
# File lib/zeitwerk/loader.rb, line 377 def autoload_subdir(parent, cname, subdir) if autoload_path = autoload_path_set_by_me_for?(parent, cname) cpath = cpath(parent, cname) register_explicit_namespace(cpath) if ruby?(autoload_path) # We do not need to issue another autoload, the existing one is enough # no matter if it is for a file or a directory. Just remember the # subdirectory has to be visited if the namespace is used. lazy_subdirs[cpath] << subdir elsif !cdef?(parent, cname) # First time we find this namespace, set an autoload for it. lazy_subdirs[cpath(parent, cname)] << subdir set_autoload(parent, cname, subdir) else # For whatever reason the constant that corresponds to this namespace has # already been defined, we have to recurse. log("the namespace #{cpath(parent, cname)} already exists, descending into #{subdir}") if logger set_autoloads_in_dir(subdir, cget(parent, cname)) end end
promote_namespace_from_implicit_to_explicit(dir:, file:, parent:, cname:)
click to toggle source
‘dir` is the directory that would have autovivified a namespace. `file` is the file where we’ve found the namespace is explicitly defined.
@sig (dir: String, file: String, parent: Module, cname: Symbol) -> void
# File lib/zeitwerk/loader.rb, line 422 def promote_namespace_from_implicit_to_explicit(dir:, file:, parent:, cname:) autoloads.delete(dir) Registry.unregister_autoload(dir) log("earlier autoload for #{cpath(parent, cname)} discarded, it is actually an explicit namespace defined in #{file}") if logger set_autoload(parent, cname, file) register_explicit_namespace(cpath(parent, cname)) end
raise_if_conflicting_directory(dir)
click to toggle source
@sig (String) -> void
# File lib/zeitwerk/loader.rb, line 468 def raise_if_conflicting_directory(dir) self.class.mutex.synchronize do Registry.loaders.each do |loader| next if loader == self next if loader.ignores?(dir) dir = dir + "/" loader.root_dirs.each do |root_dir, _namespace| next if ignores?(root_dir) root_dir = root_dir + "/" if dir.start_with?(root_dir) || root_dir.start_with?(dir) require "pp" # Needed for pretty_inspect, even in Ruby 2.5. raise Error, "loader\n\n#{pretty_inspect}\n\nwants to manage directory #{dir.chop}," \ " which is already managed by\n\n#{loader.pretty_inspect}\n" EOS end end end end end
register_explicit_namespace(cpath)
click to toggle source
@sig (String) -> void
# File lib/zeitwerk/loader.rb, line 463 def register_explicit_namespace(cpath) ExplicitNamespace.register(cpath, self) end
run_on_unload_callbacks(cpath, value, abspath)
click to toggle source
@sig (String, Object, String) -> void
# File lib/zeitwerk/loader.rb, line 492 def run_on_unload_callbacks(cpath, value, abspath) # Order matters. If present, run the most specific one. on_unload_callbacks[cpath]&.each { |c| c.call(value, abspath) } on_unload_callbacks[:ANY]&.each { |c| c.call(cpath, value, abspath) } end
set_autoload(parent, cname, abspath)
click to toggle source
@sig (Module, Symbol, String) -> void
# File lib/zeitwerk/loader.rb, line 433 def set_autoload(parent, cname, abspath) parent.autoload(cname, abspath) if logger if ruby?(abspath) log("autoload set for #{cpath(parent, cname)}, to be loaded from #{abspath}") else log("autoload set for #{cpath(parent, cname)}, to be autovivified from #{abspath}") end end autoloads[abspath] = [parent, cname] Registry.register_autoload(self, abspath) # See why in the documentation of Zeitwerk::Registry.inceptions. unless parent.autoload?(cname) Registry.register_inception(cpath(parent, cname), abspath, self) end end
unload_autoload(parent, cname)
click to toggle source
@sig (Module, Symbol) -> void
# File lib/zeitwerk/loader.rb, line 499 def unload_autoload(parent, cname) parent.__send__(:remove_const, cname) log("autoload for #{cpath(parent, cname)} removed") if logger end
unload_cref(parent, cname)
click to toggle source
@sig (Module, Symbol) -> void
# File lib/zeitwerk/loader.rb, line 505 def unload_cref(parent, cname) # Let's optimistically remove_const. The way we use it, this is going to # succeed always if all is good. parent.__send__(:remove_const, cname) rescue ::NameError # There are a few edge scenarios in which this may happen. If the constant # is gone, that is OK, anyway. else log("#{cpath(parent, cname)} unloaded") if logger end