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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4012f73de9387546f477e8254668d450c00310666bde922b90a6b2be8d4b9740
4
- data.tar.gz: 7c403df9ea53494c2eb1a01b3fb81f70ce1a6488a420728f134c7c32ab4cb444
3
+ metadata.gz: a57a618cc6c371488c6b2a1360b3bfb37b4914e7c44addd688dd9ff6d245f92b
4
+ data.tar.gz: 927300a0bec3a2941e79e3065068cb3359ced9a368a23204e31eb76c1de347bc
5
5
  SHA512:
6
- metadata.gz: f2222619050df7f4271a73b2abdc258d541249ed34a75738afb1661ba17460dc2a0c53690f33a85e33b5925e28a6e2d292fa9d12711722261ae517d6d38f7520
7
- data.tar.gz: 77679e246700480f751e0bce8373d5fe648a78f41a2b8bd97cc0d9c0bdff52651bd64be59ad56809b2785539fd7439f3b9ad554d9ddb8f668fbca9b187d51a24
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), and you can also tell Zeitwerk that certain files or directories are autoloadable, but should not be eager loaded:
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
- 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).
434
+ However, that can be overridden with `force`:
404
435
 
405
- Eager loading is synchronized and idempotent.
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
- If eager loading a file does not define the expected class or module, Zeitwerk raises `Zeitwerk::NameError`, which is a subclass of `NameError`.
442
+ The `force` flag does not affect ignored files and directories, those are still ignored.
408
443
 
409
- If you want to eager load yourself and all dependencies using Zeitwerk, you can broadcast the `eager_load` call to all instances:
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 MRI 2.4.4 and above.
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
@@ -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)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Zeitwerk
4
- VERSION = "2.5.0.beta4"
4
+ VERSION = "2.5.0.beta5"
5
5
  end
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.beta4
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-22 00:00:00.000000000 Z
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