zeitwerk 2.7.1 → 2.7.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 +4 -4
- data/lib/zeitwerk/core_ext/kernel.rb +3 -3
- data/lib/zeitwerk/core_ext/module.rb +6 -5
- data/lib/zeitwerk/cref/map.rb +159 -0
- data/lib/zeitwerk/cref.rb +17 -16
- data/lib/zeitwerk/error.rb +2 -0
- data/lib/zeitwerk/gem_inflector.rb +2 -2
- data/lib/zeitwerk/gem_loader.rb +4 -4
- data/lib/zeitwerk/inflector.rb +3 -3
- data/lib/zeitwerk/internal.rb +1 -0
- data/lib/zeitwerk/loader/callbacks.rb +19 -23
- data/lib/zeitwerk/loader/config.rb +37 -44
- data/lib/zeitwerk/loader/eager_load.rb +7 -7
- data/lib/zeitwerk/loader/helpers.rb +9 -10
- data/lib/zeitwerk/loader.rb +133 -95
- data/lib/zeitwerk/null_inflector.rb +1 -0
- data/lib/zeitwerk/real_mod_name.rb +7 -4
- data/lib/zeitwerk/registry/autoloads.rb +38 -0
- data/lib/zeitwerk/registry/explicit_namespaces.rb +61 -0
- data/lib/zeitwerk/registry/inceptions.rb +31 -0
- data/lib/zeitwerk/registry/loaders.rb +33 -0
- data/lib/zeitwerk/registry.rb +18 -96
- data/lib/zeitwerk/version.rb +2 -1
- data/lib/zeitwerk.rb +1 -2
- metadata +8 -7
- data/lib/zeitwerk/explicit_namespace.rb +0 -113
@@ -0,0 +1,33 @@
|
|
1
|
+
module Zeitwerk::Registry
|
2
|
+
class Loaders # :nodoc:
|
3
|
+
#: () -> void
|
4
|
+
def initialize
|
5
|
+
@loaders = [] #: Array[Zeitwerk::Loader]
|
6
|
+
end
|
7
|
+
|
8
|
+
#: ({ (Zeitwerk::Loader) -> void }) -> void
|
9
|
+
def each(&block)
|
10
|
+
@loaders.each(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
#: (Zeitwerk::Loader) -> void
|
14
|
+
def register(loader)
|
15
|
+
@loaders << loader
|
16
|
+
end
|
17
|
+
|
18
|
+
#: (Zeitwerk::Loader) -> Zeitwerk::Loader?
|
19
|
+
def unregister(loader)
|
20
|
+
@loaders.delete(loader)
|
21
|
+
end
|
22
|
+
|
23
|
+
#: (Zeitwerk::Loader) -> bool
|
24
|
+
def registered?(loader) # for tests
|
25
|
+
@loaders.include?(loader)
|
26
|
+
end
|
27
|
+
|
28
|
+
#: () -> void
|
29
|
+
def clear # for tests
|
30
|
+
@loaders.clear
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/zeitwerk/registry.rb
CHANGED
@@ -2,18 +2,23 @@
|
|
2
2
|
|
3
3
|
module Zeitwerk
|
4
4
|
module Registry # :nodoc: all
|
5
|
+
require_relative "registry/autoloads"
|
6
|
+
require_relative "registry/explicit_namespaces"
|
7
|
+
require_relative "registry/inceptions"
|
8
|
+
require_relative "registry/loaders"
|
9
|
+
|
5
10
|
class << self
|
6
11
|
# Keeps track of all loaders. Useful to broadcast messages and to prevent
|
7
12
|
# them from being garbage collected.
|
8
13
|
#
|
9
14
|
# @private
|
10
|
-
|
15
|
+
#: Zeitwerk::Registry::Loaders
|
11
16
|
attr_reader :loaders
|
12
17
|
|
13
18
|
# Registers gem loaders to let `for_gem` be idempotent in case of reload.
|
14
19
|
#
|
15
20
|
# @private
|
16
|
-
|
21
|
+
#: Hash[String, Zeitwerk::Loader]
|
17
22
|
attr_reader :gem_loaders_by_root_file
|
18
23
|
|
19
24
|
# Maps absolute paths to the loaders responsible for them.
|
@@ -22,120 +27,37 @@ module Zeitwerk
|
|
22
27
|
# invoke callbacks and autovivify modules.
|
23
28
|
#
|
24
29
|
# @private
|
25
|
-
|
30
|
+
#: Zeitwerk::Registry::Autoloads
|
26
31
|
attr_reader :autoloads
|
27
32
|
|
28
|
-
# This hash table addresses an edge case in which an autoload is ignored.
|
29
|
-
#
|
30
|
-
# For example, let's suppose we want to autoload in a gem like this:
|
31
|
-
#
|
32
|
-
# # lib/my_gem.rb
|
33
|
-
# loader = Zeitwerk::Loader.new
|
34
|
-
# loader.push_dir(__dir__)
|
35
|
-
# loader.setup
|
36
|
-
#
|
37
|
-
# module MyGem
|
38
|
-
# end
|
39
|
-
#
|
40
|
-
# if you require "my_gem", as Bundler would do, this happens while setting
|
41
|
-
# up autoloads:
|
42
|
-
#
|
43
|
-
# 1. Object.autoload?(:MyGem) returns `nil` because the autoload for
|
44
|
-
# the constant is issued by Zeitwerk while the same file is being
|
45
|
-
# required.
|
46
|
-
# 2. The constant `MyGem` is undefined while setup runs.
|
47
|
-
#
|
48
|
-
# Therefore, a directory `lib/my_gem` would autovivify a module according to
|
49
|
-
# the existing information. But that would be wrong.
|
50
|
-
#
|
51
|
-
# To overcome this fundamental limitation, we keep track of the constant
|
52
|
-
# paths that are in this situation ---in the example above, "MyGem"--- and
|
53
|
-
# take this collection into account for the autovivification logic.
|
54
|
-
#
|
55
|
-
# Note that you cannot generally address this by moving the setup code
|
56
|
-
# below the constant definition, because we want libraries to be able to
|
57
|
-
# use managed constants in the module body:
|
58
|
-
#
|
59
|
-
# module MyGem
|
60
|
-
# include MyConcern
|
61
|
-
# end
|
62
|
-
#
|
63
33
|
# @private
|
64
|
-
|
65
|
-
attr_reader :
|
34
|
+
#: Zeitwerk::Registry::ExplicitNamespaces
|
35
|
+
attr_reader :explicit_namespaces
|
66
36
|
|
67
|
-
# Registers a loader.
|
68
|
-
#
|
69
37
|
# @private
|
70
|
-
|
71
|
-
|
72
|
-
loaders << loader
|
73
|
-
end
|
38
|
+
#: Zeitwerk::Registry::Inceptions
|
39
|
+
attr_reader :inceptions
|
74
40
|
|
75
41
|
# @private
|
76
|
-
|
42
|
+
#: (Zeitwerk::Loader) -> void
|
77
43
|
def unregister_loader(loader)
|
78
|
-
loaders.delete(loader)
|
79
44
|
gem_loaders_by_root_file.delete_if { |_, l| l == loader }
|
80
|
-
autoloads.delete_if { |_, l| l == loader }
|
81
|
-
inceptions.delete_if { |_, (_, l)| l == loader }
|
82
45
|
end
|
83
46
|
|
84
47
|
# This method returns always a loader, the same instance for the same root
|
85
48
|
# file. That is how Zeitwerk::Loader.for_gem is idempotent.
|
86
49
|
#
|
87
50
|
# @private
|
88
|
-
|
51
|
+
#: (String, namespace: Module, warn_on_extra_files: boolish) -> Zeitwerk::Loader
|
89
52
|
def loader_for_gem(root_file, namespace:, warn_on_extra_files:)
|
90
53
|
gem_loaders_by_root_file[root_file] ||= GemLoader.__new(root_file, namespace: namespace, warn_on_extra_files: warn_on_extra_files)
|
91
54
|
end
|
92
|
-
|
93
|
-
# @private
|
94
|
-
# @sig (Zeitwerk::Loader, String) -> String
|
95
|
-
def register_autoload(loader, abspath)
|
96
|
-
autoloads[abspath] = loader
|
97
|
-
end
|
98
|
-
|
99
|
-
# @private
|
100
|
-
# @sig (String) -> void
|
101
|
-
def unregister_autoload(abspath)
|
102
|
-
autoloads.delete(abspath)
|
103
|
-
end
|
104
|
-
|
105
|
-
# @private
|
106
|
-
# @sig (String, String, Zeitwerk::Loader) -> void
|
107
|
-
def register_inception(cpath, abspath, loader)
|
108
|
-
inceptions[cpath] = [abspath, loader]
|
109
|
-
end
|
110
|
-
|
111
|
-
# @private
|
112
|
-
# @sig (String) -> String?
|
113
|
-
def inception?(cpath, registered_by_loader=nil)
|
114
|
-
if pair = inceptions[cpath]
|
115
|
-
abspath, loader = pair
|
116
|
-
if registered_by_loader.nil? || registered_by_loader.equal?(loader)
|
117
|
-
abspath
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
# @private
|
123
|
-
# @sig (String) -> Zeitwerk::Loader?
|
124
|
-
def loader_for(path)
|
125
|
-
autoloads[path]
|
126
|
-
end
|
127
|
-
|
128
|
-
# @private
|
129
|
-
# @sig (Zeitwerk::Loader) -> void
|
130
|
-
def on_unload(loader)
|
131
|
-
autoloads.delete_if { |_path, object| object == loader }
|
132
|
-
inceptions.delete_if { |_cpath, (_path, object)| object == loader }
|
133
|
-
end
|
134
55
|
end
|
135
56
|
|
136
|
-
@loaders =
|
57
|
+
@loaders = Loaders.new
|
137
58
|
@gem_loaders_by_root_file = {}
|
138
|
-
@autoloads =
|
139
|
-
@
|
59
|
+
@autoloads = Autoloads.new
|
60
|
+
@explicit_namespaces = ExplicitNamespaces.new
|
61
|
+
@inceptions = Inceptions.new
|
140
62
|
end
|
141
63
|
end
|
data/lib/zeitwerk/version.rb
CHANGED
data/lib/zeitwerk.rb
CHANGED
@@ -7,7 +7,6 @@ module Zeitwerk
|
|
7
7
|
require_relative "zeitwerk/loader"
|
8
8
|
require_relative "zeitwerk/gem_loader"
|
9
9
|
require_relative "zeitwerk/registry"
|
10
|
-
require_relative "zeitwerk/explicit_namespace"
|
11
10
|
require_relative "zeitwerk/inflector"
|
12
11
|
require_relative "zeitwerk/gem_inflector"
|
13
12
|
require_relative "zeitwerk/null_inflector"
|
@@ -20,7 +19,7 @@ module Zeitwerk
|
|
20
19
|
# This is a dangerous method.
|
21
20
|
#
|
22
21
|
# @experimental
|
23
|
-
|
22
|
+
#: () -> void
|
24
23
|
def self.with_loader
|
25
24
|
loader = Zeitwerk::Loader.new
|
26
25
|
yield loader
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zeitwerk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.7.
|
4
|
+
version: 2.7.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Xavier Noria
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
11
|
dependencies: []
|
13
12
|
description: |2
|
14
13
|
Zeitwerk implements constant autoloading with Ruby semantics. Each gem
|
@@ -26,8 +25,8 @@ files:
|
|
26
25
|
- lib/zeitwerk/core_ext/kernel.rb
|
27
26
|
- lib/zeitwerk/core_ext/module.rb
|
28
27
|
- lib/zeitwerk/cref.rb
|
28
|
+
- lib/zeitwerk/cref/map.rb
|
29
29
|
- lib/zeitwerk/error.rb
|
30
|
-
- lib/zeitwerk/explicit_namespace.rb
|
31
30
|
- lib/zeitwerk/gem_inflector.rb
|
32
31
|
- lib/zeitwerk/gem_loader.rb
|
33
32
|
- lib/zeitwerk/inflector.rb
|
@@ -40,6 +39,10 @@ files:
|
|
40
39
|
- lib/zeitwerk/null_inflector.rb
|
41
40
|
- lib/zeitwerk/real_mod_name.rb
|
42
41
|
- lib/zeitwerk/registry.rb
|
42
|
+
- lib/zeitwerk/registry/autoloads.rb
|
43
|
+
- lib/zeitwerk/registry/explicit_namespaces.rb
|
44
|
+
- lib/zeitwerk/registry/inceptions.rb
|
45
|
+
- lib/zeitwerk/registry/loaders.rb
|
43
46
|
- lib/zeitwerk/version.rb
|
44
47
|
homepage: https://github.com/fxn/zeitwerk
|
45
48
|
licenses:
|
@@ -49,7 +52,6 @@ metadata:
|
|
49
52
|
changelog_uri: https://github.com/fxn/zeitwerk/blob/master/CHANGELOG.md
|
50
53
|
source_code_uri: https://github.com/fxn/zeitwerk
|
51
54
|
bug_tracker_uri: https://github.com/fxn/zeitwerk/issues
|
52
|
-
post_install_message:
|
53
55
|
rdoc_options: []
|
54
56
|
require_paths:
|
55
57
|
- lib
|
@@ -64,8 +66,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
66
|
- !ruby/object:Gem::Version
|
65
67
|
version: '0'
|
66
68
|
requirements: []
|
67
|
-
rubygems_version: 3.
|
68
|
-
signing_key:
|
69
|
+
rubygems_version: 3.6.9
|
69
70
|
specification_version: 4
|
70
71
|
summary: Efficient and thread-safe constant autoloader
|
71
72
|
test_files: []
|
@@ -1,113 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Zeitwerk
|
4
|
-
# This module is essentially a registry for explicit namespaces.
|
5
|
-
#
|
6
|
-
# When a loader determines that a certain file should define an explicit
|
7
|
-
# namespace, it registers it here, associating its cref with itself.
|
8
|
-
#
|
9
|
-
# If the namespace is autoloaded, our const_added callback retrieves its
|
10
|
-
# loader by calling loader_for. That way, the loader is able to scan the
|
11
|
-
# subdirectories that conform the namespace and set autoloads for their
|
12
|
-
# expected constants just in time.
|
13
|
-
#
|
14
|
-
# Once autoloaded, the namespace is unregistered.
|
15
|
-
#
|
16
|
-
# The implementation assumes an explicit namespace is managed by one loader.
|
17
|
-
# Loaders that reopen namespaces owned by other projects are responsible for
|
18
|
-
# loading their constant before setup. This is documented.
|
19
|
-
module ExplicitNamespace # :nodoc: all
|
20
|
-
# Maps cnames or cpaths of explicit namespaces with their corresponding
|
21
|
-
# loader. They are symbols for top-level ones, and strings for nested ones:
|
22
|
-
#
|
23
|
-
# {
|
24
|
-
# :Admin => #<Zeitwerk::Loader:...>,
|
25
|
-
# "Hotel::Pricing" => #<Zeitwerk::Loader:...>
|
26
|
-
# }
|
27
|
-
#
|
28
|
-
# There are two types of keys to make loader_for as fast as possible, since
|
29
|
-
# it is invoked by our const_added for all autoloads and constant actually
|
30
|
-
# added. Globally. With this trick, for top-level constants we do not need
|
31
|
-
# to call Symbol#name and perform a string lookup. Instead, we can directly
|
32
|
-
# perform a fast symbol lookup.
|
33
|
-
#
|
34
|
-
# Entries are added as the namespaces are found, and removed as they are
|
35
|
-
# autoloaded.
|
36
|
-
#
|
37
|
-
# @sig Hash[(Symbol | String) => Zeitwerk::Loader]
|
38
|
-
@loaders = {}
|
39
|
-
|
40
|
-
class << self
|
41
|
-
include RealModName
|
42
|
-
extend Internal
|
43
|
-
|
44
|
-
# Registers `cref` as being the constant path of an explicit namespace
|
45
|
-
# managed by `loader`.
|
46
|
-
#
|
47
|
-
# @sig (String, Zeitwerk::Loader) -> void
|
48
|
-
internal def register(cref, loader)
|
49
|
-
if Object.equal?(cref.mod)
|
50
|
-
@loaders[cref.cname] = loader
|
51
|
-
else
|
52
|
-
@loaders[cref.path] = loader
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
# @sig (Module, Symbol) -> Zeitwerk::Loader?
|
57
|
-
internal def loader_for(mod, cname)
|
58
|
-
if Object.equal?(mod)
|
59
|
-
@loaders.delete(cname)
|
60
|
-
else
|
61
|
-
@loaders.delete("#{real_mod_name(mod)}::#{cname}")
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
# @sig (Zeitwerk::Loader) -> void
|
66
|
-
internal def unregister_loader(loader)
|
67
|
-
@loaders.delete_if { _2.equal?(loader) }
|
68
|
-
end
|
69
|
-
|
70
|
-
# This is an internal method only used by the test suite.
|
71
|
-
#
|
72
|
-
# @sig (String) -> Zeitwerk::Loader?
|
73
|
-
internal def registered?(cname_or_cpath)
|
74
|
-
@loaders[cname_or_cpath]
|
75
|
-
end
|
76
|
-
|
77
|
-
# This is an internal method only used by the test suite.
|
78
|
-
#
|
79
|
-
# @sig () -> void
|
80
|
-
internal def clear
|
81
|
-
@loaders.clear
|
82
|
-
end
|
83
|
-
|
84
|
-
module Synchronized
|
85
|
-
extend Internal
|
86
|
-
|
87
|
-
MUTEX = Mutex.new
|
88
|
-
|
89
|
-
internal def register(...)
|
90
|
-
MUTEX.synchronize { super }
|
91
|
-
end
|
92
|
-
|
93
|
-
internal def loader_for(...)
|
94
|
-
MUTEX.synchronize { super }
|
95
|
-
end
|
96
|
-
|
97
|
-
internal def unregister_loader(...)
|
98
|
-
MUTEX.synchronize { super }
|
99
|
-
end
|
100
|
-
|
101
|
-
internal def registered?(...)
|
102
|
-
MUTEX.synchronize { super }
|
103
|
-
end
|
104
|
-
|
105
|
-
internal def clear
|
106
|
-
MUTEX.synchronize { super }
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
prepend Synchronized unless RUBY_ENGINE == "ruby"
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|