zeitwerk 2.6.7 → 2.6.8
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/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
|