zeitwerk 2.6.9 → 2.6.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/zeitwerk/loader/callbacks.rb +4 -3
- data/lib/zeitwerk/loader/helpers.rb +44 -0
- data/lib/zeitwerk/loader.rb +19 -51
- data/lib/zeitwerk/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0dd43924a88fceee915258e119a02df8fb173199576f52cf18c8298aab091361
|
4
|
+
data.tar.gz: 6aeeced1ce99e28238ebd1488a543da6ba4fb885e283f999cec30a49db3a0ccf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca6b895667327b79fe51d504de760150aeceba5edb64400a6976962c1241bb8061f5c29e4d8584ba888694a0b1b30cf2f149f66f52181089fda262dde541d902
|
7
|
+
data.tar.gz: 8393b41bda4187ce0195ce5b1192455a2bc574291188b0eba86f31af88fc66e3d441717823ac07407f8c7be4e4a97de06cb5bc1922a133e66ed51cc91f6eb1c7
|
data/README.md
CHANGED
@@ -1296,7 +1296,7 @@ If the argument corresponds to an [ignored file or directory](#ignoring-parts-of
|
|
1296
1296
|
loader.cpath_expected_at("non_existing_file.rb") # => Zeitwerk::Error
|
1297
1297
|
```
|
1298
1298
|
|
1299
|
-
`
|
1299
|
+
`Zeitwerk::NameError` is raised if a constant path cannot be derived from it:
|
1300
1300
|
|
1301
1301
|
```ruby
|
1302
1302
|
loader.cpath_expected_at("8.rb") # => Zeitwerk::NameError
|
@@ -32,8 +32,9 @@ module Zeitwerk::Loader::Callbacks
|
|
32
32
|
# @private
|
33
33
|
# @sig (String) -> void
|
34
34
|
def on_dir_autoloaded(dir)
|
35
|
-
# Module#autoload does not serialize concurrent requires, and
|
36
|
-
# directories ourselves
|
35
|
+
# Module#autoload does not serialize concurrent requires in CRuby < 3.2, and
|
36
|
+
# we handle directories ourselves without going through Kernel#require, so
|
37
|
+
# the callback needs to account for concurrency.
|
37
38
|
#
|
38
39
|
# Multi-threading would introduce a race condition here in which thread t1
|
39
40
|
# autovivifies the module, and while autoloads for its children are being
|
@@ -43,7 +44,7 @@ module Zeitwerk::Loader::Callbacks
|
|
43
44
|
# That not only would reassign the constant (undesirable per se) but, worse,
|
44
45
|
# the module object created by t2 wouldn't have any of the autoloads for its
|
45
46
|
# children, since t1 would have correctly deleted its namespace_dirs entry.
|
46
|
-
|
47
|
+
dirs_autoload_monitor.synchronize do
|
47
48
|
if cref = autoloads.delete(dir)
|
48
49
|
autovivified_module = cref[0].const_set(cref[1], Module.new)
|
49
50
|
cpath = autovivified_module.name
|
@@ -140,4 +140,48 @@ module Zeitwerk::Loader::Helpers
|
|
140
140
|
private def crem(parent, cname)
|
141
141
|
parent.__send__(:remove_const, cname)
|
142
142
|
end
|
143
|
+
|
144
|
+
CNAME_VALIDATOR = Module.new
|
145
|
+
private_constant :CNAME_VALIDATOR
|
146
|
+
|
147
|
+
# @raise [Zeitwerk::NameError]
|
148
|
+
# @sig (String, String) -> Symbol
|
149
|
+
private def cname_for(basename, abspath)
|
150
|
+
cname = inflector.camelize(basename, abspath)
|
151
|
+
|
152
|
+
unless cname.is_a?(String)
|
153
|
+
raise TypeError, "#{inflector.class}#camelize must return a String, received #{cname.inspect}"
|
154
|
+
end
|
155
|
+
|
156
|
+
if cname.include?("::")
|
157
|
+
raise Zeitwerk::NameError.new(<<~MESSAGE, cname)
|
158
|
+
wrong constant name #{cname} inferred by #{inflector.class} from
|
159
|
+
|
160
|
+
#{abspath}
|
161
|
+
|
162
|
+
#{inflector.class}#camelize should return a simple constant name without "::"
|
163
|
+
MESSAGE
|
164
|
+
end
|
165
|
+
|
166
|
+
begin
|
167
|
+
CNAME_VALIDATOR.const_defined?(cname, false)
|
168
|
+
rescue ::NameError => error
|
169
|
+
path_type = ruby?(abspath) ? "file" : "directory"
|
170
|
+
|
171
|
+
raise Zeitwerk::NameError.new(<<~MESSAGE, error.name)
|
172
|
+
#{error.message} inferred by #{inflector.class} from #{path_type}
|
173
|
+
|
174
|
+
#{abspath}
|
175
|
+
|
176
|
+
Possible ways to address this:
|
177
|
+
|
178
|
+
* Tell Zeitwerk to ignore this particular #{path_type}.
|
179
|
+
* Tell Zeitwerk to ignore one of its parent directories.
|
180
|
+
* Rename the #{path_type} to comply with the naming conventions.
|
181
|
+
* Modify the inflector to handle this case.
|
182
|
+
MESSAGE
|
183
|
+
end
|
184
|
+
|
185
|
+
cname.to_sym
|
186
|
+
end
|
143
187
|
end
|
data/lib/zeitwerk/loader.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "monitor"
|
3
4
|
require "set"
|
4
5
|
|
5
6
|
module Zeitwerk
|
@@ -91,9 +92,9 @@ module Zeitwerk
|
|
91
92
|
attr_reader :mutex
|
92
93
|
private :mutex
|
93
94
|
|
94
|
-
# @sig
|
95
|
-
attr_reader :
|
96
|
-
private :
|
95
|
+
# @sig Monitor
|
96
|
+
attr_reader :dirs_autoload_monitor
|
97
|
+
private :dirs_autoload_monitor
|
97
98
|
|
98
99
|
def initialize
|
99
100
|
super
|
@@ -103,11 +104,12 @@ module Zeitwerk
|
|
103
104
|
@to_unload = {}
|
104
105
|
@namespace_dirs = Hash.new { |h, cpath| h[cpath] = [] }
|
105
106
|
@shadowed_files = Set.new
|
106
|
-
@mutex = Mutex.new
|
107
|
-
@mutex2 = Mutex.new
|
108
107
|
@setup = false
|
109
108
|
@eager_loaded = false
|
110
109
|
|
110
|
+
@mutex = Mutex.new
|
111
|
+
@dirs_autoload_monitor = Monitor.new
|
112
|
+
|
111
113
|
Registry.register_loader(self)
|
112
114
|
end
|
113
115
|
|
@@ -237,15 +239,13 @@ module Zeitwerk
|
|
237
239
|
return unless dir?(abspath) || ruby?(abspath)
|
238
240
|
return if ignored_path?(abspath)
|
239
241
|
|
240
|
-
|
241
|
-
abspaths = []
|
242
|
+
paths = []
|
242
243
|
|
243
244
|
if ruby?(abspath)
|
244
245
|
basename = File.basename(abspath, ".rb")
|
245
246
|
return if hidden?(basename)
|
246
247
|
|
247
|
-
|
248
|
-
abspaths << abspath
|
248
|
+
paths << [basename, abspath]
|
249
249
|
walk_up_from = File.dirname(abspath)
|
250
250
|
else
|
251
251
|
walk_up_from = abspath
|
@@ -260,28 +260,15 @@ module Zeitwerk
|
|
260
260
|
basename = File.basename(dir)
|
261
261
|
return if hidden?(basename)
|
262
262
|
|
263
|
-
unless collapse?(dir)
|
264
|
-
cnames << inflector.camelize(basename, dir).to_sym
|
265
|
-
abspaths << dir
|
266
|
-
end
|
263
|
+
paths << [basename, abspath] unless collapse?(dir)
|
267
264
|
end
|
268
265
|
|
269
266
|
return unless root_namespace
|
270
267
|
|
271
|
-
if
|
268
|
+
if paths.empty?
|
272
269
|
real_mod_name(root_namespace)
|
273
270
|
else
|
274
|
-
|
275
|
-
# problematic one, if any.
|
276
|
-
cnames.reverse!
|
277
|
-
|
278
|
-
cname_validator = Module.new
|
279
|
-
cnames.each_with_index do |cname, i|
|
280
|
-
cname_validator.const_defined?(cname, false)
|
281
|
-
rescue ::NameError
|
282
|
-
j = -(i + 1)
|
283
|
-
raise Zeitwerk::NameError.new("cannot derive a constant name from #{abspaths[j]}")
|
284
|
-
end
|
271
|
+
cnames = paths.reverse_each.map { |b, a| cname_for(b, a) }
|
285
272
|
|
286
273
|
if root_namespace == Object
|
287
274
|
cnames.join("::")
|
@@ -422,34 +409,15 @@ module Zeitwerk
|
|
422
409
|
# @sig (String, Module) -> void
|
423
410
|
private def set_autoloads_in_dir(dir, parent)
|
424
411
|
ls(dir) do |basename, abspath|
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
412
|
+
if ruby?(basename)
|
413
|
+
basename.delete_suffix!(".rb")
|
414
|
+
autoload_file(parent, cname_for(basename, abspath), abspath)
|
415
|
+
else
|
416
|
+
if collapse?(abspath)
|
417
|
+
set_autoloads_in_dir(abspath, parent)
|
430
418
|
else
|
431
|
-
|
432
|
-
set_autoloads_in_dir(abspath, parent)
|
433
|
-
else
|
434
|
-
cname = inflector.camelize(basename, abspath).to_sym
|
435
|
-
autoload_subdir(parent, cname, abspath)
|
436
|
-
end
|
419
|
+
autoload_subdir(parent, cname_for(basename, abspath), abspath)
|
437
420
|
end
|
438
|
-
rescue ::NameError => error
|
439
|
-
path_type = ruby?(abspath) ? "file" : "directory"
|
440
|
-
|
441
|
-
raise NameError.new(<<~MESSAGE, error.name)
|
442
|
-
#{error.message} inferred by #{inflector.class} from #{path_type}
|
443
|
-
|
444
|
-
#{abspath}
|
445
|
-
|
446
|
-
Possible ways to address this:
|
447
|
-
|
448
|
-
* Tell Zeitwerk to ignore this particular #{path_type}.
|
449
|
-
* Tell Zeitwerk to ignore one of its parent directories.
|
450
|
-
* Rename the #{path_type} to comply with the naming conventions.
|
451
|
-
* Modify the inflector to handle this case.
|
452
|
-
MESSAGE
|
453
421
|
end
|
454
422
|
end
|
455
423
|
end
|
data/lib/zeitwerk/version.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.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Xavier Noria
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-02 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |2
|
14
14
|
Zeitwerk implements constant autoloading with Ruby semantics. Each gem
|