main_like_module 0.2.0 → 0.3.0
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/HISTORY.md +15 -0
- data/README.md +46 -7
- data/lib/main_like_module/import.rb +61 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1b20df879329c7be3e7e04d3eac2206590db083cd1003c227dd4bded56c29fe8
|
|
4
|
+
data.tar.gz: 63897091aa9d8e8f9d7860529e1eeb4e42594f70ca3db5208298dbd322b455cd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 46e8a794dd5815f037f91159a62bb7d8a3a9f4ff68569831a416bc1dbbb54ed03f5547d16765a898acc30f4a984edc75f86c3858cc164cc903db841b2a2ac86f
|
|
7
|
+
data.tar.gz: 0eb79799a209e4798e2a6fa2ed8688183a43cfbf4460fe45a7014409e3daa3b761c516d3b8ae0287832c5c32cf6be175215c99ffefc9444b126c048251157b0d
|
data/HISTORY.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# RELEASE HISTORY
|
|
2
2
|
|
|
3
|
+
## 0.3.0 / 2026-04-08
|
|
4
|
+
|
|
5
|
+
Fold in the `import`/`import_relative` feature from rubyworks/finder.
|
|
6
|
+
|
|
7
|
+
Changes:
|
|
8
|
+
|
|
9
|
+
* Add `Kernel#import` and `Kernel#import_relative` (require
|
|
10
|
+
`'main_like_module/import'`) as scope-aware alternatives to `require`
|
|
11
|
+
and `require_relative`. They evaluate the loaded script into the
|
|
12
|
+
current scope rather than into the toplevel, providing a partial
|
|
13
|
+
workaround for Problem 1 (toplevel pollution of Object).
|
|
14
|
+
* Update README to document the new feature and explain how the two
|
|
15
|
+
pieces of the library address Ruby's two toplevel design quirks.
|
|
16
|
+
|
|
17
|
+
|
|
3
18
|
## 0.2.0 / 2026-04-07
|
|
4
19
|
|
|
5
20
|
Maintenance release modernizing the project.
|
data/README.md
CHANGED
|
@@ -87,11 +87,14 @@ not a hand-picked subset.
|
|
|
87
87
|
|
|
88
88
|
## What This Library Does
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
This library addresses both problems, though only one of them fully.
|
|
91
|
+
|
|
92
|
+
### Completing the Toplevel Proxy (Problem 2)
|
|
93
|
+
|
|
94
|
+
```ruby
|
|
95
|
+
require 'main_like_module'
|
|
96
|
+
```
|
|
93
97
|
|
|
94
|
-
The second problem *can* be addressed, and that is what this library does.
|
|
95
98
|
On `require`, it walks `Module`'s instance methods and, for each one not
|
|
96
99
|
already available at the toplevel, defines a singleton method on `main`
|
|
97
100
|
that forwards the call to `Object.class_eval`. The result is that anything
|
|
@@ -108,9 +111,45 @@ you can do inside a `module` body, you can now do at the toplevel as well.
|
|
|
108
111
|
Public, private, and protected `Module` methods are all proxied with their
|
|
109
112
|
correct visibility.
|
|
110
113
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
+
### A Partial Workaround for Toplevel Pollution (Problem 1)
|
|
115
|
+
|
|
116
|
+
```ruby
|
|
117
|
+
require 'main_like_module/import'
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
The parser-level pollution of `Object` cannot be fixed from userland —
|
|
121
|
+
that ship sailed when the Ruby grammar was written. But for code you
|
|
122
|
+
*write yourself*, this library provides `Kernel#import` and
|
|
123
|
+
`Kernel#import_relative` as scope-aware alternatives to `require` and
|
|
124
|
+
`require_relative`. They evaluate the loaded script directly into the
|
|
125
|
+
*current scope* rather than into the toplevel:
|
|
126
|
+
|
|
127
|
+
```ruby
|
|
128
|
+
require 'main_like_module/import'
|
|
129
|
+
|
|
130
|
+
module MyApp
|
|
131
|
+
import 'helpers' # helpers.rb is evaluated into MyApp,
|
|
132
|
+
# not into Object
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
MyApp.some_helper_method #=> works
|
|
136
|
+
Object.private_instance_methods.include?(:some_helper_method)
|
|
137
|
+
#=> false -- Object stays clean
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
`import` searches `$LOAD_PATH` the way `require` does. `import_relative`
|
|
141
|
+
resolves its argument relative to the calling file the way
|
|
142
|
+
`require_relative` does. Both raise `LoadError` on miss.
|
|
143
|
+
|
|
144
|
+
This is a *partial* workaround. It only helps for code that uses `import`
|
|
145
|
+
explicitly — toplevel code in scripts you don't control still pollutes
|
|
146
|
+
`Object`. But for organizing your own libraries into clean module
|
|
147
|
+
namespaces without ceremony, it is genuinely useful.
|
|
148
|
+
|
|
149
|
+
`import` was originally part of the `rubyworks/finder` gem, which has
|
|
150
|
+
been folded into `main_like_module` because the two libraries are really
|
|
151
|
+
about the same thing: making Ruby's toplevel/module loading semantics
|
|
152
|
+
behave more sensibly.
|
|
114
153
|
|
|
115
154
|
|
|
116
155
|
## Should You Use This?
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Kernel#import and Kernel#import_relative are variants of #require and
|
|
2
|
+
# #require_relative that evaluate the loaded script *into the current scope*
|
|
3
|
+
# instead of into the toplevel. This provides a partial workaround for the
|
|
4
|
+
# fact that toplevel definitions in Ruby pollute Object globally.
|
|
5
|
+
#
|
|
6
|
+
# module MyApp
|
|
7
|
+
# import 'somefile' # somefile's contents are loaded into MyApp,
|
|
8
|
+
# # not into Object
|
|
9
|
+
# end
|
|
10
|
+
#
|
|
11
|
+
# Originally extracted from rubyworks/finder.
|
|
12
|
+
|
|
13
|
+
module Kernel
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
# Find +feature+ in $LOAD_PATH and evaluate it into the current scope.
|
|
18
|
+
#
|
|
19
|
+
# Unlike #require, definitions in the loaded file are added to whatever
|
|
20
|
+
# scope #import was called from rather than to Object.
|
|
21
|
+
def import(feature)
|
|
22
|
+
file = nil
|
|
23
|
+
if File.file?(feature) && File.absolute_path(feature) == feature
|
|
24
|
+
file = feature
|
|
25
|
+
else
|
|
26
|
+
candidates = feature.end_with?('.rb') ? [feature] : ["#{feature}.rb", feature]
|
|
27
|
+
$LOAD_PATH.each do |dir|
|
|
28
|
+
candidates.each do |c|
|
|
29
|
+
path = File.expand_path(c, dir)
|
|
30
|
+
if File.file?(path)
|
|
31
|
+
file = path
|
|
32
|
+
break
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
break if file
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
raise LoadError, "no such file to import -- #{feature}" unless file
|
|
39
|
+
instance_eval(::File.read(file), file)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Like #import, but resolves +fname+ relative to the file that called
|
|
43
|
+
# #import_relative (mirroring how #require_relative works).
|
|
44
|
+
def import_relative(fname)
|
|
45
|
+
call = caller.first
|
|
46
|
+
fail "Can't parse #{call}" unless call.rindex(/:\d+(:in [`'].*[`'])?$/)
|
|
47
|
+
path = $`
|
|
48
|
+
if /\A\((.*)\)/ =~ path # eval, etc.
|
|
49
|
+
raise LoadError, "import_relative is called in #{$1}"
|
|
50
|
+
end
|
|
51
|
+
base = File.expand_path(fname, File.dirname(path))
|
|
52
|
+
file = if File.file?(base)
|
|
53
|
+
base
|
|
54
|
+
elsif File.file?("#{base}.rb")
|
|
55
|
+
"#{base}.rb"
|
|
56
|
+
end
|
|
57
|
+
raise LoadError, "no such file to import -- #{base}" unless file
|
|
58
|
+
instance_eval(::File.read(file), file)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: main_like_module
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Trans
|
|
@@ -49,6 +49,7 @@ files:
|
|
|
49
49
|
- LICENSE.txt
|
|
50
50
|
- README.md
|
|
51
51
|
- lib/main_like_module.rb
|
|
52
|
+
- lib/main_like_module/import.rb
|
|
52
53
|
homepage: https://github.com/rubyworks/main_like_module
|
|
53
54
|
licenses:
|
|
54
55
|
- BSD-2-Clause
|