Module: Zeitwerk::Loader::Config

Included in:
Zeitwerk::Loader
Defined in:
lib/zeitwerk/loader/config.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#collapse_dirsObject (readonly)

The actual collection of absolute directory names at the time the collapse glob patterns were expanded. Computed on setup, and recomputed on reload.



51
52
53
# File 'lib/zeitwerk/loader/config.rb', line 51

def collapse_dirs
  @collapse_dirs
end

#collapse_glob_patternsObject (readonly)

Absolute paths of directories or glob patterns to be collapsed.



44
45
46
# File 'lib/zeitwerk/loader/config.rb', line 44

def collapse_glob_patterns
  @collapse_glob_patterns
end

#eager_load_exclusionsObject (readonly)

Absolute paths of files or directories not to be eager loaded.



57
58
59
# File 'lib/zeitwerk/loader/config.rb', line 57

def eager_load_exclusions
  @eager_load_exclusions
end

#ignored_glob_patternsObject (readonly)

Absolute paths of files, directories, or glob patterns to be totally ignored.



30
31
32
# File 'lib/zeitwerk/loader/config.rb', line 30

def ignored_glob_patterns
  @ignored_glob_patterns
end

#ignored_pathsObject (readonly)

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.



38
39
40
# File 'lib/zeitwerk/loader/config.rb', line 38

def ignored_paths
  @ignored_paths
end

#inflectorObject

Returns the value of attribute inflector.



23
24
25
# File 'lib/zeitwerk/loader/config.rb', line 23

def inflector
  @inflector
end

#loggerObject

Returns the value of attribute logger.



80
81
82
# File 'lib/zeitwerk/loader/config.rb', line 80

def logger
  @logger
end

#on_load_callbacksObject (readonly)

User-oriented callbacks to be fired when a constant is loaded.



70
71
72
# File 'lib/zeitwerk/loader/config.rb', line 70

def on_load_callbacks
  @on_load_callbacks
end

#on_setup_callbacksObject (readonly)

User-oriented callbacks to be fired on setup and on reload.



63
64
65
# File 'lib/zeitwerk/loader/config.rb', line 63

def on_setup_callbacks
  @on_setup_callbacks
end

#on_unload_callbacksObject (readonly)

User-oriented callbacks to be fired before constants are removed.



77
78
79
# File 'lib/zeitwerk/loader/config.rb', line 77

def on_unload_callbacks
  @on_unload_callbacks
end

#root_dirsObject (readonly)

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`.



20
21
22
# File 'lib/zeitwerk/loader/config.rb', line 20

def root_dirs
  @root_dirs
end

Instance Method Details

#collapse(*glob_patterns) ⇒ Object

Configure directories or glob patterns to be collapsed.



192
193
194
195
196
197
198
# 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

#dirsObject

Absolute paths of the root directories. This is a read-only collection, please push here via ‘push_dir`.



144
145
146
# File 'lib/zeitwerk/loader/config.rb', line 144

def dirs
  root_dirs.keys.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.



174
175
176
# File 'lib/zeitwerk/loader/config.rb', line 174

def do_not_eager_load(*paths)
  mutex.synchronize { eager_load_exclusions.merge(expand_paths(paths)) }
end

#enable_reloadingObject

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.

Raises:



153
154
155
156
157
158
159
160
161
162
163
# 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

#ignore(*glob_patterns) ⇒ Object

Configure files, directories, or glob patterns to be totally ignored.



181
182
183
184
185
186
187
# 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

#ignores?(abspath) ⇒ Boolean

Returns:

  • (Boolean)


270
271
272
273
274
# 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

#initializeObject



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# 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

#log!Object

Logs to ‘$stdout`, handy shortcut for debugging.



264
265
266
# File 'lib/zeitwerk/loader/config.rb', line 264

def log!
  @logger = ->(msg) { puts msg }
end

#on_load(cpath = :ANY, &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

Raises:

  • (TypeError)


228
229
230
231
232
233
234
# 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

#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.



204
205
206
207
208
209
# 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

#on_unload(cpath = :ANY, &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

Raises:

  • (TypeError)


253
254
255
256
257
258
259
# 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

#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.

Raises:



107
108
109
110
111
112
113
114
115
116
117
118
119
120
# 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

#reloading_enabled?Boolean

Returns:

  • (Boolean)


166
167
168
# File 'lib/zeitwerk/loader/config.rb', line 166

def reloading_enabled?
  @reloading_enabled
end

#tagObject

Returns the loader’s tag.

Implemented as a method instead of via attr_reader for symmetry with the writer below.



128
129
130
# File 'lib/zeitwerk/loader/config.rb', line 128

def tag
  @tag
end

#tag=(tag) ⇒ Object

Sets a tag for the loader, useful for logging.

Parameters:

  • tag (#to_s)


136
137
138
# File 'lib/zeitwerk/loader/config.rb', line 136

def tag=(tag)
  @tag = tag.to_s
end