zeitwerk 2.6.1 → 2.6.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +242 -34
- data/lib/zeitwerk/error.rb +6 -0
- data/lib/zeitwerk/explicit_namespace.rb +14 -10
- data/lib/zeitwerk/gem_inflector.rb +2 -2
- data/lib/zeitwerk/gem_loader.rb +12 -8
- data/lib/zeitwerk/internal.rb +12 -0
- data/lib/zeitwerk/kernel.rb +3 -0
- data/lib/zeitwerk/loader/callbacks.rb +10 -10
- data/lib/zeitwerk/loader/config.rb +83 -48
- data/lib/zeitwerk/loader/eager_load.rb +228 -0
- data/lib/zeitwerk/loader/helpers.rb +30 -16
- data/lib/zeitwerk/loader.rb +145 -114
- data/lib/zeitwerk/registry.rb +2 -2
- data/lib/zeitwerk/version.rb +1 -1
- data/lib/zeitwerk.rb +1 -0
- metadata +5 -3
data/lib/zeitwerk/loader.rb
CHANGED
@@ -7,11 +7,15 @@ module Zeitwerk
|
|
7
7
|
require_relative "loader/helpers"
|
8
8
|
require_relative "loader/callbacks"
|
9
9
|
require_relative "loader/config"
|
10
|
+
require_relative "loader/eager_load"
|
11
|
+
|
12
|
+
extend Internal
|
10
13
|
|
11
14
|
include RealModName
|
12
15
|
include Callbacks
|
13
16
|
include Helpers
|
14
17
|
include Config
|
18
|
+
include EagerLoad
|
15
19
|
|
16
20
|
MUTEX = Mutex.new
|
17
21
|
private_constant :MUTEX
|
@@ -24,9 +28,9 @@ module Zeitwerk
|
|
24
28
|
# "/Users/fxn/blog/app/models/hotel/pricing.rb" => [Hotel, :Pricing]
|
25
29
|
# ...
|
26
30
|
#
|
27
|
-
# @private
|
28
31
|
# @sig Hash[String, [Module, Symbol]]
|
29
32
|
attr_reader :autoloads
|
33
|
+
internal :autoloads
|
30
34
|
|
31
35
|
# We keep track of autoloaded directories to remove them from the registry
|
32
36
|
# at the end of eager loading.
|
@@ -34,9 +38,9 @@ module Zeitwerk
|
|
34
38
|
# Files are removed as they are autoloaded, but directories need to wait due
|
35
39
|
# to concurrency (see why in Zeitwerk::Loader::Callbacks#on_dir_autoloaded).
|
36
40
|
#
|
37
|
-
# @private
|
38
41
|
# @sig Array[String]
|
39
42
|
attr_reader :autoloaded_dirs
|
43
|
+
internal :autoloaded_dirs
|
40
44
|
|
41
45
|
# Stores metadata needed for unloading. Its entries look like this:
|
42
46
|
#
|
@@ -50,11 +54,11 @@ module Zeitwerk
|
|
50
54
|
# If reloading is enabled, this hash is filled as constants are autoloaded
|
51
55
|
# or eager loaded. Otherwise, the collection remains empty.
|
52
56
|
#
|
53
|
-
# @private
|
54
57
|
# @sig Hash[String, [String, [Module, Symbol]]]
|
55
58
|
attr_reader :to_unload
|
59
|
+
internal :to_unload
|
56
60
|
|
57
|
-
# Maps constant paths
|
61
|
+
# Maps namespace constant paths to their respective directories.
|
58
62
|
#
|
59
63
|
# For example, given this mapping:
|
60
64
|
#
|
@@ -64,21 +68,32 @@ module Zeitwerk
|
|
64
68
|
# ...
|
65
69
|
# ]
|
66
70
|
#
|
67
|
-
# when `Admin` gets defined we know that it plays the role of a namespace
|
68
|
-
# that its children are spread over those directories. We'll visit them
|
69
|
-
# up the corresponding autoloads.
|
71
|
+
# when `Admin` gets defined we know that it plays the role of a namespace
|
72
|
+
# and that its children are spread over those directories. We'll visit them
|
73
|
+
# to set up the corresponding autoloads.
|
70
74
|
#
|
71
|
-
# @private
|
72
75
|
# @sig Hash[String, Array[String]]
|
73
|
-
attr_reader :
|
76
|
+
attr_reader :namespace_dirs
|
77
|
+
internal :namespace_dirs
|
78
|
+
|
79
|
+
# A shadowed file is a file managed by this loader that is ignored when
|
80
|
+
# setting autoloads because its matching constant is already taken.
|
81
|
+
#
|
82
|
+
# This private set is populated as we descend. For example, if the loader
|
83
|
+
# has only scanned the top-level, `shadowed_files` does not have shadowed
|
84
|
+
# files that may exist deep in the project tree yet.
|
85
|
+
#
|
86
|
+
# @sig Set[String]
|
87
|
+
attr_reader :shadowed_files
|
88
|
+
internal :shadowed_files
|
74
89
|
|
75
|
-
# @private
|
76
90
|
# @sig Mutex
|
77
91
|
attr_reader :mutex
|
92
|
+
private :mutex
|
78
93
|
|
79
|
-
# @private
|
80
94
|
# @sig Mutex
|
81
95
|
attr_reader :mutex2
|
96
|
+
private :mutex2
|
82
97
|
|
83
98
|
def initialize
|
84
99
|
super
|
@@ -86,7 +101,8 @@ module Zeitwerk
|
|
86
101
|
@autoloads = {}
|
87
102
|
@autoloaded_dirs = []
|
88
103
|
@to_unload = {}
|
89
|
-
@
|
104
|
+
@namespace_dirs = Hash.new { |h, cpath| h[cpath] = [] }
|
105
|
+
@shadowed_files = Set.new
|
90
106
|
@mutex = Mutex.new
|
91
107
|
@mutex2 = Mutex.new
|
92
108
|
@setup = false
|
@@ -95,15 +111,15 @@ module Zeitwerk
|
|
95
111
|
Registry.register_loader(self)
|
96
112
|
end
|
97
113
|
|
98
|
-
# Sets autoloads in the root
|
114
|
+
# Sets autoloads in the root namespaces.
|
99
115
|
#
|
100
116
|
# @sig () -> void
|
101
117
|
def setup
|
102
118
|
mutex.synchronize do
|
103
119
|
break if @setup
|
104
120
|
|
105
|
-
|
106
|
-
set_autoloads_in_dir(root_dir,
|
121
|
+
actual_roots.each do |root_dir, root_namespace|
|
122
|
+
set_autoloads_in_dir(root_dir, root_namespace)
|
107
123
|
end
|
108
124
|
|
109
125
|
on_setup_callbacks.each(&:call)
|
@@ -120,12 +136,14 @@ module Zeitwerk
|
|
120
136
|
# unload them.
|
121
137
|
#
|
122
138
|
# This method is public but undocumented. Main interface is `reload`, which
|
123
|
-
# means `unload` + `setup`. This one is
|
139
|
+
# means `unload` + `setup`. This one is available to be used together with
|
124
140
|
# `unregister`, which is undocumented too.
|
125
141
|
#
|
126
142
|
# @sig () -> void
|
127
143
|
def unload
|
128
144
|
mutex.synchronize do
|
145
|
+
raise SetupRequired unless @setup
|
146
|
+
|
129
147
|
# We are going to keep track of the files that were required by our
|
130
148
|
# autoloads to later remove them from $LOADED_FEATURES, thus making them
|
131
149
|
# loadable by Kernel#require again.
|
@@ -181,10 +199,11 @@ module Zeitwerk
|
|
181
199
|
autoloads.clear
|
182
200
|
autoloaded_dirs.clear
|
183
201
|
to_unload.clear
|
184
|
-
|
202
|
+
namespace_dirs.clear
|
203
|
+
shadowed_files.clear
|
185
204
|
|
186
205
|
Registry.on_unload(self)
|
187
|
-
ExplicitNamespace.
|
206
|
+
ExplicitNamespace.__unregister_loader(self)
|
188
207
|
|
189
208
|
@setup = false
|
190
209
|
@eager_loaded = false
|
@@ -201,6 +220,7 @@ module Zeitwerk
|
|
201
220
|
# @sig () -> void
|
202
221
|
def reload
|
203
222
|
raise ReloadingDisabledError unless reloading_enabled?
|
223
|
+
raise SetupRequired unless @setup
|
204
224
|
|
205
225
|
unload
|
206
226
|
recompute_ignored_paths
|
@@ -208,58 +228,6 @@ module Zeitwerk
|
|
208
228
|
setup
|
209
229
|
end
|
210
230
|
|
211
|
-
# Eager loads all files in the root directories, recursively. Files do not
|
212
|
-
# need to be in `$LOAD_PATH`, absolute file names are used. Ignored files
|
213
|
-
# are not eager loaded. You can opt-out specifically in specific files and
|
214
|
-
# directories with `do_not_eager_load`, and that can be overridden passing
|
215
|
-
# `force: true`.
|
216
|
-
#
|
217
|
-
# @sig (true | false) -> void
|
218
|
-
def eager_load(force: false)
|
219
|
-
mutex.synchronize do
|
220
|
-
break if @eager_loaded
|
221
|
-
|
222
|
-
log("eager load start") if logger
|
223
|
-
|
224
|
-
honour_exclusions = !force
|
225
|
-
|
226
|
-
queue = []
|
227
|
-
actual_root_dirs.each do |root_dir, namespace|
|
228
|
-
queue << [namespace, root_dir] unless honour_exclusions && excluded_from_eager_load?(root_dir)
|
229
|
-
end
|
230
|
-
|
231
|
-
while to_eager_load = queue.shift
|
232
|
-
namespace, dir = to_eager_load
|
233
|
-
|
234
|
-
ls(dir) do |basename, abspath|
|
235
|
-
next if honour_exclusions && excluded_from_eager_load?(abspath)
|
236
|
-
|
237
|
-
if ruby?(abspath)
|
238
|
-
if cref = autoloads[abspath]
|
239
|
-
cget(*cref)
|
240
|
-
end
|
241
|
-
elsif !root_dirs.key?(abspath)
|
242
|
-
if collapse?(abspath)
|
243
|
-
queue << [namespace, abspath]
|
244
|
-
else
|
245
|
-
cname = inflector.camelize(basename, abspath)
|
246
|
-
queue << [cget(namespace, cname), abspath]
|
247
|
-
end
|
248
|
-
end
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
autoloaded_dirs.each do |autoloaded_dir|
|
253
|
-
Registry.unregister_autoload(autoloaded_dir)
|
254
|
-
end
|
255
|
-
autoloaded_dirs.clear
|
256
|
-
|
257
|
-
@eager_loaded = true
|
258
|
-
|
259
|
-
log("eager load end") if logger
|
260
|
-
end
|
261
|
-
end
|
262
|
-
|
263
231
|
# Says if the given constant path would be unloaded on reload. This
|
264
232
|
# predicate returns `false` if reloading is disabled.
|
265
233
|
#
|
@@ -282,18 +250,29 @@ module Zeitwerk
|
|
282
250
|
# @sig () -> void
|
283
251
|
def unregister
|
284
252
|
Registry.unregister_loader(self)
|
285
|
-
ExplicitNamespace.
|
253
|
+
ExplicitNamespace.__unregister_loader(self)
|
254
|
+
end
|
255
|
+
|
256
|
+
# The return value of this predicate is only meaningful if the loader has
|
257
|
+
# scanned the file. This is the case in the spots where we use it.
|
258
|
+
#
|
259
|
+
# @sig (String) -> Boolean
|
260
|
+
internal def shadowed_file?(file)
|
261
|
+
shadowed_files.member?(file)
|
286
262
|
end
|
287
263
|
|
288
264
|
# --- Class methods ---------------------------------------------------------------------------
|
289
265
|
|
290
266
|
class << self
|
267
|
+
include RealModName
|
268
|
+
|
291
269
|
# @sig #call | #debug | nil
|
292
270
|
attr_accessor :default_logger
|
293
271
|
|
294
272
|
# This is a shortcut for
|
295
273
|
#
|
296
274
|
# require "zeitwerk"
|
275
|
+
#
|
297
276
|
# loader = Zeitwerk::Loader.new
|
298
277
|
# loader.tag = File.basename(__FILE__, ".rb")
|
299
278
|
# loader.inflector = Zeitwerk::GemInflector.new(__FILE__)
|
@@ -308,14 +287,64 @@ module Zeitwerk
|
|
308
287
|
# @sig (bool) -> Zeitwerk::GemLoader
|
309
288
|
def for_gem(warn_on_extra_files: true)
|
310
289
|
called_from = caller_locations(1, 1).first.path
|
311
|
-
Registry.loader_for_gem(called_from, warn_on_extra_files: warn_on_extra_files)
|
290
|
+
Registry.loader_for_gem(called_from, namespace: Object, warn_on_extra_files: warn_on_extra_files)
|
291
|
+
end
|
292
|
+
|
293
|
+
# This is a shortcut for
|
294
|
+
#
|
295
|
+
# require "zeitwerk"
|
296
|
+
#
|
297
|
+
# loader = Zeitwerk::Loader.new
|
298
|
+
# loader.tag = namespace.name + "-" + File.basename(__FILE__, ".rb")
|
299
|
+
# loader.inflector = Zeitwerk::GemInflector.new(__FILE__)
|
300
|
+
# loader.push_dir(__dir__, namespace: namespace)
|
301
|
+
#
|
302
|
+
# except that this method returns the same object in subsequent calls from
|
303
|
+
# the same file, in the unlikely case the gem wants to be able to reload.
|
304
|
+
#
|
305
|
+
# This method returns a subclass of Zeitwerk::Loader, but the exact type
|
306
|
+
# is private, client code can only rely on the interface.
|
307
|
+
#
|
308
|
+
# @sig (bool) -> Zeitwerk::GemLoader
|
309
|
+
def for_gem_extension(namespace)
|
310
|
+
unless namespace.is_a?(Module) # Note that Class < Module.
|
311
|
+
raise Zeitwerk::Error, "#{namespace.inspect} is not a class or module object, should be"
|
312
|
+
end
|
313
|
+
|
314
|
+
unless real_mod_name(namespace)
|
315
|
+
raise Zeitwerk::Error, "extending anonymous namespaces is unsupported"
|
316
|
+
end
|
317
|
+
|
318
|
+
called_from = caller_locations(1, 1).first.path
|
319
|
+
Registry.loader_for_gem(called_from, namespace: namespace, warn_on_extra_files: false)
|
312
320
|
end
|
313
321
|
|
314
|
-
# Broadcasts `eager_load` to all loaders.
|
322
|
+
# Broadcasts `eager_load` to all loaders. Those that have not been setup
|
323
|
+
# are skipped.
|
315
324
|
#
|
316
325
|
# @sig () -> void
|
317
326
|
def eager_load_all
|
318
|
-
Registry.loaders.each
|
327
|
+
Registry.loaders.each do |loader|
|
328
|
+
begin
|
329
|
+
loader.eager_load
|
330
|
+
rescue SetupRequired
|
331
|
+
# This is fine, we eager load what can be eager loaded.
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
# Broadcasts `eager_load_namespace` to all loaders. Those that have not
|
337
|
+
# been setup are skipped.
|
338
|
+
#
|
339
|
+
# @sig (Module) -> void
|
340
|
+
def eager_load_namespace(mod)
|
341
|
+
Registry.loaders.each do |loader|
|
342
|
+
begin
|
343
|
+
loader.eager_load_namespace(mod)
|
344
|
+
rescue SetupRequired
|
345
|
+
# This is fine, we eager load what can be eager loaded.
|
346
|
+
end
|
347
|
+
end
|
319
348
|
end
|
320
349
|
|
321
350
|
# Returns an array with the absolute paths of the root directories of all
|
@@ -327,10 +356,8 @@ module Zeitwerk
|
|
327
356
|
end
|
328
357
|
end
|
329
358
|
|
330
|
-
private # -------------------------------------------------------------------------------------
|
331
|
-
|
332
359
|
# @sig (String, Module) -> void
|
333
|
-
def set_autoloads_in_dir(dir, parent)
|
360
|
+
private def set_autoloads_in_dir(dir, parent)
|
334
361
|
ls(dir) do |basename, abspath|
|
335
362
|
begin
|
336
363
|
if ruby?(basename)
|
@@ -338,19 +365,11 @@ module Zeitwerk
|
|
338
365
|
cname = inflector.camelize(basename, abspath).to_sym
|
339
366
|
autoload_file(parent, cname, abspath)
|
340
367
|
else
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
# To resolve the ambiguity file name -> constant path this introduces,
|
345
|
-
# the `app/models/concerns` directory is totally ignored as a namespace,
|
346
|
-
# it counts only as root. The guard checks that.
|
347
|
-
unless root_dir?(abspath)
|
368
|
+
if collapse?(abspath)
|
369
|
+
set_autoloads_in_dir(abspath, parent)
|
370
|
+
else
|
348
371
|
cname = inflector.camelize(basename, abspath).to_sym
|
349
|
-
|
350
|
-
set_autoloads_in_dir(abspath, parent)
|
351
|
-
else
|
352
|
-
autoload_subdir(parent, cname, abspath)
|
353
|
-
end
|
372
|
+
autoload_subdir(parent, cname, abspath)
|
354
373
|
end
|
355
374
|
end
|
356
375
|
rescue ::NameError => error
|
@@ -373,17 +392,26 @@ module Zeitwerk
|
|
373
392
|
end
|
374
393
|
|
375
394
|
# @sig (Module, Symbol, String) -> void
|
376
|
-
def autoload_subdir(parent, cname, subdir)
|
395
|
+
private def autoload_subdir(parent, cname, subdir)
|
377
396
|
if autoload_path = autoload_path_set_by_me_for?(parent, cname)
|
378
397
|
cpath = cpath(parent, cname)
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
398
|
+
if ruby?(autoload_path)
|
399
|
+
# Scanning visited a Ruby file first, and now a directory for the same
|
400
|
+
# constant has been found. This means we are dealing with an explicit
|
401
|
+
# namespace whose definition was seen first.
|
402
|
+
#
|
403
|
+
# Registering is idempotent, and we have to keep the autoload pointing
|
404
|
+
# to the file. This may run again if more directories are found later
|
405
|
+
# on, no big deal.
|
406
|
+
register_explicit_namespace(cpath)
|
407
|
+
end
|
408
|
+
# If the existing autoload points to a file, it has to be preserved, if
|
409
|
+
# not, it is fine as it is. In either case, we do not need to override.
|
410
|
+
# Just remember the subdirectory conforms this namespace.
|
411
|
+
namespace_dirs[cpath] << subdir
|
384
412
|
elsif !cdef?(parent, cname)
|
385
413
|
# First time we find this namespace, set an autoload for it.
|
386
|
-
|
414
|
+
namespace_dirs[cpath(parent, cname)] << subdir
|
387
415
|
set_autoload(parent, cname, subdir)
|
388
416
|
else
|
389
417
|
# For whatever reason the constant that corresponds to this namespace has
|
@@ -394,10 +422,11 @@ module Zeitwerk
|
|
394
422
|
end
|
395
423
|
|
396
424
|
# @sig (Module, Symbol, String) -> void
|
397
|
-
def autoload_file(parent, cname, file)
|
425
|
+
private def autoload_file(parent, cname, file)
|
398
426
|
if autoload_path = strict_autoload_path(parent, cname) || Registry.inception?(cpath(parent, cname))
|
399
427
|
# First autoload for a Ruby file wins, just ignore subsequent ones.
|
400
428
|
if ruby?(autoload_path)
|
429
|
+
shadowed_files << file
|
401
430
|
log("file #{file} is ignored because #{autoload_path} has precedence") if logger
|
402
431
|
else
|
403
432
|
promote_namespace_from_implicit_to_explicit(
|
@@ -408,6 +437,7 @@ module Zeitwerk
|
|
408
437
|
)
|
409
438
|
end
|
410
439
|
elsif cdef?(parent, cname)
|
440
|
+
shadowed_files << file
|
411
441
|
log("file #{file} is ignored because #{cpath(parent, cname)} is already defined") if logger
|
412
442
|
else
|
413
443
|
set_autoload(parent, cname, file)
|
@@ -418,7 +448,7 @@ module Zeitwerk
|
|
418
448
|
# the file where we've found the namespace is explicitly defined.
|
419
449
|
#
|
420
450
|
# @sig (dir: String, file: String, parent: Module, cname: Symbol) -> void
|
421
|
-
def promote_namespace_from_implicit_to_explicit(dir:, file:, parent:, cname:)
|
451
|
+
private def promote_namespace_from_implicit_to_explicit(dir:, file:, parent:, cname:)
|
422
452
|
autoloads.delete(dir)
|
423
453
|
Registry.unregister_autoload(dir)
|
424
454
|
|
@@ -429,7 +459,7 @@ module Zeitwerk
|
|
429
459
|
end
|
430
460
|
|
431
461
|
# @sig (Module, Symbol, String) -> void
|
432
|
-
def set_autoload(parent, cname, abspath)
|
462
|
+
private def set_autoload(parent, cname, abspath)
|
433
463
|
parent.autoload(cname, abspath)
|
434
464
|
|
435
465
|
if logger
|
@@ -450,7 +480,7 @@ module Zeitwerk
|
|
450
480
|
end
|
451
481
|
|
452
482
|
# @sig (Module, Symbol) -> String?
|
453
|
-
def autoload_path_set_by_me_for?(parent, cname)
|
483
|
+
private def autoload_path_set_by_me_for?(parent, cname)
|
454
484
|
if autoload_path = strict_autoload_path(parent, cname)
|
455
485
|
autoload_path if autoloads.key?(autoload_path)
|
456
486
|
else
|
@@ -459,26 +489,27 @@ module Zeitwerk
|
|
459
489
|
end
|
460
490
|
|
461
491
|
# @sig (String) -> void
|
462
|
-
def register_explicit_namespace(cpath)
|
463
|
-
ExplicitNamespace.
|
492
|
+
private def register_explicit_namespace(cpath)
|
493
|
+
ExplicitNamespace.__register(cpath, self)
|
464
494
|
end
|
465
495
|
|
466
496
|
# @sig (String) -> void
|
467
|
-
def raise_if_conflicting_directory(dir)
|
497
|
+
private def raise_if_conflicting_directory(dir)
|
468
498
|
MUTEX.synchronize do
|
499
|
+
dir_slash = dir + "/"
|
500
|
+
|
469
501
|
Registry.loaders.each do |loader|
|
470
502
|
next if loader == self
|
471
|
-
next if loader.
|
503
|
+
next if loader.__ignores?(dir)
|
472
504
|
|
473
|
-
|
474
|
-
loader.root_dirs.each do |root_dir, _namespace|
|
505
|
+
loader.__roots.each_key do |root_dir|
|
475
506
|
next if ignores?(root_dir)
|
476
507
|
|
477
|
-
|
478
|
-
if
|
508
|
+
root_dir_slash = root_dir + "/"
|
509
|
+
if dir_slash.start_with?(root_dir_slash) || root_dir_slash.start_with?(dir_slash)
|
479
510
|
require "pp" # Needed for pretty_inspect, even in Ruby 2.5.
|
480
511
|
raise Error,
|
481
|
-
"loader\n\n#{pretty_inspect}\n\nwants to manage directory #{dir
|
512
|
+
"loader\n\n#{pretty_inspect}\n\nwants to manage directory #{dir}," \
|
482
513
|
" which is already managed by\n\n#{loader.pretty_inspect}\n"
|
483
514
|
EOS
|
484
515
|
end
|
@@ -488,23 +519,23 @@ module Zeitwerk
|
|
488
519
|
end
|
489
520
|
|
490
521
|
# @sig (String, Object, String) -> void
|
491
|
-
def run_on_unload_callbacks(cpath, value, abspath)
|
522
|
+
private def run_on_unload_callbacks(cpath, value, abspath)
|
492
523
|
# Order matters. If present, run the most specific one.
|
493
524
|
on_unload_callbacks[cpath]&.each { |c| c.call(value, abspath) }
|
494
525
|
on_unload_callbacks[:ANY]&.each { |c| c.call(cpath, value, abspath) }
|
495
526
|
end
|
496
527
|
|
497
528
|
# @sig (Module, Symbol) -> void
|
498
|
-
def unload_autoload(parent, cname)
|
499
|
-
parent
|
529
|
+
private def unload_autoload(parent, cname)
|
530
|
+
crem(parent, cname)
|
500
531
|
log("autoload for #{cpath(parent, cname)} removed") if logger
|
501
532
|
end
|
502
533
|
|
503
534
|
# @sig (Module, Symbol) -> void
|
504
|
-
def unload_cref(parent, cname)
|
535
|
+
private def unload_cref(parent, cname)
|
505
536
|
# Let's optimistically remove_const. The way we use it, this is going to
|
506
537
|
# succeed always if all is good.
|
507
|
-
parent
|
538
|
+
crem(parent, cname)
|
508
539
|
rescue ::NameError
|
509
540
|
# There are a few edge scenarios in which this may happen. If the constant
|
510
541
|
# is gone, that is OK, anyway.
|
data/lib/zeitwerk/registry.rb
CHANGED
@@ -86,8 +86,8 @@ module Zeitwerk
|
|
86
86
|
#
|
87
87
|
# @private
|
88
88
|
# @sig (String) -> Zeitwerk::Loader
|
89
|
-
def loader_for_gem(root_file, warn_on_extra_files:)
|
90
|
-
gem_loaders_by_root_file[root_file] ||= GemLoader.
|
89
|
+
def loader_for_gem(root_file, namespace:, warn_on_extra_files:)
|
90
|
+
gem_loaders_by_root_file[root_file] ||= GemLoader.__new(root_file, namespace: namespace, warn_on_extra_files: warn_on_extra_files)
|
91
91
|
end
|
92
92
|
|
93
93
|
# @private
|
data/lib/zeitwerk/version.rb
CHANGED
data/lib/zeitwerk.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zeitwerk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.6.
|
4
|
+
version: 2.6.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Xavier Noria
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-04-28 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |2
|
14
14
|
Zeitwerk implements constant autoloading with Ruby semantics. Each gem
|
@@ -28,10 +28,12 @@ files:
|
|
28
28
|
- lib/zeitwerk/gem_inflector.rb
|
29
29
|
- lib/zeitwerk/gem_loader.rb
|
30
30
|
- lib/zeitwerk/inflector.rb
|
31
|
+
- lib/zeitwerk/internal.rb
|
31
32
|
- lib/zeitwerk/kernel.rb
|
32
33
|
- lib/zeitwerk/loader.rb
|
33
34
|
- lib/zeitwerk/loader/callbacks.rb
|
34
35
|
- lib/zeitwerk/loader/config.rb
|
36
|
+
- lib/zeitwerk/loader/eager_load.rb
|
35
37
|
- lib/zeitwerk/loader/helpers.rb
|
36
38
|
- lib/zeitwerk/real_mod_name.rb
|
37
39
|
- lib/zeitwerk/registry.rb
|
@@ -59,7 +61,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
59
61
|
- !ruby/object:Gem::Version
|
60
62
|
version: '0'
|
61
63
|
requirements: []
|
62
|
-
rubygems_version: 3.
|
64
|
+
rubygems_version: 3.4.11
|
63
65
|
signing_key:
|
64
66
|
specification_version: 4
|
65
67
|
summary: Efficient and thread-safe constant autoloader
|