Module: Zeitwerk::Loader::Config
- Extended by:
- Internal
- Includes:
- RealModName
- Included in:
- Zeitwerk::Loader
- Defined in:
- lib/zeitwerk/loader/config.rb
Instance Attribute Summary collapse
-
#inflector ⇒ Object
: camelize(String, String) -> String.
-
#logger ⇒ Object
: call(String) -> void | debug(String) -> void | nil.
-
#nsfile ⇒ Object
Basename of files that define namespaces.
-
#roots ⇒ Object
readonly
Absolute paths of the root directories, mapped to their respective root namespaces:.
Instance Method Summary collapse
-
#collapse(*glob_patterns) ⇒ Object
Configure directories or glob patterns to be collapsed.
-
#dirs(namespaces: false, ignored: false) ⇒ Object
If ‘namespaces` is falsey (default), returns an array with the absolute paths of the root directories as strings.
-
#do_not_eager_load(*paths) ⇒ Object
Let eager load ignore the given files or directories.
-
#enable_reloading ⇒ Object
You need to call this method before setup in order to be able to reload.
-
#ignore(*glob_patterns) ⇒ Object
Configure files, directories, or glob patterns to be totally ignored.
-
#initialize ⇒ Object
: () -> void.
-
#log! ⇒ Object
Logs to ‘$stdout`, handy shortcut for debugging.
-
#on_load(cpath = UNDEFINED, &block) ⇒ Object
Configure a block to be invoked once a certain constant path is loaded.
-
#on_setup(&block) ⇒ Object
Configure a block to be called after setup and on each reload.
-
#on_unload(cpath = UNDEFINED, &block) ⇒ Object
Configure a block to be invoked right before a certain constant is removed.
-
#push_dir(path, namespace: Object) ⇒ Object
Pushes ‘path` to the list of root directories.
-
#reloading_enabled? ⇒ Boolean
: () -> bool.
-
#tag ⇒ Object
Returns the loader’s tag.
-
#tag=(tag) ⇒ Object
Sets a tag for the loader, useful for logging.
Methods included from Internal
Methods included from RealModName
Instance Attribute Details
#inflector ⇒ Object
: camelize(String, String) -> String
14 15 16 |
# File 'lib/zeitwerk/loader/config.rb', line 14 def inflector @inflector end |
#logger ⇒ Object
: call(String) -> void | debug(String) -> void | nil
17 18 19 |
# File 'lib/zeitwerk/loader/config.rb', line 17 def logger @logger end |
#nsfile ⇒ Object
Basename of files that define namespaces. For example, if ‘nsfile` is ’ns.rb’, then ‘foo/ns.rb` defines the `Foo` namespace.
: String?
39 40 41 |
# File 'lib/zeitwerk/loader/config.rb', line 39 def nsfile @nsfile end |
#roots ⇒ Object (readonly)
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]
32 33 34 |
# File 'lib/zeitwerk/loader/config.rb', line 32 def roots @roots end |
Instance Method Details
#collapse(*glob_patterns) ⇒ Object
Configure directories or glob patterns to be collapsed.
: (*(String | Pathname | Array[String | Pathname])) -> void
245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/zeitwerk/loader/config.rb', line 245 def collapse(*glob_patterns) glob_patterns = (glob_patterns) mutex.synchronize do collapse_glob_patterns.merge(glob_patterns) new_collapse_dirs = (glob_patterns) collapse_dirs.merge(new_collapse_dirs) new_collapse_dirs.each do |dir| collapse_parents << File.dirname(dir) end end end |
#dirs(namespaces: false, ignored: false) ⇒ Object
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]
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/zeitwerk/loader/config.rb', line 186 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 |
#do_not_eager_load(*paths) ⇒ Object
Let eager load ignore the given files or directories. The constants defined in those files are still autoloadable.
: (*(String | Pathname | Array[String | Pathname])) -> void
227 228 229 |
# File 'lib/zeitwerk/loader/config.rb', line 227 def do_not_eager_load(*paths) mutex.synchronize { eager_load_exclusions.merge((paths)) } end |
#enable_reloading ⇒ Object
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
206 207 208 209 210 211 212 213 214 215 216 |
# File 'lib/zeitwerk/loader/config.rb', line 206 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 |
#ignore(*glob_patterns) ⇒ Object
Configure files, directories, or glob patterns to be totally ignored.
: (*(String | Pathname | Array[String | Pathname])) -> void
234 235 236 237 238 239 240 |
# File 'lib/zeitwerk/loader/config.rb', line 234 def ignore(*glob_patterns) glob_patterns = (glob_patterns) mutex.synchronize do ignored_glob_patterns.merge(glob_patterns) ignored_paths.merge((glob_patterns)) end end |
#initialize ⇒ Object
: () -> void
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/zeitwerk/loader/config.rb', line 103 def initialize @inflector = Zeitwerk::Inflector.new @logger = self.class.default_logger @tag = SecureRandom.hex(3) @initialized_at = Time.now @roots = {} @nsfile = nil @ignored_glob_patterns = Set.new @ignored_paths = Set.new @collapse_glob_patterns = Set.new @collapse_dirs = Set.new @collapse_parents = Set.new @eager_load_exclusions = Set.new @reloading_enabled = false @on_setup_callbacks = [] @on_load_callbacks = {} @on_unload_callbacks = {} end |
#log! ⇒ Object
Logs to ‘$stdout`, handy shortcut for debugging.
: () -> void
331 332 333 |
# File 'lib/zeitwerk/loader/config.rb', line 331 def log! @logger = ->(msg) { puts msg } end |
#on_load(cpath = UNDEFINED, &block) ⇒ Object
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 | NameError | { (String, top, String) -> void } -> void
284 285 286 287 288 289 290 291 292 293 294 295 296 |
# File 'lib/zeitwerk/loader/config.rb', line 284 def on_load(cpath = UNDEFINED, &block) key = if cpath.equal?(UNDEFINED) :ANY elsif !cpath.is_a?(String) raise TypeError, 'on_load only accepts strings' else @cpv.validate!(cpath) end mutex.synchronize do (on_load_callbacks[key] ||= []) << block end end |
#on_setup(&block) ⇒ Object
Configure a block to be called after setup and on each reload. If setup was already done, the block runs immediately.
: () { () -> void } -> void
261 262 263 264 265 266 |
# File 'lib/zeitwerk/loader/config.rb', line 261 def on_setup(&block) mutex.synchronize do on_setup_callbacks << block block.call if @setup end end |
#on_unload(cpath = UNDEFINED, &block) ⇒ Object
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 | NameError | { (String, top, String) -> void } -> void
314 315 316 317 318 319 320 321 322 323 324 325 326 |
# File 'lib/zeitwerk/loader/config.rb', line 314 def on_unload(cpath = UNDEFINED, &block) key = if cpath.equal?(UNDEFINED) :ANY elsif !cpath.is_a?(String) raise TypeError, 'on_unload only accepts strings' else @cpv.validate!(cpath) end mutex.synchronize do (on_unload_callbacks[key] ||= []) << block end end |
#push_dir(path, namespace: Object) ⇒ Object
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
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/zeitwerk/loader/config.rb', line 129 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.(path) if @fs.dir?(abspath) raise_if_conflicting_root_dir(abspath) roots[abspath] = namespace else raise Zeitwerk::Error, "the root directory #{abspath} does not exist" end end |
#reloading_enabled? ⇒ Boolean
: () -> bool
219 220 221 |
# File 'lib/zeitwerk/loader/config.rb', line 219 def reloading_enabled? @reloading_enabled end |
#tag ⇒ Object
Returns the loader’s tag.
Implemented as a method instead of via attr_reader for symmetry with the writer below.
: () -> String
153 154 155 |
# File 'lib/zeitwerk/loader/config.rb', line 153 def tag @tag end |
#tag=(tag) ⇒ Object
Sets a tag for the loader, useful for logging.
: (to_s() -> String) -> void
160 161 162 |
# File 'lib/zeitwerk/loader/config.rb', line 160 def tag=(tag) @tag = tag.to_s end |