im 0.2.0 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +28 -31
- data/lib/im/const_path.rb +2 -0
- data/lib/im/loader.rb +2 -1
- data/lib/im/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12f266a57a80938158b66bdbc0345fcdc0305c11ddaca54e510613426f1ec0ca
|
4
|
+
data.tar.gz: f1a64495a579e4fba187e8d1f6db1f3025da5dfe47b7217c255e1e8ff03fd4c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a33aaedf83fcf5c85ec424ad6307236ced2a952575348a66689cc54c468e6bee697f7daec25f8259c1e18942ec2b307ac24a524c6c21994efcd376f5fb74fbf
|
7
|
+
data.tar.gz: 8f2bcfab90aae5e132a65021169860128586102e7fc405777d96ee505674354ef1f13bf4d8d53810eb04ab2d93ad6602266647765e2c571490122a0915fab481
|
data/README.md
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
# Im
|
2
2
|
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/im.svg)][gem]
|
3
4
|
[![Build Status](https://github.com/shioyama/im/actions/workflows/ci.yml/badge.svg)][actions]
|
4
5
|
|
6
|
+
[gem]: https://rubygems.org/gems/im
|
5
7
|
[actions]: https://github.com/shioyama/im/actions
|
6
8
|
|
7
9
|
<!-- TOC -->
|
@@ -28,13 +30,12 @@ any way touching the global namespace.
|
|
28
30
|
To do this, Im leverages code autoloading, Zeitwerk conventions around file
|
29
31
|
structure and naming, and two features added in Ruby 3.2: `Kernel#load`
|
30
32
|
with a module argument[^1] and `Module#const_added`[^2]. Since these Ruby
|
31
|
-
features are essential to its design,
|
33
|
+
features are essential to its design, Im is not usable with earlier versions
|
32
34
|
of Ruby.
|
33
35
|
|
34
|
-
Im started its life as a fork of Zeitwerk and has a very similar interface.
|
35
|
-
|
36
|
-
|
37
|
-
paths managed by each gem.
|
36
|
+
Im started its life as a fork of Zeitwerk and has a very similar interface. Im
|
37
|
+
and Zeitwerk can be used alongside each other provided there is no overlap
|
38
|
+
between file paths managed by each gem.
|
38
39
|
|
39
40
|
Im is in active development and should be considered experimental until the
|
40
41
|
eventual release of version 1.0. Versions 0.1.6 and earlier of the gem were
|
@@ -43,12 +44,12 @@ part of a different experiment and are unrelated to the current gem.
|
|
43
44
|
<a id="markdown-synopsis" name="synopsis"></a>
|
44
45
|
## Synopsis
|
45
46
|
|
46
|
-
Im
|
47
|
-
|
47
|
+
Im's public interface is in most respects identical to that of Zeitwerk. The
|
48
|
+
central difference is that whereas Zeitwerk loads constants into the global
|
48
49
|
namespace (rooted in `Object`), Im loads them into anonymous namespaces rooted
|
49
|
-
on the loader itself.
|
50
|
-
|
51
|
-
loaders, there can also be arbitrarily many autoloaded namespaces.
|
50
|
+
on the loader itself. `Im::Loader` is a subclass of `Module`, and thus each
|
51
|
+
loader instance can define its own namespace. Since there can be arbitrarily
|
52
|
+
many loaders, there can also be arbitrarily many autoloaded namespaces.
|
52
53
|
|
53
54
|
Im's gem interface looks like this:
|
54
55
|
|
@@ -66,7 +67,7 @@ end
|
|
66
67
|
loader.eager_load # optionally
|
67
68
|
```
|
68
69
|
|
69
|
-
The generic interface is
|
70
|
+
The generic interface is identical to Zeitwerk's:
|
70
71
|
|
71
72
|
```ruby
|
72
73
|
loader = Zeitwerk::Loader.new
|
@@ -84,7 +85,7 @@ Object.const_defined?(:MyGem)
|
|
84
85
|
```
|
85
86
|
|
86
87
|
In order to prevent leakage, the gem's entrypoint, in this case
|
87
|
-
`lib/my_gem.rb
|
88
|
+
`lib/my_gem.rb`, must not define anything at toplevel, hence the use of
|
88
89
|
`module loader::MyGem`.
|
89
90
|
|
90
91
|
Once the entrypoint has been required, all constants defined within the gem's
|
@@ -107,7 +108,7 @@ foo = loader::MyGem::Foo
|
|
107
108
|
# loads `Foo` from lib/my_gem/foo.rb
|
108
109
|
|
109
110
|
foo.new.hello_world
|
110
|
-
|
111
|
+
#=> "Hello World!"
|
111
112
|
```
|
112
113
|
|
113
114
|
Constants under the loader can be given permanent names that are different from
|
@@ -116,16 +117,12 @@ the one defined in the gem itself:
|
|
116
117
|
```ruby
|
117
118
|
Bar = loader::MyGem::Foo
|
118
119
|
Bar.new.hello_world
|
119
|
-
|
120
|
+
#=> "Hello World!"
|
120
121
|
```
|
121
122
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
The loader variable can go out of scope. Like Zeitwerk, Im keeps a registry
|
126
|
-
with all of them, and so the object won't be garbage collected. For
|
127
|
-
convenience, Im also provides a method, `Im#import`, to fetch a loader for
|
128
|
-
a given file path:
|
123
|
+
Like Zeitwerk, Im keeps a registry of all loaders, so the loader objects won't
|
124
|
+
be garbage collected. For convenience, Im also provides a method, `Im#import`,
|
125
|
+
to fetch a loader for a given file path:
|
129
126
|
|
130
127
|
```ruby
|
131
128
|
require "im"
|
@@ -133,7 +130,7 @@ require "my_gem"
|
|
133
130
|
|
134
131
|
extend Im
|
135
132
|
my_gem = import "my_gem"
|
136
|
-
#=>
|
133
|
+
#=> my_gem::MyGem is autoloadable
|
137
134
|
```
|
138
135
|
|
139
136
|
Reloading works like Zeitwerk:
|
@@ -209,15 +206,15 @@ anywhere in the global namespace.
|
|
209
206
|
### Relative and absolute cpaths
|
210
207
|
|
211
208
|
Im uses two types of constant paths: relative and absolute, wherever possible
|
212
|
-
defaulting to relative ones. A
|
209
|
+
defaulting to relative ones. A _relative cpath_ is a constant name relative to
|
213
210
|
the loader in which it was originally defined, regardless of any other names it
|
214
|
-
was assigned. Whereas Zeitwerk uses absolute cpaths, Im uses relative
|
215
|
-
all external loader APIs (see usage for examples).
|
211
|
+
was later assigned. Whereas Zeitwerk uses absolute cpaths, Im uses relative
|
212
|
+
cpaths for all external loader APIs (see usage for examples).
|
216
213
|
|
217
214
|
To understand these concepts, it is important first to distinguish between two
|
218
215
|
types of names in Ruby: _temporary names_ and _permanent names_.
|
219
216
|
|
220
|
-
A
|
217
|
+
A _temporary name_ is a constant name on an anonymous-rooted namespace, for
|
221
218
|
example a loader:
|
222
219
|
|
223
220
|
```ruby
|
@@ -228,7 +225,7 @@ my_gem::Foo.name
|
|
228
225
|
```
|
229
226
|
|
230
227
|
Here, the string `"#<Im::Loader ...>::Foo"` is called a temporary name. We can
|
231
|
-
give this module a
|
228
|
+
give this module a _permanent name_ by assigning it to a toplevel constant:
|
232
229
|
|
233
230
|
```ruby
|
234
231
|
Bar = my_gem::Foo
|
@@ -244,12 +241,12 @@ keys in Im's internal registries to index constants and their autoloads, which
|
|
244
241
|
is critical for successful autoloading.
|
245
242
|
|
246
243
|
To get around this issue, Im tracks all module names and uses relative naming
|
247
|
-
inside loader code.
|
248
|
-
|
244
|
+
inside loader code. Internally, Im has a method, `relative_cpath`, which can
|
245
|
+
generate any module name under a module in the loader namespace:
|
249
246
|
|
250
247
|
```ruby
|
251
|
-
my_gem.relative_cpath
|
252
|
-
#=> "Foo"
|
248
|
+
my_gem.send(:relative_cpath, loader::Foo, :Baz)
|
249
|
+
#=> "Foo::Baz"
|
253
250
|
```
|
254
251
|
|
255
252
|
Using relative cpaths frees Im from depending on `Module#name` for
|
data/lib/im/const_path.rb
CHANGED
data/lib/im/loader.rb
CHANGED
@@ -349,7 +349,7 @@ module Im
|
|
349
349
|
|
350
350
|
private # -------------------------------------------------------------------------------------
|
351
351
|
|
352
|
-
# @sig (String, Module) -> void
|
352
|
+
# @sig (String, Module?) -> void
|
353
353
|
def set_autoloads_in_dir(dir, parent = self)
|
354
354
|
ls(dir) do |basename, abspath|
|
355
355
|
begin
|
@@ -516,6 +516,7 @@ module Im
|
|
516
516
|
else
|
517
517
|
# If an autoloaded file loads an autoloaded constant from another file, we need to deduce the module name
|
518
518
|
# before we can add the parent to module_cpaths. In this case, we have no choice but to work from to_s.
|
519
|
+
#binding.irb if parent.is_a?(String)
|
519
520
|
mod_name = Im.cpath(parent)
|
520
521
|
current_module_prefix = "#{Im.cpath(self)}::"
|
521
522
|
raise InvalidModuleName, "invalid module name for #{parent}" unless mod_name.start_with?(current_module_prefix)
|
data/lib/im/version.rb
CHANGED