zeitwerk 2.5.0.beta4 → 2.5.0.beta5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +77 -6
- data/lib/zeitwerk/loader.rb +8 -5
- 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: a57a618cc6c371488c6b2a1360b3bfb37b4914e7c44addd688dd9ff6d245f92b
|
4
|
+
data.tar.gz: 927300a0bec3a2941e79e3065068cb3359ced9a368a23204e31eb76c1de347bc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c26a751d80bcf719e2705c30c24e78300141b8cfe4a57e3bed2a9bf26e80534755a0fe067b6f32e6c1f4e7bbaf7693232640a76ff710e868c07f11128e9da6d
|
7
|
+
data.tar.gz: 270a9053e7ecccf58366272d6e60d2d3967d80f3d9777a0825700efcacf95e468a31c29924436df4231a53a971d31b0b4157d9f8bb8b82a91bd6fb6b2fdfb592
|
data/README.md
CHANGED
@@ -19,12 +19,15 @@
|
|
19
19
|
- [Implicit namespaces](#implicit-namespaces)
|
20
20
|
- [Explicit namespaces](#explicit-namespaces)
|
21
21
|
- [Collapsing directories](#collapsing-directories)
|
22
|
+
- [Testing compliance](#testing-compliance)
|
22
23
|
- [Usage](#usage)
|
23
24
|
- [Setup](#setup)
|
24
25
|
- [Generic](#generic)
|
25
26
|
- [for_gem](#for_gem)
|
26
27
|
- [Autoloading](#autoloading)
|
27
28
|
- [Eager loading](#eager-loading)
|
29
|
+
- [Eager load exclusions](#eager-load-exclusions)
|
30
|
+
- [Global eager load](#global-eager-load)
|
28
31
|
- [Reloading](#reloading)
|
29
32
|
- [Inflection](#inflection)
|
30
33
|
- [Zeitwerk::Inflector](#zeitwerkinflector)
|
@@ -42,9 +45,11 @@
|
|
42
45
|
- [Use case: The adapter pattern](#use-case-the-adapter-pattern)
|
43
46
|
- [Use case: Test files mixed with implementation files](#use-case-test-files-mixed-with-implementation-files)
|
44
47
|
- [Edge cases](#edge-cases)
|
48
|
+
- [Beware of circular dependencies](#beware-of-circular-dependencies)
|
45
49
|
- [Reopening third-party namespaces](#reopening-third-party-namespaces)
|
46
50
|
- [Rules of thumb](#rules-of-thumb)
|
47
51
|
- [Debuggers](#debuggers)
|
52
|
+
- [debug.rb](#debugrb)
|
48
53
|
- [Break](#break)
|
49
54
|
- [Byebug](#byebug)
|
50
55
|
- [Pronunciation](#pronunciation)
|
@@ -289,6 +294,23 @@ To illustrate usage of glob patterns, if `actions` in the example above is part
|
|
289
294
|
loader.collapse("#{__dir__}/*/actions")
|
290
295
|
```
|
291
296
|
|
297
|
+
<a id="markdown-testing-compliance" name="testing-compliance"></a>
|
298
|
+
### Testing compliance
|
299
|
+
|
300
|
+
When a managed file is loaded, Zeitwerk verifies the expected constant is defined. If it is not, `Zeitwerk::NameError` is raised.
|
301
|
+
|
302
|
+
So, an easy way to ensure compliance in the test suite is to eager load the project:
|
303
|
+
|
304
|
+
```ruby
|
305
|
+
begin
|
306
|
+
loader.eager_load(force: true)
|
307
|
+
rescue Zeitwerk::NameError => e
|
308
|
+
flunk e.message
|
309
|
+
else
|
310
|
+
assert true
|
311
|
+
end
|
312
|
+
```
|
313
|
+
|
292
314
|
<a id="markdown-usage" name="usage"></a>
|
293
315
|
## Usage
|
294
316
|
|
@@ -391,7 +413,16 @@ Zeitwerk instances are able to eager load their managed files:
|
|
391
413
|
loader.eager_load
|
392
414
|
```
|
393
415
|
|
394
|
-
That skips [ignored files and directories](#ignoring-parts-of-the-project)
|
416
|
+
That skips [ignored files and directories](#ignoring-parts-of-the-project).
|
417
|
+
|
418
|
+
In gems, the method needs to be invoked after the main namespace has been defined, as shown in [Synopsis](https://github.com/fxn/zeitwerk#synopsis).
|
419
|
+
|
420
|
+
Eager loading is synchronized and idempotent.
|
421
|
+
|
422
|
+
<a id="markdown-eager-load-exclusions" name="eager-load-exclusions"></a>
|
423
|
+
#### Eager load exclusions
|
424
|
+
|
425
|
+
You can tell Zeitwerk that certain files or directories are autoloadable, but should not be eager loaded:
|
395
426
|
|
396
427
|
```ruby
|
397
428
|
db_adapters = "#{__dir__}/my_gem/db_adapters"
|
@@ -400,13 +431,20 @@ loader.setup
|
|
400
431
|
loader.eager_load # won't eager load the database adapters
|
401
432
|
```
|
402
433
|
|
403
|
-
|
434
|
+
However, that can be overridden with `force`:
|
404
435
|
|
405
|
-
|
436
|
+
```ruby
|
437
|
+
loader.eager_load(force: true) # database adapters are eager loaded
|
438
|
+
```
|
439
|
+
|
440
|
+
Which may be handy if the project eager loads in the test suite to [ensure project layour compliance](#testing-compliance).
|
406
441
|
|
407
|
-
|
442
|
+
The `force` flag does not affect ignored files and directories, those are still ignored.
|
408
443
|
|
409
|
-
|
444
|
+
<a id="markdown-global-eager-load" name="global-eager-load"></a>
|
445
|
+
#### Global eager load
|
446
|
+
|
447
|
+
If you want to eager load yourself and all dependencies that use Zeitwerk, you can broadcast the `eager_load` call to all instances:
|
410
448
|
|
411
449
|
```ruby
|
412
450
|
Zeitwerk::Loader.eager_load_all
|
@@ -416,6 +454,8 @@ This may be handy in top-level services, like web applications.
|
|
416
454
|
|
417
455
|
Note that thanks to idempotence `Zeitwerk::Loader.eager_load_all` won't eager load twice if any of the instances already eager loaded.
|
418
456
|
|
457
|
+
This method does not accept the `force` flag, since in general it wouldn't be a good idea to force eager loading in 3rd party code.
|
458
|
+
|
419
459
|
<a id="markdown-reloading" name="reloading"></a>
|
420
460
|
### Reloading
|
421
461
|
|
@@ -642,6 +682,8 @@ There are use cases for this last catch-all callback, but they are rare. If you
|
|
642
682
|
|
643
683
|
If both types of callbacks are defined, the specific ones run first.
|
644
684
|
|
685
|
+
Since `on_load` callbacks are executed right after files are loaded, even if the loading context seems to be far away, in practice **the block is subject to [circular dependencies](#beware-of-circular-dependencies)**. As a rule of thumb, as far as loading order and its interdependencies is concerned, you have to program as if the block was executed at the bottom of the file just loaded.
|
686
|
+
|
645
687
|
<a id="markdown-the-on_unload-callback" name="the-on_unload-callback"></a>
|
646
688
|
#### The on_unload callback
|
647
689
|
|
@@ -854,6 +896,26 @@ Trip = Struct.new { ... } # NOT SUPPORTED
|
|
854
896
|
|
855
897
|
This only affects explicit namespaces, those idioms work well for any other ordinary class or module.
|
856
898
|
|
899
|
+
<a id="markdown-beware-of-circular-dependencies" name="beware-of-circular-dependencies"></a>
|
900
|
+
### Beware of circular dependencies
|
901
|
+
|
902
|
+
In Ruby, you can't have certain top-level circular dependencies. Take for example:
|
903
|
+
|
904
|
+
```ruby
|
905
|
+
# c.rb
|
906
|
+
class C < D
|
907
|
+
end
|
908
|
+
|
909
|
+
# d.rb
|
910
|
+
class D
|
911
|
+
C
|
912
|
+
end
|
913
|
+
```
|
914
|
+
|
915
|
+
In order to define `C`, you need to load `D`. However, the body of `D` refers to `C`.
|
916
|
+
|
917
|
+
Circular dependencies like those do not work in plain Ruby, and therefore do not work in projects managed by Zeitwerk either.
|
918
|
+
|
857
919
|
<a id="markdown-reopening-third-party-namespaces" name="reopening-third-party-namespaces"></a>
|
858
920
|
### Reopening third-party namespaces
|
859
921
|
|
@@ -908,6 +970,11 @@ With that, when Zeitwerk scans the file system and reaches the gem directories `
|
|
908
970
|
<a id="markdown-debuggers" name="debuggers"></a>
|
909
971
|
### Debuggers
|
910
972
|
|
973
|
+
<a id="markdown-debugrb" name="debugrb"></a>
|
974
|
+
#### debug.rb
|
975
|
+
|
976
|
+
The new [debug.rb](https://github.com/ruby/debug) gem and Zeitwerk seem to be compatible, as far as I can tell. This is the new debugger that is going to ship with Ruby 3.1.
|
977
|
+
|
911
978
|
<a id="markdown-break" name="break"></a>
|
912
979
|
#### Break
|
913
980
|
|
@@ -926,7 +993,11 @@ Zeitwerk and [Byebug](https://github.com/deivid-rodriguez/byebug) are incompatib
|
|
926
993
|
<a id="markdown-supported-ruby-versions" name="supported-ruby-versions"></a>
|
927
994
|
## Supported Ruby versions
|
928
995
|
|
929
|
-
Zeitwerk works with
|
996
|
+
Zeitwerk works with CRuby 2.5 and above.
|
997
|
+
|
998
|
+
On TruffleRuby all is good except for thread-safety. Right now, in TruffleRuby `Module#autoload` does not block threads accessing a constant that is being autoloaded. CRuby prevents such access to avoid concurrent threads from seeing partial evaluations of the corresponding file. Zeitwerk inherits autoloading thread-safety from this property. This is not an issue if your project gets eager loaded, or if you lazy load in single-threaded environments. (See https://github.com/oracle/truffleruby/issues/2431.)
|
999
|
+
|
1000
|
+
JRuby 9.3.0.0 is almost there. As of this writing, the test suite of Zeitwerk passes on JRuby except for three tests. (See https://github.com/jruby/jruby/issues/6781.)
|
930
1001
|
|
931
1002
|
<a id="markdown-testing" name="testing"></a>
|
932
1003
|
## Testing
|
data/lib/zeitwerk/loader.rb
CHANGED
@@ -210,25 +210,28 @@ module Zeitwerk
|
|
210
210
|
# Eager loads all files in the root directories, recursively. Files do not
|
211
211
|
# need to be in `$LOAD_PATH`, absolute file names are used. Ignored files
|
212
212
|
# are not eager loaded. You can opt-out specifically in specific files and
|
213
|
-
# directories with `do_not_eager_load
|
213
|
+
# directories with `do_not_eager_load`, and that can be overridden passing
|
214
|
+
# `force: true`.
|
214
215
|
#
|
215
|
-
# @sig () -> void
|
216
|
-
def eager_load
|
216
|
+
# @sig (true | false) -> void
|
217
|
+
def eager_load(force: false)
|
217
218
|
mutex.synchronize do
|
218
219
|
break if @eager_loaded
|
219
220
|
|
220
221
|
log("eager load start") if logger
|
221
222
|
|
223
|
+
honour_exclusions = !force
|
224
|
+
|
222
225
|
queue = []
|
223
226
|
actual_root_dirs.each do |root_dir, namespace|
|
224
|
-
queue << [namespace, root_dir] unless excluded_from_eager_load?(root_dir)
|
227
|
+
queue << [namespace, root_dir] unless honour_exclusions && excluded_from_eager_load?(root_dir)
|
225
228
|
end
|
226
229
|
|
227
230
|
while to_eager_load = queue.shift
|
228
231
|
namespace, dir = to_eager_load
|
229
232
|
|
230
233
|
ls(dir) do |basename, abspath|
|
231
|
-
next if excluded_from_eager_load?(abspath)
|
234
|
+
next if honour_exclusions && excluded_from_eager_load?(abspath)
|
232
235
|
|
233
236
|
if ruby?(abspath)
|
234
237
|
if cref = autoloads.cref_for(abspath)
|
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.5.0.
|
4
|
+
version: 2.5.0.beta5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Xavier Noria
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-09-
|
11
|
+
date: 2021-09-29 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |2
|
14
14
|
Zeitwerk implements constant autoloading with Ruby semantics. Each gem
|