zeitwerk 1.3.4 → 1.4.0

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: 53e3caf01e7af10f0f12922ebbe41f400a27eee1fa8d47a1d580ba1bb421393b
4
- data.tar.gz: 6b76087bdc7abec95aa7a70ee5c5b70cb7567e7b02c8dbb290852a3bda523089
3
+ metadata.gz: a7e867060d3bf347938f153335a463ddbb48995f70f3aed8472a6641e2592a71
4
+ data.tar.gz: af10438f14e119bf184133b1c1734e01fbe61954ce2128805a1ab941125dc4cf
5
5
  SHA512:
6
- metadata.gz: 31aabb9e4c66028674508efa6dad871ece2893a3bb78e9c53d24be6721dbbd1a9f0960348ca5c7b33dc3e16670bd2c8b37eea3d813f6ce045b63410a73033a66
7
- data.tar.gz: dc9f42aecb424d7695d48e831ec0ef70159538ded7abf470cc0a26195087aa8a3ce0d3a3a83c8978a88dda8fccb747013db60b0b1b2169e5a6c9ff1b30e94bb8
6
+ metadata.gz: a744a32914b0bd02c07842b448770512d6a8aad66b5524bbe9bb6ef854faeea1ce11e2090bc9a968aebb3501d54de54f65f7927f9d26d4f365a13ad806920e38
7
+ data.tar.gz: 032c50fd06d88be03ee5fae4d7fd6bdbd34780b5dc1f978a8a63a3a9bdda960d417dcb91b40bb82865d3c58b6751cf58506c1bed2454c65c14c6c1d2b5f7bdc7
data/README.md CHANGED
@@ -216,7 +216,14 @@ Zeitwerk instances are able to eager load their managed files:
216
216
  loader.eager_load
217
217
  ```
218
218
 
219
- That skips ignored files and directories.
219
+ That skips [ignored files and directories](#ignoring-parts-of-the-project), and you can also tell Zeitwerk that certain files or directories are autoloadable, but should not be eager loaded:
220
+
221
+ ```ruby
222
+ db_adapters = "#{__dir__}/my_gem/db_adapters"
223
+ loader.do_not_eager_load(db_adapters)
224
+ loader.setup
225
+ loader.eager_load # won't eager load the database adapters
226
+ ```
220
227
 
221
228
  Eager loading is synchronized and idempotent.
222
229
 
@@ -57,6 +57,10 @@ module Zeitwerk
57
57
  @cpaths = {}
58
58
  @mutex = Mutex.new
59
59
  @tracer = TracePoint.new(:class) do |event|
60
+ # If the class is a singleton class, we won't do anything with it so we can bail out immediately.
61
+ # This is several orders of magnitude faster than accessing `Module#name`.
62
+ next if event.self.singleton_class?
63
+
60
64
  # Note that it makes sense to compute the hash code unconditionally,
61
65
  # because the trace point is disabled if cpaths is empty.
62
66
  if loader = cpaths.delete(event.self.name)
@@ -57,7 +57,7 @@ module Zeitwerk
57
57
  #
58
58
  # A shadowed file is a file managed by this autoloader that is skipped
59
59
  # because its matching constant path has already been seen. Think $LOAD_PATH
60
- # + require, only the first occurrence of a given relative name is loaded.
60
+ # and require, only the first occurrence of a given relative name is loaded.
61
61
  #
62
62
  # If the existing occurrence is an autoload, we map the file name to the
63
63
  # shadowing autoload path. If the existing occurrence is an already defined
@@ -66,7 +66,7 @@ module Zeitwerk
66
66
  #
67
67
  # @private
68
68
  # @return [{String => String}]
69
- attr_reader :shadowed
69
+ attr_reader :shadowed_files
70
70
 
71
71
  # Maps real absolute paths for which an autoload has been set to their
72
72
  # corresponding parent class or module and constant name.
@@ -83,7 +83,7 @@ module Zeitwerk
83
83
  #
84
84
  # @private
85
85
  # @return [Set<String>]
86
- attr_reader :loaded
86
+ attr_reader :loaded_cpaths
87
87
 
88
88
  # Maps constant paths of namespaces to arrays of corresponding directories.
89
89
  #
@@ -103,6 +103,12 @@ module Zeitwerk
103
103
  # @return [{String => <String>}]
104
104
  attr_reader :lazy_subdirs
105
105
 
106
+ # Absolute paths of files or directories not to be eager loaded.
107
+ #
108
+ # @private
109
+ # @return [Set<String>]
110
+ attr_reader :eager_load_exclusions
111
+
106
112
  # @private
107
113
  # @return [Mutex]
108
114
  attr_reader :mutex
@@ -114,14 +120,15 @@ module Zeitwerk
114
120
  @inflector = Inflector.new
115
121
  @logger = self.class.default_logger
116
122
 
117
- @root_dirs = {}
118
- @preloads = []
119
- @ignored = Set.new
120
- @ignored_paths = Set.new
121
- @autoloads = {}
122
- @loaded = Set.new
123
- @lazy_subdirs = {}
124
- @shadowed = {}
123
+ @root_dirs = {}
124
+ @preloads = []
125
+ @ignored = Set.new
126
+ @ignored_paths = Set.new
127
+ @autoloads = {}
128
+ @loaded_cpaths = Set.new
129
+ @lazy_subdirs = {}
130
+ @shadowed_files = {}
131
+ @eager_load_exclusions = Set.new
125
132
 
126
133
  @mutex = Mutex.new
127
134
  @setup = false
@@ -230,9 +237,9 @@ module Zeitwerk
230
237
  end
231
238
 
232
239
  autoloads.clear
233
- loaded.clear
240
+ loaded_cpaths.clear
234
241
  lazy_subdirs.clear
235
- shadowed.clear
242
+ shadowed_files.clear
236
243
 
237
244
  Registry.on_unload(self)
238
245
  ExplicitNamespace.unregister(self)
@@ -255,18 +262,21 @@ module Zeitwerk
255
262
 
256
263
  # Eager loads all files in the root directories, recursively. Files do not
257
264
  # need to be in `$LOAD_PATH`, absolute file names are used. Ignored files
258
- # are not eager loaded.
265
+ # are not eager loaded. You can opt-out specifically in specific files and
266
+ # directories with `do_not_eager_load`.
259
267
  #
260
268
  # @return [void]
261
269
  def eager_load
262
270
  mutex.synchronize do
263
271
  break if @eager_loaded
264
272
 
265
- queue = non_ignored_root_dirs
273
+ queue = non_ignored_root_dirs.reject { |dir| eager_load_exclusions.member?(dir) }
266
274
  while dir = queue.shift
267
275
  each_abspath(dir) do |abspath|
276
+ next if eager_load_exclusions.member?(abspath)
277
+
268
278
  if ruby?(abspath)
269
- require abspath unless shadowed.key?(abspath)
279
+ require abspath unless shadowed_files.key?(abspath)
270
280
  elsif dir?(abspath)
271
281
  queue << abspath
272
282
  end
@@ -277,12 +287,21 @@ module Zeitwerk
277
287
  end
278
288
  end
279
289
 
290
+ # Let eager load ignore the given files or directories. The constants
291
+ # defined in those files are still autoloadable.
292
+ #
293
+ # @param paths [<String, Pathname, <String, Pathname>>]
294
+ # @return [void]
295
+ def do_not_eager_load(*paths)
296
+ mutex.synchronize { eager_load_exclusions.merge(expand_paths(paths)) }
297
+ end
298
+
280
299
  # Says if the given constant path has been loaded.
281
300
  #
282
301
  # @param cpath [String]
283
302
  # @return [Boolean]
284
303
  def loaded?(cpath)
285
- loaded.member?(cpath)
304
+ loaded_cpaths.member?(cpath)
286
305
  end
287
306
 
288
307
  # --- Class methods ---------------------------------------------------------------------------
@@ -387,7 +406,7 @@ module Zeitwerk
387
406
  def autoload_file(parent, cname, file)
388
407
  if autoload_path = autoload_for?(parent, cname)
389
408
  # First autoload for a Ruby file wins, just ignore subsequent ones.
390
- shadowed[file] = autoload_path and return if ruby?(autoload_path)
409
+ shadowed_files[file] = autoload_path and return if ruby?(autoload_path)
391
410
 
392
411
  # Override autovivification, we want the namespace to become the
393
412
  # class/module defined in this file.
@@ -397,7 +416,7 @@ module Zeitwerk
397
416
  set_autoload(parent, cname, file)
398
417
  register_explicit_namespace(cpath(parent, cname))
399
418
  elsif cdef?(parent, cname)
400
- shadowed[file] = cpath(parent, cname)
419
+ shadowed_files[file] = cpath(parent, cname)
401
420
  else
402
421
  set_autoload(parent, cname, file)
403
422
  end
@@ -6,7 +6,7 @@ module Zeitwerk::Loader::Callbacks
6
6
  # @return [void]
7
7
  def on_file_autoloaded(file)
8
8
  parent, cname = autoloads[file]
9
- loaded.add(cpath(parent, cname))
9
+ loaded_cpaths.add(cpath(parent, cname))
10
10
  log("constant #{cpath(parent, cname)} loaded from file #{file}") if logger
11
11
  end
12
12
 
@@ -22,7 +22,7 @@ module Zeitwerk::Loader::Callbacks
22
22
  autovivified_module = parent.const_set(cname, Module.new)
23
23
  log("module #{autovivified_module.name} autovivified from directory #{dir}") if logger
24
24
 
25
- loaded.add(autovivified_module.name)
25
+ loaded_cpaths.add(autovivified_module.name)
26
26
  on_namespace_loaded(autovivified_module)
27
27
  end
28
28
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Zeitwerk
4
- VERSION = "1.3.4"
4
+ VERSION = "1.4.0"
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: 1.3.4
4
+ version: 1.4.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-03-14 00:00:00.000000000 Z
11
+ date: 2019-03-19 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |2
14
14
  Zeitwerk implements constant autoloading with Ruby semantics. Each gem