zeitwerk 2.6.9 → 2.6.11

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: b1de024fb1ddb2f4bc64ced5aacf898f01b6336d5d8b85701d0757e256d062fb
4
- data.tar.gz: d3f06cb22aad419d5c1778fc4a13e1cc036cd062b5ac1fcece5eb4fa3ba1ce00
3
+ metadata.gz: 0dd43924a88fceee915258e119a02df8fb173199576f52cf18c8298aab091361
4
+ data.tar.gz: 6aeeced1ce99e28238ebd1488a543da6ba4fb885e283f999cec30a49db3a0ccf
5
5
  SHA512:
6
- metadata.gz: 3b49724afa7c8097eb6014264faa50f6320c7686760fc5677f6c648f6f4c482b2aa6efb8f78621721c6b00ed424a0a77864cdf8fafb2a481a0ddd1c333115d04
7
- data.tar.gz: 01b7782fea2affe16c5241f9325649e90f3beb3150f168cecf6d710fdfffb66a9bfa853ca4ce562ddbdca3133718b7b2bdb2b1260cf997724d668d6639a5199b
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
- `Zeitwer::NameError` is raised if a constant path cannot be derived from it:
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 we handle
36
- # directories ourselves, so the callback needs to account for concurrency.
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
- mutex2.synchronize do
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
@@ -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 Mutex
95
- attr_reader :mutex2
96
- private :mutex2
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
- cnames = []
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
- cnames << inflector.camelize(basename, abspath).to_sym
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 cnames.empty?
268
+ if paths.empty?
272
269
  real_mod_name(root_namespace)
273
270
  else
274
- # We reverse before validating the segments to report the leftmost
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
- begin
426
- if ruby?(basename)
427
- basename.delete_suffix!(".rb")
428
- cname = inflector.camelize(basename, abspath).to_sym
429
- autoload_file(parent, cname, abspath)
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
- if collapse?(abspath)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Zeitwerk
4
- VERSION = "2.6.9"
4
+ VERSION = "2.6.11"
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.6.9
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-07-25 00:00:00.000000000 Z
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