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.
: Set
Absolute paths of directories or glob patterns to be collapsed.
: Set
Absolute paths of files or directories not to be eager loaded.
: Set
Absolute paths of files, directories, or glob patterns to be ignored.
: 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.
: Set
: camelize(String, String) -> String
: call(String) -> void | debug(String) -> void | nil
User-oriented callbacks to be fired when a constant is loaded.
: Hash[String, Array[{ (top, String) -> void }]] | Hash[Symbol, Array[{ (String, top, String) -> void }]]
User-oriented callbacks to be fired on setup and on reload.
: Array[{ () -> void }]
User-oriented callbacks to be fired before constants are removed.
: Hash[String, Array[{ (top, String) -> void }]] | Hash[Symbol, Array[{ (String, top, String) -> void }]]
Absolute paths of the root directories, mapped to their respective root namespaces: "/Users/fxn/blog/app/channels" => Object, "/Users/fxn/blog/app/adapters" => ActiveJob::QueueAdapters, ... Stored in a hash to preserve order, easily handle duplicates, and have a fast lookup by directory. This is a private collection maintained by the loader. The public interface for it is `push_dir` and `dirs`.
: Hash[String, Module]
Public Class Methods
Source
# File lib/zeitwerk/loader/config.rb, line 85 def initialize @inflector = Zeitwerk::Inflector.new @logger = self.class.default_logger @tag = SecureRandom.hex(3) @initialized_at = Time.now @roots = {} @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 = {} end
Public Instance Methods
Source
# File lib/zeitwerk/loader/config.rb, line 213 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
Configure directories or glob patterns to be collapsed.
: (*(String | Pathname | Array[String | Pathname])) -> void
Source
# File lib/zeitwerk/loader/config.rb, line 154 def dirs(namespaces: false, ignored: false) if namespaces if ignored || ignored_paths.empty? roots.clone else roots.reject { |root_dir, _namespace| ignored_path?(root_dir) } end else if ignored || ignored_paths.empty? roots.keys else roots.keys.reject { |root_dir| ignored_path?(root_dir) } end end.freeze end
If `namespaces` is falsey (default), returns an array with the absolute paths of the root directories as strings. If truthy, returns a hash table instead. Keys are the absolute paths of the root directories as strings, values are their corresponding namespaces, class or module objects. If `ignored` is falsey (default), ignored root directories are filtered out. These are read-only collections, please add to them with `push_dir`.
: (?namespaces: boolish, ?ignored: boolish) -> Array | Hash[String, Module]
Source
# File lib/zeitwerk/loader/config.rb, line 195 def do_not_eager_load(*paths) mutex.synchronize { eager_load_exclusions.merge(expand_paths(paths)) } end
Let eager load ignore the given files or directories. The constants defined in those files are still autoloadable.
: (*(String | Pathname | Array[String | Pathname])) -> void
Source
# File lib/zeitwerk/loader/config.rb, line 174 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
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.
: () -> void ! Zeitwerk::Error
Source
# File lib/zeitwerk/loader/config.rb, line 202 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
Configure files, directories, or glob patterns to be totally ignored.
: (*(String | Pathname | Array[String | Pathname])) -> void
Source
# File lib/zeitwerk/loader/config.rb, line 289 def ignores?(abspath) # Common use case. return false if ignored_paths.empty? walk_up(abspath) do |path| return true if ignored_path?(path) return false if roots.key?(path) end false end
Source
# File lib/zeitwerk/loader/config.rb, line 281 def log! @logger = ->(msg) { puts msg } end
Logs to `$stdout`, handy shortcut for debugging.
: () -> void
Source
# File lib/zeitwerk/loader/config.rb, line 247 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 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
: (String?) { (top, String) -> void } -> void ! TypeError
Source
# File lib/zeitwerk/loader/config.rb, line 225 def on_setup(&block) mutex.synchronize do on_setup_callbacks << block block.call if @setup end end
Configure a block to be called after setup and on each reload. If setup was already done, the block runs immediately.
: () { () -> void } -> void
Source
# File lib/zeitwerk/loader/config.rb, line 270 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
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
: (String?) { (top, String) -> void } -> void ! TypeError
Source
# File lib/zeitwerk/loader/config.rb, line 109 def push_dir(path, namespace: Object) unless namespace.is_a?(Module) # Note that Class < Module. raise Zeitwerk::Error, "#{namespace.inspect} is not a class or module object, should be" end unless real_mod_name(namespace) raise Zeitwerk::Error, "root namespaces cannot be anonymous" end abspath = File.expand_path(path) if dir?(abspath) raise_if_conflicting_directory(abspath) roots[abspath] = namespace else raise Zeitwerk::Error, "the root directory #{abspath} does not exist" 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.
: (String | Pathname, namespace: Module) -> void ! Zeitwerk::Error
Source
# File lib/zeitwerk/loader/config.rb, line 187 def reloading_enabled? @reloading_enabled end
: () -> bool
Source
# File lib/zeitwerk/loader/config.rb, line 133 def tag @tag end
Returns the loader's tag. Implemented as a method instead of via attr_reader for symmetry with the writer below.
: () -> String
Source
# File lib/zeitwerk/loader/config.rb, line 140 def tag=(tag) @tag = tag.to_s end
Sets a tag for the loader, useful for logging.
: (to_s() -> String) -> void
Private Instance Methods
Source
# File lib/zeitwerk/loader/config.rb, line 307 def actual_roots roots.reject do |root_dir, _root_namespace| !dir?(root_dir) || ignored_path?(root_dir) end end
: () -> Array
Source
# File lib/zeitwerk/loader/config.rb, line 332 def collapse?(dir) collapse_dirs.member?(dir) end
: (String) -> bool
Source
# File lib/zeitwerk/loader/config.rb, line 319 def excluded_from_eager_load?(abspath) # Optimize this common use case. return false if eager_load_exclusions.empty? walk_up(abspath) do |path| return true if eager_load_exclusions.member?(path) return false if roots.key?(path) end false end
: (String) -> bool
Source
# File lib/zeitwerk/loader/config.rb, line 342 def expand_glob_patterns(glob_patterns) # Note that Dir.glob works with regular file names just fine. That is, # glob patterns technically need no wildcards. glob_patterns.flat_map { |glob_pattern| Dir.glob(glob_pattern) } end
Source
# File lib/zeitwerk/loader/config.rb, line 337 def expand_paths(paths) paths.flatten.map! { |path| File.expand_path(path) } end
: (String | Pathname | Array[String | Pathname]) -> Array
Source
# File lib/zeitwerk/loader/config.rb, line 302 def ignored_path?(abspath) ignored_paths.member?(abspath) end
: (String) -> bool
Source
# File lib/zeitwerk/loader/config.rb, line 354 def recompute_collapse_dirs collapse_dirs.replace(expand_glob_patterns(collapse_glob_patterns)) end
: () -> void
Source
# File lib/zeitwerk/loader/config.rb, line 349 def recompute_ignored_paths ignored_paths.replace(expand_glob_patterns(ignored_glob_patterns)) end
: () -> void
Source
# File lib/zeitwerk/loader/config.rb, line 314 def root_dir?(dir) roots.key?(dir) end
: (String) -> bool