zeitwerk 2.6.13 → 2.6.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +49 -1
- data/lib/zeitwerk/gem_loader.rb +1 -2
- data/lib/zeitwerk/loader/eager_load.rb +9 -7
- data/lib/zeitwerk/loader/helpers.rb +10 -6
- data/lib/zeitwerk/loader.rb +67 -33
- data/lib/zeitwerk/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 06d0e5697b46d13993ad46322296a64f44e05a83087281944378fc79ee8067ba
|
4
|
+
data.tar.gz: 00371f27991d326fcbdfbf4e8e0668925a24d81662bc64890b3fbe653ae00243
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a2666faaf75882a06ad5a2b408e1cff593744b15fca61864a20c255a2868af22f8b60a7125c5d61f83374efa5e1a21ee627d17ea0ef8f3586a71efba4f3fa8e
|
7
|
+
data.tar.gz: aad3c7421105576216338a3eb521bb44188d9f2a371f69e5a069e4b619ab1d101b1fb9477bc55ef7bf35c50942bd1ddb5c50571392e9e487eedb9a09e5e9a778
|
data/README.md
CHANGED
@@ -60,6 +60,7 @@
|
|
60
60
|
- [Introspection](#introspection)
|
61
61
|
- [`Zeitwerk::Loader#dirs`](#zeitwerkloaderdirs)
|
62
62
|
- [`Zeitwerk::Loader#cpath_expected_at`](#zeitwerkloadercpath_expected_at)
|
63
|
+
- [`Zeitwerk::Loader#all_expected_cpaths`](#zeitwerkloaderall_expected_cpaths)
|
63
64
|
- [Encodings](#encodings)
|
64
65
|
- [Rules of thumb](#rules-of-thumb)
|
65
66
|
- [Debuggers](#debuggers)
|
@@ -259,7 +260,7 @@ app/controllers/admin/users_controller.rb -> Admin::UsersController
|
|
259
260
|
|
260
261
|
and does not have a file called `admin.rb`, Zeitwerk automatically creates an `Admin` module on your behalf the first time `Admin` is used.
|
261
262
|
|
262
|
-
To trigger this behavior, the directory must contain non-ignored Ruby files with the
|
263
|
+
To trigger this behavior, the directory must contain non-ignored Ruby files with the ".rb" extension, either directly or recursively. Otherwise, the directory is ignored. This condition is reevaluated during reloads.
|
263
264
|
|
264
265
|
<a id="markdown-explicit-namespaces" name="explicit-namespaces"></a>
|
265
266
|
### Explicit namespaces
|
@@ -1330,6 +1331,53 @@ loader.cpath_expected_at("8.rb") # => Zeitwerk::NameError
|
|
1330
1331
|
|
1331
1332
|
This method does not parse file contents and does not guarantee files define the returned constant path. It just says which is the _expected_ one.
|
1332
1333
|
|
1334
|
+
`Zeitwerk::Loader#cpath_expected_at` is designed to be used with individual paths. If you want to know all the expected constant paths in the project, please use `Zeitwerk::Loader#all_expected_cpaths`, documented next.
|
1335
|
+
|
1336
|
+
<a id="markdown-zeitwerkloaderall_expected_cpaths" name="zeitwerkloaderall_expected_cpaths"></a>
|
1337
|
+
#### `Zeitwerk::Loader#all_expected_cpaths`
|
1338
|
+
|
1339
|
+
The method `Zeitwerk::Loader#all_expected_cpaths` returns a hash that maps the absolute paths of the files and directories managed by the receiver to their corresponding expected constant paths.
|
1340
|
+
|
1341
|
+
Ignored files or directories are not included in the result. Directories that do not contain any files with the ".rb" extension (recursively) are also excluded. Additionally, if a directory contains files with the ".rb" extension but all of them are ignored, it is treated as if it contains no ".rb" files.
|
1342
|
+
|
1343
|
+
For example, if `lib` is the root directory of a gem with the following contents:
|
1344
|
+
|
1345
|
+
```
|
1346
|
+
lib/my_gem.rb
|
1347
|
+
lib/my_gem/version.rb
|
1348
|
+
lib/my_gem/ignored.rb
|
1349
|
+
lib/my_gem/drivers/unix.rb
|
1350
|
+
lib/my_gem/drivers/windows.rb
|
1351
|
+
lib/my_gem/collapsed/foo.rb
|
1352
|
+
lib/tasks/my_gem.rake
|
1353
|
+
```
|
1354
|
+
|
1355
|
+
`Zeitwerk::Loader#all_expected_cpaths` would return (maybe in a different order):
|
1356
|
+
|
1357
|
+
```ruby
|
1358
|
+
{
|
1359
|
+
"/.../lib" => "Object",
|
1360
|
+
"/.../lib/my_gem.rb" => "MyGem",
|
1361
|
+
"/.../lib/my_gem" => "MyGem",
|
1362
|
+
"/.../lib/my_gem/version.rb" => "MyGem::VERSION",
|
1363
|
+
"/.../lib/my_gem/drivers" => "MyGem::Drivers",
|
1364
|
+
"/.../lib/my_gem/drivers/unix.rb" => "MyGem::Drivers::Unix",
|
1365
|
+
"/.../lib/my_gem/drivers/windows.rb" => "MyGem::Drivers::Windows",
|
1366
|
+
"/.../lib/my_gem/collapsed" => "MyGem"
|
1367
|
+
"/.../lib/my_gem/collapsed/foo.rb" => "MyGem::Foo"
|
1368
|
+
}
|
1369
|
+
```
|
1370
|
+
|
1371
|
+
As the names suggest, the previous example assumes `lib/my_gem/ignored.rb` is ignored (so, not present in the returned hash), and `lib/my_gem/collapsed` is a collapsed directory (so the expected namespace at that level is still `MyGem`, this is an edge case).
|
1372
|
+
|
1373
|
+
Directory paths are guaranteed to not have trailing slashes.
|
1374
|
+
|
1375
|
+
Note that `lib/tasks` is not present in the hash because it contains no files with the ".rb" extension. The loader does not consider the `lib/tasks` directory to represent a Ruby namespace; therefore, it does not end up in the hash.
|
1376
|
+
|
1377
|
+
The order of the hash entries is undefined.
|
1378
|
+
|
1379
|
+
This method does not parse file contents and does not guarantee files define the corresponding constant paths. It just says which are the _expected_ ones.
|
1380
|
+
|
1333
1381
|
<a id="markdown-encodings" name="encodings"></a>
|
1334
1382
|
### Encodings
|
1335
1383
|
|
data/lib/zeitwerk/gem_loader.rb
CHANGED
@@ -42,13 +42,12 @@ module Zeitwerk
|
|
42
42
|
def warn_on_extra_files
|
43
43
|
expected_namespace_dir = @root_file.delete_suffix(".rb")
|
44
44
|
|
45
|
-
ls(@root_dir) do |basename, abspath|
|
45
|
+
ls(@root_dir) do |basename, abspath, ftype|
|
46
46
|
next if abspath == @root_file
|
47
47
|
next if abspath == expected_namespace_dir
|
48
48
|
|
49
49
|
basename_without_ext = basename.delete_suffix(".rb")
|
50
50
|
cname = inflector.camelize(basename_without_ext, abspath).to_sym
|
51
|
-
ftype = dir?(abspath) ? "directory" : "file"
|
52
51
|
|
53
52
|
warn(<<~EOS)
|
54
53
|
WARNING: Zeitwerk defines the constant #{cname} after the #{ftype}
|
@@ -164,13 +164,13 @@ module Zeitwerk::Loader::EagerLoad
|
|
164
164
|
log("eager load directory #{dir} start") if logger
|
165
165
|
|
166
166
|
queue = [[dir, namespace]]
|
167
|
-
|
168
|
-
dir, namespace =
|
167
|
+
until queue.empty?
|
168
|
+
dir, namespace = queue.shift
|
169
169
|
|
170
|
-
ls(dir) do |basename, abspath|
|
170
|
+
ls(dir) do |basename, abspath, ftype|
|
171
171
|
next if honour_exclusions && eager_load_exclusions.member?(abspath)
|
172
172
|
|
173
|
-
if
|
173
|
+
if ftype == :file
|
174
174
|
if (cref = autoloads[abspath])
|
175
175
|
cget(*cref)
|
176
176
|
end
|
@@ -209,9 +209,11 @@ module Zeitwerk::Loader::EagerLoad
|
|
209
209
|
next_dirs = []
|
210
210
|
|
211
211
|
suffix.split("::").each do |segment|
|
212
|
-
|
213
|
-
|
214
|
-
|
212
|
+
until dirs.empty?
|
213
|
+
dir = dirs.shift
|
214
|
+
|
215
|
+
ls(dir) do |basename, abspath, ftype|
|
216
|
+
next unless ftype == :directory
|
215
217
|
|
216
218
|
if collapse?(abspath)
|
217
219
|
dirs << abspath
|
@@ -31,13 +31,15 @@ module Zeitwerk::Loader::Helpers
|
|
31
31
|
if dir?(abspath)
|
32
32
|
next if roots.key?(abspath)
|
33
33
|
next if !has_at_least_one_ruby_file?(abspath)
|
34
|
+
ftype = :directory
|
34
35
|
else
|
35
36
|
next unless ruby?(abspath)
|
37
|
+
ftype = :file
|
36
38
|
end
|
37
39
|
|
38
40
|
# We freeze abspath because that saves allocations when passed later to
|
39
41
|
# File methods. See #125.
|
40
|
-
yield basename, abspath.freeze
|
42
|
+
yield basename, abspath.freeze, ftype
|
41
43
|
end
|
42
44
|
end
|
43
45
|
|
@@ -45,12 +47,14 @@ module Zeitwerk::Loader::Helpers
|
|
45
47
|
private def has_at_least_one_ruby_file?(dir)
|
46
48
|
to_visit = [dir]
|
47
49
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
50
|
+
until to_visit.empty?
|
51
|
+
dir = to_visit.shift
|
52
|
+
|
53
|
+
ls(dir) do |_basename, abspath, ftype|
|
54
|
+
if ftype == :file
|
53
55
|
return true
|
56
|
+
else
|
57
|
+
to_visit << abspath
|
54
58
|
end
|
55
59
|
end
|
56
60
|
end
|
data/lib/zeitwerk/loader.rb
CHANGED
@@ -230,53 +230,87 @@ module Zeitwerk
|
|
230
230
|
setup
|
231
231
|
end
|
232
232
|
|
233
|
-
|
234
|
-
|
235
|
-
|
233
|
+
# Returns a hash that maps the absolute paths of the managed files and
|
234
|
+
# directories to their respective expected constant paths.
|
235
|
+
#
|
236
|
+
# @sig () -> Hash[String, String]
|
237
|
+
def all_expected_cpaths
|
238
|
+
result = {}
|
236
239
|
|
237
|
-
|
240
|
+
actual_roots.each do |root_dir, root_namespace|
|
241
|
+
queue = [[root_dir, real_mod_name(root_namespace)]]
|
238
242
|
|
239
|
-
|
240
|
-
|
243
|
+
until queue.empty?
|
244
|
+
dir, cpath = queue.shift
|
245
|
+
result[dir] = cpath
|
241
246
|
|
242
|
-
|
247
|
+
prefix = cpath == "Object" ? "" : cpath + "::"
|
243
248
|
|
244
|
-
|
245
|
-
|
246
|
-
|
249
|
+
ls(dir) do |basename, abspath, ftype|
|
250
|
+
if ftype == :file
|
251
|
+
basename.delete_suffix!(".rb")
|
252
|
+
result[abspath] = prefix + inflector.camelize(basename, abspath)
|
253
|
+
else
|
254
|
+
if collapse?(abspath)
|
255
|
+
queue << [abspath, cpath]
|
256
|
+
else
|
257
|
+
queue << [abspath, prefix + inflector.camelize(basename, abspath)]
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
247
263
|
|
248
|
-
|
249
|
-
walk_up_from = File.dirname(abspath)
|
250
|
-
else
|
251
|
-
walk_up_from = abspath
|
264
|
+
result
|
252
265
|
end
|
253
266
|
|
254
|
-
|
267
|
+
# @sig (String | Pathname) -> String?
|
268
|
+
def cpath_expected_at(path)
|
269
|
+
abspath = File.expand_path(path)
|
255
270
|
|
256
|
-
|
257
|
-
break if root_namespace = roots[dir]
|
258
|
-
return if ignored_path?(dir)
|
271
|
+
raise Zeitwerk::Error.new("#{abspath} does not exist") unless File.exist?(abspath)
|
259
272
|
|
260
|
-
|
261
|
-
return if
|
273
|
+
return unless dir?(abspath) || ruby?(abspath)
|
274
|
+
return if ignored_path?(abspath)
|
262
275
|
|
263
|
-
paths
|
264
|
-
end
|
276
|
+
paths = []
|
265
277
|
|
266
|
-
|
278
|
+
if ruby?(abspath)
|
279
|
+
basename = File.basename(abspath, ".rb")
|
280
|
+
return if hidden?(basename)
|
267
281
|
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
282
|
+
paths << [basename, abspath]
|
283
|
+
walk_up_from = File.dirname(abspath)
|
284
|
+
else
|
285
|
+
walk_up_from = abspath
|
286
|
+
end
|
272
287
|
|
273
|
-
|
274
|
-
|
288
|
+
root_namespace = nil
|
289
|
+
|
290
|
+
walk_up(walk_up_from) do |dir|
|
291
|
+
break if root_namespace = roots[dir]
|
292
|
+
return if ignored_path?(dir)
|
293
|
+
|
294
|
+
basename = File.basename(dir)
|
295
|
+
return if hidden?(basename)
|
296
|
+
|
297
|
+
paths << [basename, abspath] unless collapse?(dir)
|
298
|
+
end
|
299
|
+
|
300
|
+
return unless root_namespace
|
301
|
+
|
302
|
+
if paths.empty?
|
303
|
+
real_mod_name(root_namespace)
|
275
304
|
else
|
276
|
-
|
305
|
+
cnames = paths.reverse_each.map { |b, a| cname_for(b, a) }
|
306
|
+
|
307
|
+
if root_namespace == Object
|
308
|
+
cnames.join("::")
|
309
|
+
else
|
310
|
+
"#{real_mod_name(root_namespace)}::#{cnames.join("::")}"
|
311
|
+
end
|
277
312
|
end
|
278
313
|
end
|
279
|
-
end
|
280
314
|
|
281
315
|
# Says if the given constant path would be unloaded on reload. This
|
282
316
|
# predicate returns `false` if reloading is disabled.
|
@@ -408,8 +442,8 @@ module Zeitwerk
|
|
408
442
|
|
409
443
|
# @sig (String, Module) -> void
|
410
444
|
private def define_autoloads_for_dir(dir, parent)
|
411
|
-
ls(dir) do |basename, abspath|
|
412
|
-
if
|
445
|
+
ls(dir) do |basename, abspath, ftype|
|
446
|
+
if ftype == :file
|
413
447
|
basename.delete_suffix!(".rb")
|
414
448
|
autoload_file(parent, cname_for(basename, abspath), abspath)
|
415
449
|
else
|
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.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Xavier Noria
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-05-14 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |2
|
14
14
|
Zeitwerk implements constant autoloading with Ruby semantics. Each gem
|
@@ -62,7 +62,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
62
62
|
- !ruby/object:Gem::Version
|
63
63
|
version: '0'
|
64
64
|
requirements: []
|
65
|
-
rubygems_version: 3.5.
|
65
|
+
rubygems_version: 3.5.7
|
66
66
|
signing_key:
|
67
67
|
specification_version: 4
|
68
68
|
summary: Efficient and thread-safe constant autoloader
|