zeitwerk 2.5.0.beta6 → 2.5.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 74d74bec1f4963cc5d04f037e14723408ae5d1f8c4df16f31f2901402e3230ed
4
- data.tar.gz: 3ebd7f860583cc7a560360b2e766193dc0c74c5cd902c7cb632a614e32dc68e7
3
+ metadata.gz: 8e0d44c224600274a41893cc27d119539f5d625c3be6ed46a54052d9b139c58c
4
+ data.tar.gz: 16c701ed5717318fab08631a001a7c067f81a2027fabbfe4b6a0f6775da60a7d
5
5
  SHA512:
6
- metadata.gz: f0bec92696285efb5ad1f76094b71a4de5a38a0665b493737c945623042b4d744be2c58f4006ed5c8c4abe0ccb70854c94ba63c3b7eeef1a5ae47086a956668d
7
- data.tar.gz: a1392b3b73dcd85769f793aeca9a9d10cb50c70259d88761574c1e62e201b24f32d7122eda587af6017dea93fca27ce9463e5f0dae7b98523d3edba2c13802eb
6
+ metadata.gz: d897fb5bdfc8b27080dbcd6160945e4a4cec6fb0f31c4eb21cd448ec26d1291ad373696995aaddcf4e387b7d731fbe4530b43f3b77f97159ba69bed447f07ade
7
+ data.tar.gz: 3cc2dbbc0840f2d420eb32ed725aaf24b7d889d989060211a9877703b44b6e71fa1d1884df2f50cfbf121b1954cf51db7e867232cde7470698fdb7e408c1be23
data/README.md CHANGED
@@ -50,8 +50,8 @@
50
50
  - [Rules of thumb](#rules-of-thumb)
51
51
  - [Debuggers](#debuggers)
52
52
  - [debug.rb](#debugrb)
53
- - [Break](#break)
54
53
  - [Byebug](#byebug)
54
+ - [Break](#break)
55
55
  - [Pronunciation](#pronunciation)
56
56
  - [Supported Ruby versions](#supported-ruby-versions)
57
57
  - [Testing](#testing)
@@ -810,7 +810,9 @@ Kernel.module_eval do
810
810
  end
811
811
  ```
812
812
 
813
- That file does not define a constant path after the path name and you need to tell Zeitwerk:
813
+ `Kernel` is already defined by Ruby so the module cannot be autoloaded. Also, that file does not define a constant path after the path name. Therefore, Zeitwerk should not process it at all.
814
+
815
+ The extension can still coexist with the rest of the project, you only need to tell Zeitwerk to ignore it:
814
816
 
815
817
  ```ruby
816
818
  kernel_ext = "#{__dir__}/my_gem/core_ext/kernel.rb"
@@ -826,6 +828,14 @@ loader.ignore(core_ext)
826
828
  loader.setup
827
829
  ```
828
830
 
831
+ Now, that file has to be loaded manually with `require` or `require_relative`:
832
+
833
+ ```ruby
834
+ require_relative "my_gem/core_ext/kernel"
835
+ ```
836
+
837
+ and you can do that anytime, before configuring the loader, or after configuring the loader, does not matter.
838
+
829
839
  <a id="markdown-use-case-the-adapter-pattern" name="use-case-the-adapter-pattern"></a>
830
840
  #### Use case: The adapter pattern
831
841
 
@@ -973,17 +983,19 @@ With that, when Zeitwerk scans the file system and reaches the gem directories `
973
983
  <a id="markdown-debugrb" name="debugrb"></a>
974
984
  #### debug.rb
975
985
 
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.
986
+ The new [debug.rb](https://github.com/ruby/debug) gem and Zeitwerk are mostly compatible. This is the new debugger that is going to ship with Ruby 3.1.
977
987
 
978
- <a id="markdown-break" name="break"></a>
979
- #### Break
980
-
981
- Zeitwerk works fine with [@gsamokovarov](https://github.com/gsamokovarov)'s [Break](https://github.com/gsamokovarov/break) debugger.
988
+ There's one exception, though: Due to a technical limitation of tracepoints, explicit namespaces are not autoloaded while expressions are evaluated in the REPL. See [ruby/debug#408](https://github.com/ruby/debug/issues/408).
982
989
 
983
990
  <a id="markdown-byebug" name="byebug"></a>
984
991
  #### Byebug
985
992
 
986
- Zeitwerk and [Byebug](https://github.com/deivid-rodriguez/byebug) are incompatible, classes or modules that belong to [explicit namespaces](#explicit-namespaces) are not autoloaded inside a Byebug session. See [this issue](https://github.com/deivid-rodriguez/byebug/issues/564#issuecomment-499413606) for further details.
993
+ Zeitwerk and [Byebug](https://github.com/deivid-rodriguez/byebug) have a similar edge incompatibility.
994
+
995
+ <a id="markdown-break" name="break"></a>
996
+ #### Break
997
+
998
+ Zeitwerk works fine with [@gsamokovarov](https://github.com/gsamokovarov)'s [Break](https://github.com/gsamokovarov/break) debugger.
987
999
 
988
1000
  <a id="markdown-pronunciation" name="pronunciation"></a>
989
1001
  ## Pronunciation
@@ -24,22 +24,22 @@ module Kernel
24
24
  def require(path)
25
25
  if loader = Zeitwerk::Registry.loader_for(path)
26
26
  if path.end_with?(".rb")
27
- zeitwerk_original_require(path).tap do |required|
28
- loader.on_file_autoloaded(path) if required
29
- end
27
+ required = zeitwerk_original_require(path)
28
+ loader.on_file_autoloaded(path) if required
29
+ required
30
30
  else
31
31
  loader.on_dir_autoloaded(path)
32
32
  true
33
33
  end
34
34
  else
35
- zeitwerk_original_require(path).tap do |required|
36
- if required
37
- abspath = $LOADED_FEATURES.last
38
- if loader = Zeitwerk::Registry.loader_for(abspath)
39
- loader.on_file_autoloaded(abspath)
40
- end
35
+ required = zeitwerk_original_require(path)
36
+ if required
37
+ abspath = $LOADED_FEATURES.last
38
+ if loader = Zeitwerk::Registry.loader_for(abspath)
39
+ loader.on_file_autoloaded(abspath)
41
40
  end
42
41
  end
42
+ required
43
43
  end
44
44
  end
45
45
 
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "set"
4
- require "securerandom"
5
4
 
6
5
  module Zeitwerk
7
6
  class Loader
@@ -14,22 +13,16 @@ module Zeitwerk
14
13
  include Helpers
15
14
  include Config
16
15
 
17
- # Keeps track of autoloads defined by the loader which have not been
18
- # executed so far.
16
+ # Maps absolute paths for which an autoload has been set ---and not
17
+ # executed--- to their corresponding parent class or module and constant
18
+ # name.
19
19
  #
20
- # This metadata helps us implement a few things:
21
- #
22
- # 1. When autoloads are triggered, ensure they define the expected constant
23
- # and invoke user callbacks. If reloading is enabled, remember cref and
24
- # abspath for later unloading logic.
25
- #
26
- # 2. When unloading, remove autoloads that have not been executed.
27
- #
28
- # 3. Eager load with a recursive const_get, rather than a recursive require,
29
- # for consistency with lazy loading.
20
+ # "/Users/fxn/blog/app/models/user.rb" => [Object, :User],
21
+ # "/Users/fxn/blog/app/models/hotel/pricing.rb" => [Hotel, :Pricing]
22
+ # ...
30
23
  #
31
24
  # @private
32
- # @sig Zeitwerk::Autoloads
25
+ # @sig Hash[String, [Module, Symbol]]
33
26
  attr_reader :autoloads
34
27
 
35
28
  # We keep track of autoloaded directories to remove them from the registry
@@ -87,7 +80,7 @@ module Zeitwerk
87
80
  def initialize
88
81
  super
89
82
 
90
- @autoloads = Autoloads.new
83
+ @autoloads = {}
91
84
  @autoloaded_dirs = []
92
85
  @to_unload = {}
93
86
  @lazy_subdirs = Hash.new { |h, cpath| h[cpath] = [] }
@@ -138,7 +131,7 @@ module Zeitwerk
138
131
  # is enough.
139
132
  unloaded_files = Set.new
140
133
 
141
- autoloads.each do |(parent, cname), abspath|
134
+ autoloads.each do |abspath, (parent, cname)|
142
135
  if parent.autoload?(cname)
143
136
  unload_autoload(parent, cname)
144
137
  else
@@ -234,7 +227,7 @@ module Zeitwerk
234
227
  next if honour_exclusions && excluded_from_eager_load?(abspath)
235
228
 
236
229
  if ruby?(abspath)
237
- if cref = autoloads.cref_for(abspath)
230
+ if cref = autoloads[abspath]
238
231
  cget(*cref)
239
232
  end
240
233
  elsif dir?(abspath) && !root_dirs.key?(abspath)
@@ -376,7 +369,7 @@ module Zeitwerk
376
369
 
377
370
  # @sig (Module, Symbol, String) -> void
378
371
  def autoload_subdir(parent, cname, subdir)
379
- if autoload_path = autoloads.abspath_for(parent, cname)
372
+ if autoload_path = autoload_path_set_by_me_for?(parent, cname)
380
373
  cpath = cpath(parent, cname)
381
374
  register_explicit_namespace(cpath) if ruby?(autoload_path)
382
375
  # We do not need to issue another autoload, the existing one is enough
@@ -432,7 +425,7 @@ module Zeitwerk
432
425
 
433
426
  # @sig (Module, Symbol, String) -> void
434
427
  def set_autoload(parent, cname, abspath)
435
- autoloads.define(parent, cname, abspath)
428
+ parent.autoload(cname, abspath)
436
429
 
437
430
  if logger
438
431
  if ruby?(abspath)
@@ -442,6 +435,7 @@ module Zeitwerk
442
435
  end
443
436
  end
444
437
 
438
+ autoloads[abspath] = [parent, cname]
445
439
  Registry.register_autoload(self, abspath)
446
440
 
447
441
  # See why in the documentation of Zeitwerk::Registry.inceptions.
@@ -450,6 +444,15 @@ module Zeitwerk
450
444
  end
451
445
  end
452
446
 
447
+ # @sig (Module, Symbol) -> String?
448
+ def autoload_path_set_by_me_for?(parent, cname)
449
+ if autoload_path = strict_autoload_path(parent, cname)
450
+ autoload_path if autoloads.key?(autoload_path)
451
+ else
452
+ Registry.inception?(cpath(parent, cname))
453
+ end
454
+ end
455
+
453
456
  # @sig (String) -> void
454
457
  def register_explicit_namespace(cpath)
455
458
  ExplicitNamespace.register(cpath, self)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Zeitwerk
4
- VERSION = "2.5.0.beta6"
4
+ VERSION = "2.5.3"
5
5
  end
data/lib/zeitwerk.rb CHANGED
@@ -3,7 +3,6 @@
3
3
  module Zeitwerk
4
4
  require_relative "zeitwerk/real_mod_name"
5
5
  require_relative "zeitwerk/loader"
6
- require_relative "zeitwerk/autoloads"
7
6
  require_relative "zeitwerk/registry"
8
7
  require_relative "zeitwerk/explicit_namespace"
9
8
  require_relative "zeitwerk/inflector"
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.beta6
4
+ version: 2.5.3
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-10-14 00:00:00.000000000 Z
11
+ date: 2021-12-30 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |2
14
14
  Zeitwerk implements constant autoloading with Ruby semantics. Each gem
@@ -23,7 +23,6 @@ files:
23
23
  - MIT-LICENSE
24
24
  - README.md
25
25
  - lib/zeitwerk.rb
26
- - lib/zeitwerk/autoloads.rb
27
26
  - lib/zeitwerk/error.rb
28
27
  - lib/zeitwerk/explicit_namespace.rb
29
28
  - lib/zeitwerk/gem_inflector.rb
@@ -55,9 +54,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
55
54
  version: '2.5'
56
55
  required_rubygems_version: !ruby/object:Gem::Requirement
57
56
  requirements:
58
- - - ">"
57
+ - - ">="
59
58
  - !ruby/object:Gem::Version
60
- version: 1.3.1
59
+ version: '0'
61
60
  requirements: []
62
61
  rubygems_version: 3.2.22
63
62
  signing_key:
@@ -1,71 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Zeitwerk
4
- # @private
5
- class Autoloads
6
- # Maps crefs for which an autoload has been defined to the corresponding
7
- # absolute path.
8
- #
9
- # [Object, :User] => "/Users/fxn/blog/app/models/user.rb"
10
- # [Object, :Hotel] => "/Users/fxn/blog/app/models/hotel"
11
- # ...
12
- #
13
- # This colection is transient, callbacks delete its entries as autoloads get
14
- # executed.
15
- #
16
- # @sig Hash[[Module, Symbol], String]
17
- attr_reader :c2a
18
-
19
- # This is the inverse of c2a, for inverse lookups.
20
- #
21
- # @sig Hash[String, [Module, Symbol]]
22
- attr_reader :a2c
23
-
24
- # @sig () -> void
25
- def initialize
26
- @c2a = {}
27
- @a2c = {}
28
- end
29
-
30
- # @sig (Module, Symbol, String) -> void
31
- def define(parent, cname, abspath)
32
- parent.autoload(cname, abspath)
33
- cref = [parent, cname]
34
- c2a[cref] = abspath
35
- a2c[abspath] = cref
36
- end
37
-
38
- # @sig () { () -> [[Module, Symbol], String] } -> void
39
- def each(&block)
40
- c2a.each(&block)
41
- end
42
-
43
- # @sig (Module, Symbol) -> String?
44
- def abspath_for(parent, cname)
45
- c2a[[parent, cname]]
46
- end
47
-
48
- # @sig (String) -> [Module, Symbol]?
49
- def cref_for(abspath)
50
- a2c[abspath]
51
- end
52
-
53
- # @sig (String) -> [Module, Symbol]?
54
- def delete(abspath)
55
- cref = a2c.delete(abspath)
56
- c2a.delete(cref)
57
- cref
58
- end
59
-
60
- # @sig () -> void
61
- def clear
62
- c2a.clear
63
- a2c.clear
64
- end
65
-
66
- # @sig () -> bool
67
- def empty?
68
- c2a.empty? && a2c.empty?
69
- end
70
- end
71
- end