Module: Zeitwerk::Registry
- Defined in:
- lib/zeitwerk/registry.rb
Overview
:nodoc: all
Class Attribute Summary collapse
-
.autoloads ⇒ {String => Zeitwerk::Loader}
readonly
Maps real paths to the loaders responsible for them.
-
.inceptions ⇒ {String => (String, Zeitwerk::Loader)}
readonly
This hash table addresses an edge case in which an autoload is ignored.
-
.loaders ⇒ <Zeitwerk::Loader>
readonly
Keeps track of all loaders.
-
.loaders_managing_gems ⇒ {String => Zeitwerk::Loader}
readonly
Registers loaders created with ‘for_gem` to make the method idempotent in case of reload.
Class Method Summary collapse
- .inception?(cpath) ⇒ String?
- .loader_for(path) ⇒ Zeitwerk::Loader?
-
.loader_for_gem(root_file) ⇒ Zeitwerk::Loader
This method returns always a loader, the same instance for the same root file.
- .on_unload(loader) ⇒ void
- .register_autoload(loader, realpath) ⇒ void
- .register_inception(cpath, realpath, loader) ⇒ void
-
.register_loader(loader) ⇒ void
Registers a loader.
- .unregister_autoload(realpath) ⇒ void
Class Attribute Details
.autoloads ⇒ {String => Zeitwerk::Loader} (readonly)
Maps real paths to the loaders responsible for them.
This information is used by our decorated ‘Kernel#require` to be able to invoke callbacks and autovivify modules.
27 28 29 |
# File 'lib/zeitwerk/registry.rb', line 27 def autoloads @autoloads end |
.inceptions ⇒ {String => (String, Zeitwerk::Loader)} (readonly)
This hash table addresses an edge case in which an autoload is ignored.
For example, let’s suppose we want to autoload in a gem like this:
# lib/my_gem.rb
loader = Zeitwerk::Loader.new
loader.push_dir(__dir__)
loader.setup
module MyGem
end
if you require “my_gem”, as Bundler would do, this happens while setting up autoloads:
1. Object.autoload?(:MyGem) returns `nil` because the autoload for
the constant is issued by Zeitwerk while the same file is being
required.
2. The constant `MyGem` is undefined while setup runs.
Therefore, a directory ‘lib/my_gem` would autovivify a module according to the existing information. But that would be wrong.
To overcome this fundamental limitation, we keep track of the constant paths that are in this situation —in the example above, “MyGem”— and take this collection into account for the autovivification logic.
Note that you cannot generally address this by moving the setup code below the constant definition, because we want libraries to be able to use managed constants in the module body:
module MyGem
include MyConcern
end
66 67 68 |
# File 'lib/zeitwerk/registry.rb', line 66 def inceptions @inceptions end |
.loaders ⇒ <Zeitwerk::Loader> (readonly)
Keeps track of all loaders. Useful to broadcast messages and to prevent them from being garbage collected.
11 12 13 |
# File 'lib/zeitwerk/registry.rb', line 11 def loaders @loaders end |
.loaders_managing_gems ⇒ {String => Zeitwerk::Loader} (readonly)
Registers loaders created with ‘for_gem` to make the method idempotent in case of reload.
18 19 20 |
# File 'lib/zeitwerk/registry.rb', line 18 def loaders_managing_gems @loaders_managing_gems end |
Class Method Details
.inception?(cpath) ⇒ String?
120 121 122 123 124 |
# File 'lib/zeitwerk/registry.rb', line 120 def inception?(cpath) if pair = inceptions[cpath] pair.first end end |
.loader_for(path) ⇒ Zeitwerk::Loader?
129 130 131 |
# File 'lib/zeitwerk/registry.rb', line 129 def loader_for(path) autoloads[path] end |
.loader_for_gem(root_file) ⇒ Zeitwerk::Loader
This method returns always a loader, the same instance for the same root file. That is how Zeitwerk::Loader.for_gem is idempotent.
83 84 85 86 87 88 89 90 91 |
# File 'lib/zeitwerk/registry.rb', line 83 def loader_for_gem(root_file) loaders_managing_gems[root_file] ||= begin Loader.new.tap do |loader| loader.tag = File.basename(root_file, ".rb") loader.inflector = GemInflector.new(root_file) loader.push_dir(File.dirname(root_file)) end end end |
.on_unload(loader) ⇒ void
This method returns an undefined value.
136 137 138 139 |
# File 'lib/zeitwerk/registry.rb', line 136 def on_unload(loader) autoloads.delete_if { |_path, object| object == loader } inceptions.delete_if { |_cpath, (_path, object)| object == loader } end |
.register_autoload(loader, realpath) ⇒ void
This method returns an undefined value.
97 98 99 |
# File 'lib/zeitwerk/registry.rb', line 97 def register_autoload(loader, realpath) autoloads[realpath] = loader end |
.register_inception(cpath, realpath, loader) ⇒ void
This method returns an undefined value.
113 114 115 |
# File 'lib/zeitwerk/registry.rb', line 113 def register_inception(cpath, realpath, loader) inceptions[cpath] = [realpath, loader] end |
.register_loader(loader) ⇒ void
This method returns an undefined value.
Registers a loader.
73 74 75 |
# File 'lib/zeitwerk/registry.rb', line 73 def register_loader(loader) loaders << loader end |
.unregister_autoload(realpath) ⇒ void
This method returns an undefined value.
104 105 106 |
# File 'lib/zeitwerk/registry.rb', line 104 def unregister_autoload(realpath) autoloads.delete(realpath) end |