zeitwerk 2.6.7 → 2.6.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +60 -0
- data/lib/zeitwerk/gem_inflector.rb +2 -2
- data/lib/zeitwerk/gem_loader.rb +11 -7
- data/lib/zeitwerk/loader/config.rb +7 -8
- data/lib/zeitwerk/loader.rb +33 -1
- data/lib/zeitwerk/registry.rb +2 -2
- data/lib/zeitwerk/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 418f16f6224359c716a990f72ae916c980a3f388b09ab018c0972b8558530620
|
4
|
+
data.tar.gz: '04847c6c8f8f894fe3c2b3c39d175b5854b583d3a02ef5cca27a53cb1b8dafd4'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f86272e84721cf9b8b1e07182b1b60cfe732ef2c266dbe076225d32af52fc9a30c278a14651ddbb3d435636646dd23c948d3fe0f00ed9b8393abdeb34dd40028
|
7
|
+
data.tar.gz: 562738b53779310e899c2065c7046844d27daabb5f354972e4c9b65bec3e5c0cdade92d19ed815fe7b0dc01538603daa3e4dd2f0049fe9a7a2e74313c0f040f6
|
data/README.md
CHANGED
@@ -24,6 +24,7 @@
|
|
24
24
|
- [Setup](#setup)
|
25
25
|
- [Generic](#generic)
|
26
26
|
- [for_gem](#for_gem)
|
27
|
+
- [for_gem_extension](#for_gem_extension)
|
27
28
|
- [Autoloading](#autoloading)
|
28
29
|
- [Eager loading](#eager-loading)
|
29
30
|
- [Eager load exclusions](#eager-load-exclusions)
|
@@ -410,6 +411,65 @@ Otherwise, there's a flag to say the extra stuff is OK:
|
|
410
411
|
Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
|
411
412
|
```
|
412
413
|
|
414
|
+
<a id="markdown-for_gem_extension" name="for_gem_extension"></a>
|
415
|
+
#### for_gem_extension
|
416
|
+
|
417
|
+
Let's suppose you are writing a gem to extend `Net::HTTP` with some niche feature. By [convention](https://guides.rubygems.org/name-your-gem/):
|
418
|
+
|
419
|
+
* The gem should be called `net-http-niche_feature`. That is, hyphens for the extended part, a hyphen, and underscores for yours.
|
420
|
+
* The namespace should be `Net::HTTP::NicheFeature`.
|
421
|
+
* The entry point should be `lib/net/http/niche_feature.rb`.
|
422
|
+
* Optionally, the gem could have a top-level `lib/net-http-niche_feature.rb`, but, if defined, that one should have just a `require` call for the entry point.
|
423
|
+
|
424
|
+
The top-level file mentioned in the last point is optional. In particular, from
|
425
|
+
|
426
|
+
```ruby
|
427
|
+
gem "net-http-niche_feature"
|
428
|
+
```
|
429
|
+
|
430
|
+
if the hyphenated file does not exist, Bundler notes the conventional hyphenated pattern and issues a `require` for `net/http/niche_feature`.
|
431
|
+
|
432
|
+
Gem extensions following the conventions above have a dedicated loader constructor: `Zeitwerk::Loader.for_gem_extension`.
|
433
|
+
|
434
|
+
The structure of the gem would be like this:
|
435
|
+
|
436
|
+
```ruby
|
437
|
+
# lib/net-http-niche_feature.rb (optional)
|
438
|
+
|
439
|
+
# For technical reasons, this cannot be require_relative.
|
440
|
+
require "net/http/niche_feature"
|
441
|
+
|
442
|
+
|
443
|
+
# lib/net/http/niche_feature.rb
|
444
|
+
|
445
|
+
require "net/http"
|
446
|
+
require "zeitwerk"
|
447
|
+
|
448
|
+
loader = Zeitwerk::Loader.for_gem_extension(Net::HTTP)
|
449
|
+
loader.setup
|
450
|
+
|
451
|
+
module Net::HTTP::NicheFeature
|
452
|
+
# Since the setup has been performed, at this point we are already able
|
453
|
+
# to reference project constants, in this case Net::HTTP::NicheFeature::MyMixin.
|
454
|
+
include MyMixin
|
455
|
+
end
|
456
|
+
|
457
|
+
|
458
|
+
# lib/net/http/niche_feature/version.rb
|
459
|
+
|
460
|
+
module Net::HTTP::NicheFeature
|
461
|
+
VERSION = "1.0.0"
|
462
|
+
end
|
463
|
+
```
|
464
|
+
|
465
|
+
`Zeitwerk::Loader.for_gem_extension` expects as argument the namespace being extended, which has to be a non-anonymous class or module object.
|
466
|
+
|
467
|
+
If it exists, `lib/net/http/niche_feature/version.rb` is expected to define `Net::HTTP::NicheFeature::VERSION`.
|
468
|
+
|
469
|
+
Due to technical reasons, the entry point of the gem has to be loaded with `Kernel#require`. Loading that file with `Kernel#load` or `Kernel#require_relative` won't generally work. This is important if you load the entry point from the optional hyphenated top-level file.
|
470
|
+
|
471
|
+
`Zeitwerk::Loader.for_gem_extension` is idempotent when invoked from the same file, to support gems that want to reload (unlikely).
|
472
|
+
|
413
473
|
<a id="markdown-autoloading" name="autoloading"></a>
|
414
474
|
### Autoloading
|
415
475
|
|
@@ -5,8 +5,8 @@ module Zeitwerk
|
|
5
5
|
# @sig (String) -> void
|
6
6
|
def initialize(root_file)
|
7
7
|
namespace = File.basename(root_file, ".rb")
|
8
|
-
|
9
|
-
@version_file = File.join(
|
8
|
+
root_dir = File.dirname(root_file)
|
9
|
+
@version_file = File.join(root_dir, namespace, "version.rb")
|
10
10
|
end
|
11
11
|
|
12
12
|
# @sig (String, String) -> String
|
data/lib/zeitwerk/gem_loader.rb
CHANGED
@@ -3,27 +3,31 @@
|
|
3
3
|
module Zeitwerk
|
4
4
|
# @private
|
5
5
|
class GemLoader < Loader
|
6
|
+
include RealModName
|
7
|
+
|
6
8
|
# Users should not create instances directly, the public interface is
|
7
9
|
# `Zeitwerk::Loader.for_gem`.
|
8
10
|
private_class_method :new
|
9
11
|
|
10
12
|
# @private
|
11
13
|
# @sig (String, bool) -> Zeitwerk::GemLoader
|
12
|
-
def self.
|
13
|
-
new(root_file, warn_on_extra_files: warn_on_extra_files)
|
14
|
+
def self.__new(root_file, namespace:, warn_on_extra_files:)
|
15
|
+
new(root_file, namespace: namespace, warn_on_extra_files: warn_on_extra_files)
|
14
16
|
end
|
15
17
|
|
16
18
|
# @sig (String, bool) -> void
|
17
|
-
def initialize(root_file, warn_on_extra_files:)
|
19
|
+
def initialize(root_file, namespace:, warn_on_extra_files:)
|
18
20
|
super()
|
19
21
|
|
20
|
-
@tag
|
22
|
+
@tag = File.basename(root_file, ".rb")
|
23
|
+
@tag = real_mod_name(namespace) + "-" + @tag unless namespace.equal?(Object)
|
24
|
+
|
21
25
|
@inflector = GemInflector.new(root_file)
|
22
26
|
@root_file = File.expand_path(root_file)
|
23
|
-
@
|
27
|
+
@root_dir = File.dirname(root_file)
|
24
28
|
@warn_on_extra_files = warn_on_extra_files
|
25
29
|
|
26
|
-
push_dir(@
|
30
|
+
push_dir(@root_dir, namespace: namespace)
|
27
31
|
end
|
28
32
|
|
29
33
|
# @sig () -> void
|
@@ -38,7 +42,7 @@ module Zeitwerk
|
|
38
42
|
def warn_on_extra_files
|
39
43
|
expected_namespace_dir = @root_file.delete_suffix(".rb")
|
40
44
|
|
41
|
-
ls(@
|
45
|
+
ls(@root_dir) do |basename, abspath|
|
42
46
|
next if abspath == @root_file
|
43
47
|
next if abspath == expected_namespace_dir
|
44
48
|
|
@@ -109,8 +109,7 @@ module Zeitwerk::Loader::Config
|
|
109
109
|
# @raise [Zeitwerk::Error]
|
110
110
|
# @sig (String | Pathname, Module) -> void
|
111
111
|
def push_dir(path, namespace: Object)
|
112
|
-
# Note that Class < Module.
|
113
|
-
unless namespace.is_a?(Module)
|
112
|
+
unless namespace.is_a?(Module) # Note that Class < Module.
|
114
113
|
raise Zeitwerk::Error, "#{namespace.inspect} is not a class or module object, should be"
|
115
114
|
end
|
116
115
|
|
@@ -298,9 +297,9 @@ module Zeitwerk::Loader::Config
|
|
298
297
|
# Common use case.
|
299
298
|
return false if ignored_paths.empty?
|
300
299
|
|
301
|
-
walk_up(abspath) do |
|
302
|
-
return true if ignored_path?(
|
303
|
-
return false if roots.key?(
|
300
|
+
walk_up(abspath) do |path|
|
301
|
+
return true if ignored_path?(path)
|
302
|
+
return false if roots.key?(path)
|
304
303
|
end
|
305
304
|
|
306
305
|
false
|
@@ -328,9 +327,9 @@ module Zeitwerk::Loader::Config
|
|
328
327
|
# Optimize this common use case.
|
329
328
|
return false if eager_load_exclusions.empty?
|
330
329
|
|
331
|
-
walk_up(abspath) do |
|
332
|
-
return true if eager_load_exclusions.member?(
|
333
|
-
return false if roots.key?(
|
330
|
+
walk_up(abspath) do |path|
|
331
|
+
return true if eager_load_exclusions.member?(path)
|
332
|
+
return false if roots.key?(path)
|
334
333
|
end
|
335
334
|
|
336
335
|
false
|
data/lib/zeitwerk/loader.rb
CHANGED
@@ -264,12 +264,15 @@ module Zeitwerk
|
|
264
264
|
# --- Class methods ---------------------------------------------------------------------------
|
265
265
|
|
266
266
|
class << self
|
267
|
+
include RealModName
|
268
|
+
|
267
269
|
# @sig #call | #debug | nil
|
268
270
|
attr_accessor :default_logger
|
269
271
|
|
270
272
|
# This is a shortcut for
|
271
273
|
#
|
272
274
|
# require "zeitwerk"
|
275
|
+
#
|
273
276
|
# loader = Zeitwerk::Loader.new
|
274
277
|
# loader.tag = File.basename(__FILE__, ".rb")
|
275
278
|
# loader.inflector = Zeitwerk::GemInflector.new(__FILE__)
|
@@ -284,7 +287,36 @@ module Zeitwerk
|
|
284
287
|
# @sig (bool) -> Zeitwerk::GemLoader
|
285
288
|
def for_gem(warn_on_extra_files: true)
|
286
289
|
called_from = caller_locations(1, 1).first.path
|
287
|
-
Registry.loader_for_gem(called_from, warn_on_extra_files: warn_on_extra_files)
|
290
|
+
Registry.loader_for_gem(called_from, namespace: Object, warn_on_extra_files: warn_on_extra_files)
|
291
|
+
end
|
292
|
+
|
293
|
+
# This is a shortcut for
|
294
|
+
#
|
295
|
+
# require "zeitwerk"
|
296
|
+
#
|
297
|
+
# loader = Zeitwerk::Loader.new
|
298
|
+
# loader.tag = namespace.name + "-" + File.basename(__FILE__, ".rb")
|
299
|
+
# loader.inflector = Zeitwerk::GemInflector.new(__FILE__)
|
300
|
+
# loader.push_dir(__dir__, namespace: namespace)
|
301
|
+
#
|
302
|
+
# except that this method returns the same object in subsequent calls from
|
303
|
+
# the same file, in the unlikely case the gem wants to be able to reload.
|
304
|
+
#
|
305
|
+
# This method returns a subclass of Zeitwerk::Loader, but the exact type
|
306
|
+
# is private, client code can only rely on the interface.
|
307
|
+
#
|
308
|
+
# @sig (bool) -> Zeitwerk::GemLoader
|
309
|
+
def for_gem_extension(namespace)
|
310
|
+
unless namespace.is_a?(Module) # Note that Class < Module.
|
311
|
+
raise Zeitwerk::Error, "#{namespace.inspect} is not a class or module object, should be"
|
312
|
+
end
|
313
|
+
|
314
|
+
unless real_mod_name(namespace)
|
315
|
+
raise Zeitwerk::Error, "extending anonymous namespaces is unsupported"
|
316
|
+
end
|
317
|
+
|
318
|
+
called_from = caller_locations(1, 1).first.path
|
319
|
+
Registry.loader_for_gem(called_from, namespace: namespace, warn_on_extra_files: false)
|
288
320
|
end
|
289
321
|
|
290
322
|
# Broadcasts `eager_load` to all loaders. Those that have not been setup
|
data/lib/zeitwerk/registry.rb
CHANGED
@@ -86,8 +86,8 @@ module Zeitwerk
|
|
86
86
|
#
|
87
87
|
# @private
|
88
88
|
# @sig (String) -> Zeitwerk::Loader
|
89
|
-
def loader_for_gem(root_file, warn_on_extra_files:)
|
90
|
-
gem_loaders_by_root_file[root_file] ||= GemLoader.
|
89
|
+
def loader_for_gem(root_file, namespace:, warn_on_extra_files:)
|
90
|
+
gem_loaders_by_root_file[root_file] ||= GemLoader.__new(root_file, namespace: namespace, warn_on_extra_files: warn_on_extra_files)
|
91
91
|
end
|
92
92
|
|
93
93
|
# @private
|
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.6.
|
4
|
+
version: 2.6.8
|
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-
|
11
|
+
date: 2023-04-28 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |2
|
14
14
|
Zeitwerk implements constant autoloading with Ruby semantics. Each gem
|
@@ -61,7 +61,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
61
61
|
- !ruby/object:Gem::Version
|
62
62
|
version: '0'
|
63
63
|
requirements: []
|
64
|
-
rubygems_version: 3.4.
|
64
|
+
rubygems_version: 3.4.11
|
65
65
|
signing_key:
|
66
66
|
specification_version: 4
|
67
67
|
summary: Efficient and thread-safe constant autoloader
|