zeitwerk 2.0.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/zeitwerk/loader.rb +43 -18
- data/lib/zeitwerk/loader/callbacks.rb +16 -20
- data/lib/zeitwerk/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2af29bb519da160c83620c23a1f1c119c7b534a3e3db308b2635b344b435dfa1
|
4
|
+
data.tar.gz: ec2dc810c74887befea3550b3305b0b096610cbb06a2983dad0c041c9bed34dc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8cafd96d9f21546ea8dcb58f8b589d59b5de994492a2f89f6cd4eb2701d673e58c888884b672ddd47580778090f4af918c908e6325d5690ce8297b0e152eb391
|
7
|
+
data.tar.gz: e1fba9ebf4e35fa10c2577bdb4a19124ee26e3d09a85b2382a5bc0c83688130b14a0c8e9900e6572f25efe86c388b54139d9ca82d7053cfc415b39a618d1ec16
|
data/lib/zeitwerk/loader.rb
CHANGED
@@ -68,8 +68,9 @@ module Zeitwerk
|
|
68
68
|
# @return [{String => String}]
|
69
69
|
attr_reader :shadowed_files
|
70
70
|
|
71
|
-
# Maps real absolute paths for which an autoload has been set
|
72
|
-
# corresponding parent class or module and constant
|
71
|
+
# Maps real absolute paths for which an autoload has been set ---and not
|
72
|
+
# executed--- to their corresponding parent class or module and constant
|
73
|
+
# name.
|
73
74
|
#
|
74
75
|
# "/Users/fxn/blog/app/models/user.rb" => [Object, "User"],
|
75
76
|
# "/Users/fxn/blog/app/models/hotel/pricing.rb" => [Hotel, "Pricing"]
|
@@ -84,13 +85,18 @@ module Zeitwerk
|
|
84
85
|
#
|
85
86
|
# Files are removed as they are autoloaded, but directories need to wait due
|
86
87
|
# to concurrency (see why in Zeitwerk::Loader::Callbacks#on_dir_autoloaded).
|
88
|
+
#
|
89
|
+
# @private
|
90
|
+
# @return [<String>]
|
87
91
|
attr_reader :autoloaded_dirs
|
88
92
|
|
89
|
-
#
|
93
|
+
# Constants paths that would be unloaded if you would reload. If reloading
|
94
|
+
# is enabled, this hash is filled as constants are autoloaded or eager
|
95
|
+
# loaded. Otherwise, the collection remains empty.
|
90
96
|
#
|
91
97
|
# @private
|
92
|
-
# @return [
|
93
|
-
attr_reader :
|
98
|
+
# @return [{String => (String, (Module, String))}]
|
99
|
+
attr_reader :to_unload
|
94
100
|
|
95
101
|
# Maps constant paths of namespaces to arrays of corresponding directories.
|
96
102
|
#
|
@@ -137,7 +143,7 @@ module Zeitwerk
|
|
137
143
|
@ignored_paths = Set.new
|
138
144
|
@autoloads = {}
|
139
145
|
@autoloaded_dirs = []
|
140
|
-
@
|
146
|
+
@to_unload = {}
|
141
147
|
@lazy_subdirs = {}
|
142
148
|
@shadowed_files = {}
|
143
149
|
@eager_load_exclusions = Set.new
|
@@ -270,19 +276,21 @@ module Zeitwerk
|
|
270
276
|
|
271
277
|
autoloads.each do |realpath, (parent, cname)|
|
272
278
|
if parent.autoload?(cname)
|
273
|
-
parent
|
274
|
-
log("autoload for #{cpath(parent, cname)} removed") if logger
|
279
|
+
unload_autoload(parent, cname)
|
275
280
|
else
|
276
|
-
if
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
# Already unloaded somehow, that is fine.
|
281
|
-
end
|
281
|
+
# Could happen if loaded with require_relative. require_relative is
|
282
|
+
# not supported, and the cpath would escape `to_unload?`. This is
|
283
|
+
# just defensive code to clean things up as much as we are able to.
|
284
|
+
unload_cref(parent, cname) if cdef?(parent, cname)
|
282
285
|
unloaded_files.add(realpath) if ruby?(realpath)
|
283
286
|
end
|
284
287
|
end
|
285
288
|
|
289
|
+
to_unload.each_value do |(realpath, (parent, cname))|
|
290
|
+
unload_cref(parent, cname) if cdef?(parent, cname)
|
291
|
+
unloaded_files.add(realpath) if ruby?(realpath)
|
292
|
+
end
|
293
|
+
|
286
294
|
unless unloaded_files.empty?
|
287
295
|
# Bootsnap decorates Kernel#require to speed it up using a cache and
|
288
296
|
# this optimization does not check if $LOADED_FEATURES has the file.
|
@@ -300,7 +308,7 @@ module Zeitwerk
|
|
300
308
|
|
301
309
|
autoloads.clear
|
302
310
|
autoloaded_dirs.clear
|
303
|
-
|
311
|
+
to_unload.clear
|
304
312
|
lazy_subdirs.clear
|
305
313
|
shadowed_files.clear
|
306
314
|
|
@@ -369,12 +377,13 @@ module Zeitwerk
|
|
369
377
|
mutex.synchronize { eager_load_exclusions.merge(expand_paths(paths)) }
|
370
378
|
end
|
371
379
|
|
372
|
-
# Says if the given constant path
|
380
|
+
# Says if the given constant path would be unloaded on reload. This
|
381
|
+
# predicate returns `false` if reloading is disabled.
|
373
382
|
#
|
374
383
|
# @param cpath [String]
|
375
384
|
# @return [Boolean]
|
376
|
-
def
|
377
|
-
|
385
|
+
def to_unload?(cpath)
|
386
|
+
to_unload.key?(cpath)
|
378
387
|
end
|
379
388
|
|
380
389
|
# --- Class methods ---------------------------------------------------------------------------
|
@@ -662,5 +671,21 @@ module Zeitwerk
|
|
662
671
|
end
|
663
672
|
end
|
664
673
|
end
|
674
|
+
|
675
|
+
# @param parent [Module]
|
676
|
+
# @param cname [String]
|
677
|
+
# @return [void]
|
678
|
+
def unload_autoload(parent, cname)
|
679
|
+
parent.send(:remove_const, cname)
|
680
|
+
log("autoload for #{cpath(parent, cname)} removed") if logger
|
681
|
+
end
|
682
|
+
|
683
|
+
# @param parent [Module]
|
684
|
+
# @param cname [String]
|
685
|
+
# @return [void]
|
686
|
+
def unload_cref(parent, cname)
|
687
|
+
parent.send(:remove_const, cname)
|
688
|
+
log("#{cpath(parent, cname)} unloaded") if logger
|
689
|
+
end
|
665
690
|
end
|
666
691
|
end
|
@@ -5,10 +5,10 @@ module Zeitwerk::Loader::Callbacks
|
|
5
5
|
# @param file [String]
|
6
6
|
# @return [void]
|
7
7
|
def on_file_autoloaded(file)
|
8
|
-
|
9
|
-
|
8
|
+
cref = autoloads.delete(file)
|
9
|
+
to_unload[cpath(*cref)] = [file, cref] if reloading_enabled?
|
10
10
|
Zeitwerk::Registry.unregister_autoload(file)
|
11
|
-
log("constant #{cpath(
|
11
|
+
log("constant #{cpath(*cref)} loaded from file #{file}") if logger
|
12
12
|
end
|
13
13
|
|
14
14
|
# Invoked from our decorated Kernel#require when a managed directory is
|
@@ -25,23 +25,25 @@ module Zeitwerk::Loader::Callbacks
|
|
25
25
|
# autovivifies the module, and while autoloads for its children are being
|
26
26
|
# set, thread t2 autoloads the same namespace.
|
27
27
|
#
|
28
|
-
# Without the mutex and
|
28
|
+
# Without the mutex and subsequent delete call, t2 would reset the module.
|
29
29
|
# That not only would reassign the constant (undesirable per se) but, worse,
|
30
30
|
# the module object created by t2 wouldn't have any of the autoloads for its
|
31
31
|
# children, since t1 would have correctly deleted its lazy_subdirs entry.
|
32
32
|
mutex2.synchronize do
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
# except the first one.
|
37
|
-
break if parent.nil? || loaded_cpaths.include?(cpath(parent, cname))
|
33
|
+
if cref = autoloads.delete(dir)
|
34
|
+
autovivified_module = cref[0].const_set(cref[1], Module.new)
|
35
|
+
log("module #{autovivified_module.name} autovivified from directory #{dir}") if logger
|
38
36
|
|
39
|
-
|
40
|
-
log("module #{autovivified_module.name} autovivified from directory #{dir}") if logger
|
37
|
+
to_unload[autovivified_module.name] = [dir, cref] if reloading_enabled?
|
41
38
|
|
42
|
-
|
43
|
-
|
44
|
-
|
39
|
+
# We don't unregister `dir` in the registry because concurrent threads
|
40
|
+
# wouldn't find a loader associated to it in Kernel#require and would
|
41
|
+
# try to require the directory. Instead, we are going to keep track of
|
42
|
+
# these to be able to unregister later if eager loading.
|
43
|
+
autoloaded_dirs << dir
|
44
|
+
|
45
|
+
on_namespace_loaded(autovivified_module)
|
46
|
+
end
|
45
47
|
end
|
46
48
|
end
|
47
49
|
|
@@ -59,10 +61,4 @@ module Zeitwerk::Loader::Callbacks
|
|
59
61
|
end
|
60
62
|
end
|
61
63
|
end
|
62
|
-
|
63
|
-
# @private
|
64
|
-
# @return [(Module, String)]
|
65
|
-
def cref_autoloaded_from(path)
|
66
|
-
reloading_enabled? ? autoloads[path] : autoloads.delete(path)
|
67
|
-
end
|
68
64
|
end
|
data/lib/zeitwerk/version.rb
CHANGED
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.
|
4
|
+
version: 2.1.0
|
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-
|
11
|
+
date: 2019-04-09 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |2
|
14
14
|
Zeitwerk implements constant autoloading with Ruby semantics. Each gem
|