im 0.2.0 → 0.2.1
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/loader.rb +1 -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: e1708fffea9fb79c809dbfa34669e5471556e4d969ae8d95e689cfccc5c6f3e4
|
4
|
+
data.tar.gz: bce10f72bc879a53bda624ced7534bd0c74fc5666c6ff8545ea9371521edc8b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a112f1ee72916d690c0227a94a16f87d283b93a059f1e01d8681649ac9405ce46add46650234b2e337ace8b8571c64ba4f722f256099263eea04cfaafb3f02e1
|
7
|
+
data.tar.gz: b7a03df97bcbac97f09c8637f9c8b82fbaaddcd58640aecc2406e821910fe5cb2ed4200ddc2d6490bc0d0d2d42e6a65173bb7a52ba78c7ed2c05126a0edc669b
|
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/loader.rb
CHANGED
@@ -390,7 +390,7 @@ module Im
|
|
390
390
|
def autoload_subdir(parent, cname, subdir)
|
391
391
|
if autoload_path = autoload_path_set_by_me_for?(parent, cname)
|
392
392
|
absolute_cpath = cpath(parent, cname)
|
393
|
-
relative_cpath = relative_cpath(
|
393
|
+
relative_cpath = relative_cpath(absolute_cpath, cname)
|
394
394
|
register_explicit_namespace(cpath, relative_cpath) if ruby?(autoload_path)
|
395
395
|
|
396
396
|
# We do not need to issue another autoload, the existing one is enough
|
data/lib/im/version.rb
CHANGED