module Zeitwerk::Loader::Config
Attributes
The actual collection of absolute directory names at the time the collapse glob patterns were expanded. Computed on setup, and recomputed on reload.
@private @sig Set
Absolute paths of directories or glob patterns to be collapsed.
@private @sig Set
Absolute paths of files or directories not to be eager loaded.
@private @sig Set
Absolute paths of files, directories, or glob patterns to be totally ignored.
@private @sig Set
The actual collection of absolute file and directory names at the time the ignored glob patterns were expanded. Computed on setup, and recomputed on reload.
@private @sig Set
@sig camelize
@sig call | debug | nil
User-oriented callbacks to be fired when a constant is loaded.
@private @sig Hash[String, Array[{ (Object, String) -> void }]]
Hash[Symbol, Array[{ (String, Object, String) -> void }]]
User-oriented callbacks to be fired on setup and on reload.
@private @sig Array[{ () -> void }]
User-oriented callbacks to be fired before constants are removed.
@private @sig Hash[String, Array[{ (Object, String) -> void }]]
Hash[Symbol, Array[{ (String, Object, String) -> void }]]
Absolute paths of the root directories. Stored in a hash to preserve order, easily handle duplicates, and also be able to have a fast lookup, needed for detecting nested paths.
"/Users/fxn/blog/app/assets" => true, "/Users/fxn/blog/app/channels" => true, ...
This is a private collection maintained by the loader. The public interface for it is `push_dir` and `dirs`.
@private @sig Hash[String, true]
Public Class Methods
# File lib/zeitwerk/loader/config.rb, line 82 def initialize @initialized_at = Time.now @root_dirs = {} @inflector = Zeitwerk::Inflector.new @ignored_glob_patterns = Set.new @ignored_paths = Set.new @collapse_glob_patterns = Set.new @collapse_dirs = Set.new @eager_load_exclusions = Set.new @reloading_enabled = false @on_setup_callbacks = [] @on_load_callbacks = {} @on_unload_callbacks = {} @logger = self.class.default_logger @tag = SecureRandom.hex(3) end
Public Instance Methods
Configure directories or glob patterns to be collapsed.
@sig (*(String | Pathname | Array[String | Pathname])) -> void
# File lib/zeitwerk/loader/config.rb, line 192 def collapse(*glob_patterns) glob_patterns = expand_paths(glob_patterns) mutex.synchronize do collapse_glob_patterns.merge(glob_patterns) collapse_dirs.merge(expand_glob_patterns(glob_patterns)) end end
Absolute paths of the root directories. This is a read-only collection, please push here via `push_dir`.
@sig () -> Array
# File lib/zeitwerk/loader/config.rb, line 144 def dirs root_dirs.keys.freeze end
Let eager load ignore the given files or directories. The constants defined in those files are still autoloadable.
@sig (*(String | Pathname | Array[String | Pathname])) -> void
# File lib/zeitwerk/loader/config.rb, line 174 def do_not_eager_load(*paths) mutex.synchronize { eager_load_exclusions.merge(expand_paths(paths)) } end
You need to call this method before setup in order to be able to reload. There is no way to undo this, either you want to reload or you don't.
@raise [Zeitwerk::Error] @sig () -> void
# File lib/zeitwerk/loader/config.rb, line 153 def enable_reloading mutex.synchronize do break if @reloading_enabled if @setup raise Zeitwerk::Error, "cannot enable reloading after setup" else @reloading_enabled = true end end end
Configure files, directories, or glob patterns to be totally ignored.
@sig (*(String | Pathname | Array[String | Pathname])) -> void
# File lib/zeitwerk/loader/config.rb, line 181 def ignore(*glob_patterns) glob_patterns = expand_paths(glob_patterns) mutex.synchronize do ignored_glob_patterns.merge(glob_patterns) ignored_paths.merge(expand_glob_patterns(glob_patterns)) end end
@private @sig (String) -> bool
# File lib/zeitwerk/loader/config.rb, line 270 def ignores?(abspath) ignored_paths.any? do |ignored_path| ignored_path == abspath || (dir?(ignored_path) && abspath.start_with?(ignored_path + "/")) end end
Logs to `$stdout`, handy shortcut for debugging.
@sig () -> void
# File lib/zeitwerk/loader/config.rb, line 264 def log! @logger = ->(msg) { puts msg } end
Configure a block to be invoked once a certain constant path is loaded. Supports multiple callbacks, and if there are many, they are executed in the order in which they were defined.
loader.on_load("SomeApiClient") do |klass, _abspath| klass.endpoint = "https://api.dev" end
Can also be configured for any constant loaded:
loader.on_load do |cpath, value, abspath| # ... end
@raise [TypeError] @sig (String) { (Object, String) -> void } -> void
(:ANY) { (String, Object, String) -> void } -> void
# File lib/zeitwerk/loader/config.rb, line 228 def on_load(cpath = :ANY, &block) raise TypeError, "on_load only accepts strings" unless cpath.is_a?(String) || cpath == :ANY mutex.synchronize do (on_load_callbacks[cpath] ||= []) << block end end
Configure a block to be called after setup and on each reload. If setup was already done, the block runs immediately.
@sig () { () -> void } -> void
# File lib/zeitwerk/loader/config.rb, line 204 def on_setup(&block) mutex.synchronize do on_setup_callbacks << block block.call if @setup end end
Configure a block to be invoked right before a certain constant is removed. Supports multiple callbacks, and if there are many, they are executed in the order in which they were defined.
loader.on_unload("Country") do |klass, _abspath| klass.clear_cache end
Can also be configured for any removed constant:
loader.on_unload do |cpath, value, abspath| # ... end
@raise [TypeError] @sig (String) { (Object) -> void } -> void
(:ANY) { (String, Object) -> void } -> void
# File lib/zeitwerk/loader/config.rb, line 253 def on_unload(cpath = :ANY, &block) raise TypeError, "on_unload only accepts strings" unless cpath.is_a?(String) || cpath == :ANY mutex.synchronize do (on_unload_callbacks[cpath] ||= []) << block end end
Pushes `path` to the list of root directories.
Raises `Zeitwerk::Error` if `path` does not exist, or if another loader in the same process already manages that directory or one of its ascendants or descendants.
@raise [Zeitwerk::Error] @sig (String | Pathname, Module) -> void
# File lib/zeitwerk/loader/config.rb, line 107 def push_dir(path, namespace: Object) # Note that Class < Module. unless namespace.is_a?(Module) raise Zeitwerk::Error, "#{namespace.inspect} is not a class or module object, should be" end abspath = File.expand_path(path) if dir?(abspath) raise_if_conflicting_directory(abspath) root_dirs[abspath] = namespace else raise Zeitwerk::Error, "the root directory #{abspath} does not exist" end end
@sig () -> bool
# File lib/zeitwerk/loader/config.rb, line 166 def reloading_enabled? @reloading_enabled end
Returns the loader's tag.
Implemented as a method instead of via attr_reader for symmetry with the writer below.
@sig () -> String
# File lib/zeitwerk/loader/config.rb, line 128 def tag @tag end
Sets a tag for the loader, useful for logging.
@param tag [#to_s] @sig (to_s) -> void
# File lib/zeitwerk/loader/config.rb, line 136 def tag=(tag) @tag = tag.to_s end
Private Instance Methods
@sig () -> Array
# File lib/zeitwerk/loader/config.rb, line 279 def actual_root_dirs root_dirs.reject do |root_dir, _namespace| !dir?(root_dir) || ignored_paths.member?(root_dir) end end
@sig (String) -> bool
# File lib/zeitwerk/loader/config.rb, line 296 def collapse?(dir) collapse_dirs.member?(dir) end
@sig (String) -> bool
# File lib/zeitwerk/loader/config.rb, line 291 def excluded_from_eager_load?(abspath) eager_load_exclusions.member?(abspath) end
@sig (String | Pathname | Array[String | Pathname]) -> Array
# File lib/zeitwerk/loader/config.rb, line 301 def expand_paths(paths) paths.flatten.map! { |path| File.expand_path(path) } end
@sig () -> void
# File lib/zeitwerk/loader/config.rb, line 318 def recompute_collapse_dirs collapse_dirs.replace(expand_glob_patterns(collapse_glob_patterns)) end
@sig () -> void
# File lib/zeitwerk/loader/config.rb, line 313 def recompute_ignored_paths ignored_paths.replace(expand_glob_patterns(ignored_glob_patterns)) end
@sig (String) -> bool
# File lib/zeitwerk/loader/config.rb, line 286 def root_dir?(dir) root_dirs.key?(dir) end