zeitwerk 2.6.9 → 2.6.11

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: 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