Module: Zeitwerk::Registry

Defined in:
lib/zeitwerk/registry.rb

Overview

:nodoc: all

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.autoloadsObject (readonly)

Maps absolute 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.



26
27
28
# File 'lib/zeitwerk/registry.rb', line 26

def autoloads
  @autoloads
end

.gem_loaders_by_root_fileObject (readonly)

Registers gem loaders to let ‘for_gem` be idempotent in case of reload.



17
18
19
# File 'lib/zeitwerk/registry.rb', line 17

def gem_loaders_by_root_file
  @gem_loaders_by_root_file
end

.inceptionsObject (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


65
66
67
# File 'lib/zeitwerk/registry.rb', line 65

def inceptions
  @inceptions
end

.loadersObject (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

Class Method Details

.inception?(cpath) ⇒ Boolean

Returns:

  • (Boolean)


113
114
115
116
117
# File 'lib/zeitwerk/registry.rb', line 113

def inception?(cpath)
  if pair = inceptions[cpath]
    pair.first
  end
end

.loader_for(path) ⇒ Object



121
122
123
# File 'lib/zeitwerk/registry.rb', line 121

def loader_for(path)
  autoloads[path]
end

.loader_for_gem(root_file, namespace:, warn_on_extra_files:) ⇒ Object

This method returns always a loader, the same instance for the same root file. That is how Zeitwerk::Loader.for_gem is idempotent.



89
90
91
# File 'lib/zeitwerk/registry.rb', line 89

def loader_for_gem(root_file, namespace:, warn_on_extra_files:)
  gem_loaders_by_root_file[root_file] ||= GemLoader.__new(root_file, namespace: namespace, warn_on_extra_files: warn_on_extra_files)
end

.on_unload(loader) ⇒ Object



127
128
129
130
# File 'lib/zeitwerk/registry.rb', line 127

def on_unload(loader)
  autoloads.delete_if { |_path, object| object == loader }
  inceptions.delete_if { |_cpath, (_path, object)| object == loader }
end

.register_autoload(loader, abspath) ⇒ Object



95
96
97
# File 'lib/zeitwerk/registry.rb', line 95

def register_autoload(loader, abspath)
  autoloads[abspath] = loader
end

.register_inception(cpath, abspath, loader) ⇒ Object



107
108
109
# File 'lib/zeitwerk/registry.rb', line 107

def register_inception(cpath, abspath, loader)
  inceptions[cpath] = [abspath, loader]
end

.register_loader(loader) ⇒ Object

Registers a loader.



71
72
73
# File 'lib/zeitwerk/registry.rb', line 71

def register_loader(loader)
  loaders << loader
end

.unregister_autoload(abspath) ⇒ Object



101
102
103
# File 'lib/zeitwerk/registry.rb', line 101

def unregister_autoload(abspath)
  autoloads.delete(abspath)
end

.unregister_loader(loader) ⇒ Object



77
78
79
80
81
82
# File 'lib/zeitwerk/registry.rb', line 77

def unregister_loader(loader)
  loaders.delete(loader)
  gem_loaders_by_root_file.delete_if { |_, l| l == loader }
  autoloads.delete_if { |_, l| l == loader }
  inceptions.delete_if { |_, (_, l)| l == loader }
end