zeitwerk 2.1.5 → 2.1.6

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: e89de8ad7897a95ccc14f71e1688eb826c7e01f2c0c9381e09de5dd8815d1974
4
- data.tar.gz: 11bf19ab1b396399afc3110e8122cb783d2a2d64a889fa5ac7e506e65a8cc9be
3
+ metadata.gz: 43750607caaaa5d4fff5bd52204cafb98fbd5109b51a24d9099ba83c6a2a4990
4
+ data.tar.gz: 8ad3251fd93af9e66a9102c13556beff5805a38660d69e4c5de37e2808e76d8f
5
5
  SHA512:
6
- metadata.gz: b9a3e74bde3eec64186834b010f3c047d0b1c849a95c89747c6195b3a5fef974d4b1018cf4fca64a46e27aa5768c543d73b6203af80b170c20dab108544833e0
7
- data.tar.gz: 2055af7e3b74fa7c6c3e0c1e7dc6bb1888736c5d8204106ed0504b83a3cba74f7db2a24a72a0e2afc995cf780d4ebcd5965c74262150bb9c90fc3abf4ae97310
6
+ metadata.gz: e6e87877104078f564686a15b81882a8e20a560a36999e0f8b9916aa520dd46fe1a2b7f65cacdb7b6c62d252472b6ce1370939054f026a335e21652881820814
7
+ data.tar.gz: 3641d412ab4b9176861b9ed9b28ea7964b6a814ebb72804c96967e511562fb87f424c48d7780345be8ccd2c53bdacfe095e3e5173e166a4185bf389740258ca6
data/README.md CHANGED
@@ -338,7 +338,15 @@ This needs to be done before calling `setup`.
338
338
  <a id="markdown-logging" name="logging"></a>
339
339
  ### Logging
340
340
 
341
- Zeitwerk is silent by default, but you can configure a callable as logger:
341
+ Zeitwerk is silent by default, but you can ask loaders to trace their activity. Logging is meant just for troubleshooting, shouldn't normally be enabled.
342
+
343
+ The `log!` mehtod is a quick shortcut to let the loader log to `$stdout`:
344
+
345
+ ```
346
+ loader.log!
347
+ ```
348
+
349
+ If you want more control, a logger can be configured as a callable
342
350
 
343
351
  ```ruby
344
352
  loader.logger = method(:puts)
@@ -53,6 +53,23 @@ module Zeitwerk
53
53
  # @return [Set<String>]
54
54
  attr_reader :ignored_paths
55
55
 
56
+ # A _shadowed file_ is a file managed by this loader that is ignored when
57
+ # setting autoloads because its matching constant is taken. Either the
58
+ # constant is already defined, or there exists an autoload for it.
59
+ #
60
+ # Think $LOAD_PATH and require, only the first occurrence of a given
61
+ # relative name is loaded.
62
+ #
63
+ # This set keeps track of the absolute path of shadowed files, to be able to
64
+ # skip them while eager loading.
65
+ #
66
+ # Note this cannot be implemented with do_not_eager_load because these
67
+ # files are not autoloadable.
68
+ #
69
+ # @private
70
+ # @return [Set<String>]
71
+ attr_reader :shadowed_files
72
+
56
73
  # Maps real absolute paths for which an autoload has been set ---and not
57
74
  # executed--- to their corresponding parent class or module and constant
58
75
  # name.
@@ -138,6 +155,7 @@ module Zeitwerk
138
155
  @autoloaded_dirs = []
139
156
  @to_unload = {}
140
157
  @lazy_subdirs = {}
158
+ @shadowed_files = Set.new
141
159
  @eager_load_exclusions = Set.new
142
160
 
143
161
  # TODO: find a better name for these mutexes.
@@ -306,6 +324,7 @@ module Zeitwerk
306
324
  autoloaded_dirs.clear
307
325
  to_unload.clear
308
326
  lazy_subdirs.clear
327
+ shadowed_files.clear
309
328
 
310
329
  Registry.on_unload(self)
311
330
  ExplicitNamespace.unregister(self)
@@ -343,19 +362,19 @@ module Zeitwerk
343
362
 
344
363
  queue = actual_root_dirs.reject { |dir| eager_load_exclusions.member?(dir) }
345
364
  while dir = queue.shift
346
- const_get_if_autoload(dir)
347
-
348
- each_abspath(dir) do |abspath|
365
+ ls(dir) do |_basename, abspath|
349
366
  next if eager_load_exclusions.member?(abspath)
350
367
 
351
368
  if ruby?(abspath)
352
- const_get_if_autoload(abspath)
369
+ require abspath unless shadowed_files.member?(abspath)
353
370
  elsif dir?(abspath)
354
371
  queue << abspath
355
372
  end
356
373
  end
357
374
  end
358
375
 
376
+ shadowed_files.clear
377
+
359
378
  autoloaded_dirs.each do |autoloaded_dir|
360
379
  Registry.unregister_autoload(autoloaded_dir)
361
380
  end
@@ -391,6 +410,13 @@ module Zeitwerk
391
410
  to_unload.keys.freeze
392
411
  end
393
412
 
413
+ # Logs to `$stdout`, handy shortcut for debugging.
414
+ #
415
+ # @return [void]
416
+ def log!
417
+ @logger = ->(msg) { puts msg }
418
+ end
419
+
394
420
  # --- Class methods ---------------------------------------------------------------------------
395
421
 
396
422
  class << self
@@ -414,7 +440,7 @@ module Zeitwerk
414
440
  #
415
441
  # @return [Zeitwerk::Loader]
416
442
  def for_gem
417
- called_from = caller_locations.first.path
443
+ called_from = caller_locations(1, 1).first.path
418
444
  Registry.loader_for_gem(called_from)
419
445
  end
420
446
 
@@ -449,9 +475,10 @@ module Zeitwerk
449
475
  # @param parent [Module]
450
476
  # @return [void]
451
477
  def set_autoloads_in_dir(dir, parent)
452
- each_abspath(dir) do |abspath|
453
- cname = inflector.camelize(File.basename(abspath, ".rb"), abspath).to_sym
454
- if ruby?(abspath)
478
+ ls(dir) do |basename, abspath|
479
+ if ruby?(basename)
480
+ basename.slice!(-3, 3)
481
+ cname = inflector.camelize(basename, abspath).to_sym
455
482
  autoload_file(parent, cname, abspath)
456
483
  elsif dir?(abspath)
457
484
  # In a Rails application, `app/models/concerns` is a subdirectory of
@@ -460,7 +487,10 @@ module Zeitwerk
460
487
  # To resolve the ambiguity file name -> constant path this introduces,
461
488
  # the `app/models/concerns` directory is totally ignored as a namespace,
462
489
  # it counts only as root. The guard checks that.
463
- autoload_subdir(parent, cname, abspath) unless root_dirs.key?(abspath)
490
+ unless root_dirs.key?(abspath)
491
+ cname = inflector.camelize(basename, abspath).to_sym
492
+ autoload_subdir(parent, cname, abspath)
493
+ end
464
494
  end
465
495
  end
466
496
  end
@@ -496,6 +526,7 @@ module Zeitwerk
496
526
  if autoload_path = autoload_for?(parent, cname)
497
527
  # First autoload for a Ruby file wins, just ignore subsequent ones.
498
528
  if ruby?(autoload_path)
529
+ shadowed_files.add(file)
499
530
  log("file #{file} is ignored because #{autoload_path} has precedence") if logger
500
531
  else
501
532
  promote_namespace_from_implicit_to_explicit(
@@ -506,6 +537,7 @@ module Zeitwerk
506
537
  )
507
538
  end
508
539
  elsif cdef?(parent, cname)
540
+ shadowed_files.add(file)
509
541
  log("file #{file} is ignored because #{cpath(parent, cname)} is already defined") if logger
510
542
  else
511
543
  set_autoload(parent, cname, file)
@@ -605,7 +637,7 @@ module Zeitwerk
605
637
  # @param dir [String]
606
638
  # @return [void]
607
639
  def do_preload_dir(dir)
608
- each_abspath(dir) do |abspath|
640
+ ls(dir) do |_basename, abspath|
609
641
  do_preload_abspath(abspath)
610
642
  end
611
643
  end
@@ -625,13 +657,13 @@ module Zeitwerk
625
657
  end
626
658
 
627
659
  # @param dir [String]
628
- # @yieldparam path [String]
660
+ # @yieldparam path [String, String]
629
661
  # @return [void]
630
- def each_abspath(dir)
631
- Dir.foreach(dir) do |entry|
632
- next if entry.start_with?(".")
633
- abspath = File.join(dir, entry)
634
- yield abspath unless ignored_paths.member?(abspath)
662
+ def ls(dir)
663
+ Dir.foreach(dir) do |basename|
664
+ next if basename.start_with?(".")
665
+ abspath = File.join(dir, basename)
666
+ yield basename, abspath unless ignored_paths.member?(abspath)
635
667
  end
636
668
  end
637
669
 
@@ -664,12 +696,6 @@ module Zeitwerk
664
696
  parent.const_defined?(cname, false)
665
697
  end
666
698
 
667
- def const_get_if_autoload(abspath)
668
- if cref = autoloads[File.realpath(abspath)]
669
- cref[0].const_get(cref[1], false)
670
- end
671
- end
672
-
673
699
  def register_explicit_namespace(cpath)
674
700
  ExplicitNamespace.register(cpath, self)
675
701
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Zeitwerk
4
- VERSION = "2.1.5"
4
+ VERSION = "2.1.6"
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.1.5
4
+ version: 2.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Xavier Noria
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-24 00:00:00.000000000 Z
11
+ date: 2019-04-30 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |2
14
14
  Zeitwerk implements constant autoloading with Ruby semantics. Each gem