im 0.1.5 → 0.1.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 707475c4bc1ad6a6bf6207ca9f892a92b72a911f2fcb3cf0561e203041ede864
4
- data.tar.gz: c4ad0fc4bb0f0da2dc2b31d64ba904db9f8c3f3e87fb97def63dbbdc91cd3cf8
3
+ metadata.gz: 3ef66ecbb4745e878d911ec789567b204abe1bb174f57cee6b04ca6caddb76d9
4
+ data.tar.gz: a8cb56445189f2eb3d4fc4b7ff3b49c028b5b43cc7d8e20961481b125171d777
5
5
  SHA512:
6
- metadata.gz: 4bd14ecfb9804594795da0db412840cc5cb8a11500a335f66dbb88424575e04bfb6b4ead19480edcdf3f68fa957be0665a3c3a317c6c832a043fb645044bfa16
7
- data.tar.gz: '0048891c47b3f9bd6785141c71412c10f2ce63d746dbed8ac4e515b968e26dfe26a524ddbf8e9629eb2aa4b8fe11ef9c26ced56fa0ba6fa7d401185036e99aa8'
6
+ metadata.gz: f4fed0705aca8dfd1eb036ea78c5e5a71f64837134669937a31c04daf97224744d6c881363a688adaf61fa01322c0b462c1d6fa57ac5bf53b2eee72deb633634
7
+ data.tar.gz: a3e0d1b7e940c0afd22d4415d855964b73a043390fd6538f075affe1eb29964c5b7c3b4cf675a738a6b999ab73cba72ce2ec86af790797866ff97ee685979fb5
data/CHANGELOG.md CHANGED
@@ -1,11 +1,14 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.1.6] - 2022-10-03
4
+ - Remove `Object.const_missing` patch (Ruby patch now handles dynamic toplevel
5
+ references)
6
+
3
7
  ## [0.1.5] - 2022-09-22
4
8
  - Rename Im::Dependency -> Im::Require
5
9
  - Handle dynamic requires (require called from method body after file has been imported)
6
10
  - Refactor: move require/autoload patch logic to Im handler methods
7
11
 
8
-
9
12
  ## [0.1.4] - 2022-09-19
10
13
  - Correctly assign constants imported via recursive requires
11
14
 
data/Gemfile CHANGED
@@ -6,5 +6,3 @@ source "https://rubygems.org"
6
6
  gemspec
7
7
 
8
8
  gem "rspec", "~> 3.0"
9
- gem "rails"
10
- gem "sqlite3"
data/Gemfile.lock CHANGED
@@ -1,144 +1,12 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- im (0.1.4)
4
+ im (0.1.6)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- actioncable (7.0.4)
10
- actionpack (= 7.0.4)
11
- activesupport (= 7.0.4)
12
- nio4r (~> 2.0)
13
- websocket-driver (>= 0.6.1)
14
- actionmailbox (7.0.4)
15
- actionpack (= 7.0.4)
16
- activejob (= 7.0.4)
17
- activerecord (= 7.0.4)
18
- activestorage (= 7.0.4)
19
- activesupport (= 7.0.4)
20
- mail (>= 2.7.1)
21
- net-imap
22
- net-pop
23
- net-smtp
24
- actionmailer (7.0.4)
25
- actionpack (= 7.0.4)
26
- actionview (= 7.0.4)
27
- activejob (= 7.0.4)
28
- activesupport (= 7.0.4)
29
- mail (~> 2.5, >= 2.5.4)
30
- net-imap
31
- net-pop
32
- net-smtp
33
- rails-dom-testing (~> 2.0)
34
- actionpack (7.0.4)
35
- actionview (= 7.0.4)
36
- activesupport (= 7.0.4)
37
- rack (~> 2.0, >= 2.2.0)
38
- rack-test (>= 0.6.3)
39
- rails-dom-testing (~> 2.0)
40
- rails-html-sanitizer (~> 1.0, >= 1.2.0)
41
- actiontext (7.0.4)
42
- actionpack (= 7.0.4)
43
- activerecord (= 7.0.4)
44
- activestorage (= 7.0.4)
45
- activesupport (= 7.0.4)
46
- globalid (>= 0.6.0)
47
- nokogiri (>= 1.8.5)
48
- actionview (7.0.4)
49
- activesupport (= 7.0.4)
50
- builder (~> 3.1)
51
- erubi (~> 1.4)
52
- rails-dom-testing (~> 2.0)
53
- rails-html-sanitizer (~> 1.1, >= 1.2.0)
54
- activejob (7.0.4)
55
- activesupport (= 7.0.4)
56
- globalid (>= 0.3.6)
57
- activemodel (7.0.4)
58
- activesupport (= 7.0.4)
59
- activerecord (7.0.4)
60
- activemodel (= 7.0.4)
61
- activesupport (= 7.0.4)
62
- activestorage (7.0.4)
63
- actionpack (= 7.0.4)
64
- activejob (= 7.0.4)
65
- activerecord (= 7.0.4)
66
- activesupport (= 7.0.4)
67
- marcel (~> 1.0)
68
- mini_mime (>= 1.1.0)
69
- activesupport (7.0.4)
70
- concurrent-ruby (~> 1.0, >= 1.0.2)
71
- i18n (>= 1.6, < 2)
72
- minitest (>= 5.1)
73
- tzinfo (~> 2.0)
74
- builder (3.2.4)
75
- concurrent-ruby (1.1.10)
76
- crass (1.0.6)
77
9
  diff-lcs (1.5.0)
78
- digest (3.1.0)
79
- erubi (1.11.0)
80
- globalid (1.0.0)
81
- activesupport (>= 5.0)
82
- i18n (1.12.0)
83
- concurrent-ruby (~> 1.0)
84
- loofah (2.19.0)
85
- crass (~> 1.0.2)
86
- nokogiri (>= 1.5.9)
87
- mail (2.7.1)
88
- mini_mime (>= 0.1.1)
89
- marcel (1.0.2)
90
- method_source (1.0.0)
91
- mini_mime (1.1.2)
92
- mini_portile2 (2.8.0)
93
- minitest (5.16.3)
94
- net-imap (0.2.3)
95
- digest
96
- net-protocol
97
- strscan
98
- net-pop (0.1.1)
99
- digest
100
- net-protocol
101
- timeout
102
- net-protocol (0.1.3)
103
- timeout
104
- net-smtp (0.3.1)
105
- digest
106
- net-protocol
107
- timeout
108
- nio4r (2.5.8)
109
- nokogiri (1.13.8)
110
- mini_portile2 (~> 2.8.0)
111
- racc (~> 1.4)
112
- racc (1.6.0)
113
- rack (2.2.4)
114
- rack-test (2.0.2)
115
- rack (>= 1.3)
116
- rails (7.0.4)
117
- actioncable (= 7.0.4)
118
- actionmailbox (= 7.0.4)
119
- actionmailer (= 7.0.4)
120
- actionpack (= 7.0.4)
121
- actiontext (= 7.0.4)
122
- actionview (= 7.0.4)
123
- activejob (= 7.0.4)
124
- activemodel (= 7.0.4)
125
- activerecord (= 7.0.4)
126
- activestorage (= 7.0.4)
127
- activesupport (= 7.0.4)
128
- bundler (>= 1.15.0)
129
- railties (= 7.0.4)
130
- rails-dom-testing (2.0.3)
131
- activesupport (>= 4.2.0)
132
- nokogiri (>= 1.6)
133
- rails-html-sanitizer (1.4.3)
134
- loofah (~> 2.3)
135
- railties (7.0.4)
136
- actionpack (= 7.0.4)
137
- activesupport (= 7.0.4)
138
- method_source
139
- rake (>= 12.2)
140
- thor (~> 1.0)
141
- zeitwerk (~> 2.5)
142
10
  rake (13.0.6)
143
11
  rake-compiler (1.2.0)
144
12
  rake
@@ -155,28 +23,15 @@ GEM
155
23
  diff-lcs (>= 1.2.0, < 2.0)
156
24
  rspec-support (~> 3.11.0)
157
25
  rspec-support (3.11.0)
158
- sqlite3 (1.5.0)
159
- mini_portile2 (~> 2.8.0)
160
- strscan (3.0.4)
161
- thor (1.2.1)
162
- timeout (0.3.0)
163
- tzinfo (2.0.5)
164
- concurrent-ruby (~> 1.0)
165
- websocket-driver (0.7.5)
166
- websocket-extensions (>= 0.1.0)
167
- websocket-extensions (0.1.5)
168
- zeitwerk (2.6.0)
169
26
 
170
27
  PLATFORMS
171
28
  x86_64-linux
172
29
 
173
30
  DEPENDENCIES
174
31
  im!
175
- rails
176
32
  rake (~> 13.0)
177
33
  rake-compiler
178
34
  rspec (~> 3.0)
179
- sqlite3
180
35
 
181
36
  BUNDLED WITH
182
- 2.4.0.dev
37
+ 2.3.18
data/README.md CHANGED
@@ -24,8 +24,8 @@ require "im"
24
24
 
25
25
  extend Im
26
26
 
27
- mod = import "activemodel"
28
- #=> #<Im::Import:0x00007f2d34dfd0c8 root: active_model>
27
+ mod = import "active_model"
28
+ #=> <#Im::Import root: active_model>
29
29
  ```
30
30
 
31
31
  Constants in the imported files are under the returned module, not the root namespace:
data/lib/im/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Im
4
- VERSION = "0.1.5"
4
+ VERSION = "0.1.6"
5
5
  end
data/lib/im.rb CHANGED
@@ -1,35 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Im
4
- load $LOAD_PATH.resolve_feature_path("im/ruby_version_check")[1], true
4
+ load $:.resolve_feature_path("im/ruby_version_check")[1], true
5
5
 
6
- @constants = Object.constants.reject { |c| Kernel.autoload?(c) }.dup
6
+ @toplevel_constants = Object.constants.reject { |c| Object.autoload?(c) }
7
7
  @autoloads = {}
8
8
  @registry = {}
9
+ @current_imports = []
9
10
 
10
11
  require "im/version"
11
12
  require "im/kernel"
12
13
 
13
14
  class << self
14
- attr_reader :current_import, :registry, :autoloads, :constants
15
+ attr_reader :current_imports, :registry, :autoloads, :toplevel_constants
15
16
 
16
17
  def with_import(import)
17
- original_import = current_import
18
- @current_import = import || Im.current_import
18
+ @current_imports.push(import || current_import)
19
19
 
20
20
  unless tracer_originally_enabled = @tracer.enabled?
21
21
  @tracer.enable
22
22
  end
23
23
 
24
- yield(import)
25
-
24
+ yield
26
25
  ensure
27
- @current_import = original_import
26
+ @current_imports.pop
28
27
  @tracer.disable unless tracer_originally_enabled
29
28
  end
30
29
 
30
+ def current_import
31
+ current_imports.last
32
+ end
33
+
31
34
  def importing?
32
- !!Im.current_import
35
+ !!current_import
33
36
  end
34
37
 
35
38
  def handle_require(path, caller_path)
@@ -38,7 +41,7 @@ module Im
38
41
  return yield unless resolved_path
39
42
 
40
43
  if autoloaded = autoloads.delete(resolved_path)
41
- return with_import(autoloaded) do |_import|
44
+ return with_import(autoloaded) do
42
45
  !!import(path)
43
46
  end
44
47
  end
@@ -46,7 +49,7 @@ module Im
46
49
  if importing?
47
50
  registry[resolved_path] ||= Require.new(resolved_path, current_import)
48
51
  elsif registry.key?(caller_path)
49
- return with_import(registry[caller_path].import) do |_import|
52
+ return with_import(registry[caller_path].import) do
50
53
  !!import(resolved_path)
51
54
  end
52
55
  end
@@ -58,37 +61,43 @@ module Im
58
61
  registry[caller_path].requires << required
59
62
  end
60
63
 
61
- required.requires.each { |r| require r.path }
62
- import = current_import || Object
64
+ imports = importing? ? current_imports : [Object]
65
+ import_constants(required, imports)
66
+ end
63
67
 
64
- required.modules.each do |m|
65
- name = m.name
68
+ loaded
69
+ end
66
70
 
71
+ def handle_autoload(path)
72
+ if importing? && (resolved_path = resolve_path(path))
73
+ autoloads[resolved_path] = current_import
74
+ end
75
+ yield
76
+ end
77
+
78
+ def resolve_path(path)
79
+ (resolved = $:.resolve_feature_path(path)) && resolved[1]
80
+ end
81
+
82
+ def import_constants(required, imports)
83
+ return if imports.empty? || required.nil?
84
+
85
+ required.requires.each { |r| require r.path }
86
+
87
+ imports.each do |import|
88
+ required.defined_constants.each do |name, mod|
67
89
  # Do not assign constants that are aliased to root namespace
68
- root = name.split("::", 2)[0]
90
+ root = name.to_s.split("::", 2)[0]
69
91
  next if Object.const_defined?(root) &&
70
92
  import.const_defined?(root, false) &&
71
93
  Object.const_get(root) == import.const_get(root)
72
94
 
73
95
  begin
74
- import.const_set(name, m) unless import.const_defined?(name, false)
96
+ import.const_set(name, mod) unless import.const_defined?(name, false)
75
97
  rescue NameError
76
98
  end
77
99
  end
78
100
  end
79
-
80
- loaded
81
- end
82
-
83
- def handle_autoload(path)
84
- if resolved_path = resolve_path(path)
85
- Im.autoloads[resolved_path] = Im.current_import
86
- end
87
- yield
88
- end
89
-
90
- def resolve_path(path)
91
- (resolved = $LOAD_PATH.resolve_feature_path(path)) && resolved[1]
92
101
  end
93
102
  end
94
103
 
@@ -97,7 +106,7 @@ module Im
97
106
  @root = root
98
107
  super()
99
108
  Im.with_import(self) do
100
- Im.constants.each do |const|
109
+ Im.toplevel_constants.each do |const|
101
110
  self.const_set(const, Object.const_get(const))
102
111
  end
103
112
  end
@@ -106,23 +115,31 @@ module Im
106
115
  def inspect
107
116
  @inspect ||= "<#Im::Import root: #{@root}>"
108
117
  end
118
+
119
+ def const_added(name)
120
+ path = const_source_location(name)[0]
121
+ value = const_get(name, false)
122
+ Im.registry[path] ||= Require.new(path, self)
123
+ Im.registry[path].defined_constants[name] ||= value
124
+ super
125
+ end
109
126
  end
110
127
 
111
- Require = Struct.new(:path, :import, :modules, :requires) do
112
- def initialize(path, import, modules = [], requires = [])
113
- super(path, import, modules, requires)
128
+ Require = Struct.new(:path, :import, :defined_constants, :requires) do
129
+ def initialize(path, import, defined_constants = {}, requires = [])
130
+ super
114
131
  end
115
132
  end
116
133
 
117
134
  def import(path)
118
- if resolved = $LOAD_PATH.resolve_feature_path(path)
135
+ if resolved = $:.resolve_feature_path(path)
119
136
  resolved_path = resolved[1]
120
137
  raise LoadError, "import can only import ruby files" unless resolved[0] == :rb
121
138
  else
122
139
  raise LoadError, "cannot load such file -- #{path}"
123
140
  end
124
141
 
125
- Im.registry.fetch(resolved_path) do
142
+ required = Im.registry.fetch(resolved_path) do
126
143
  # handle autoload within import
127
144
  return nil if $LOADED_FEATURES.include?(resolved_path)
128
145
 
@@ -134,41 +151,39 @@ module Im
134
151
  load resolved_path, import
135
152
  end
136
153
  end
137
- end&.import
138
- end
139
-
140
- # This is a hack to catch references to top-level constants (`::Foo`) and, if
141
- # the calling line is a key in the Im registry, replace the toplevel constant
142
- # reference with its corresponding constant under the import namespace.
143
- #
144
- # By doing this, a reference to `::Foo` in an imported file will resolve to
145
- # `mod::Foo`, where `mod` is the import module. Ideally this should
146
- # ultimately happen at the Ruby implementation level.
147
- module RootNamespaceRedirect
148
- def const_missing(name)
149
-
150
- # Take top five locations to allow for other `const_missing` overrides
151
- # in the backtrace. If there are more than five, then this will no longer
152
- # work. This is currently very inefficient.
153
- if location = caller_locations(1, 5).find { |l| Im.registry.key?(l.path) }
154
- Im.registry[location.path].import.const_get(name)
155
- else
156
- super
157
- end
158
154
  end
155
+
156
+ Im.import_constants(required, Im.current_imports)
157
+
158
+ required&.import
159
159
  end
160
160
 
161
161
  @tracer = TracePoint.new(:class) do |event|
162
- next unless (name = event.self.name)
163
- next if Im.constants.include?(name.to_sym)
164
-
165
- if resolved = $LOAD_PATH.resolve_feature_path(event.path)
162
+ next unless (name = event.self.name&.to_sym)
163
+ next if Im.toplevel_constants.include?(name)
164
+
165
+ # We don't want to track classes defined under singleton classes, like
166
+ # this:
167
+ #
168
+ # class Foo
169
+ # class << self
170
+ # class Bar
171
+ # end
172
+ # end
173
+ # end
174
+ #
175
+ # Here, `class Bar` will trigger a TracePoint event, and because of the
176
+ # Ruby patch `name` will return "Bar", but this is not actually a class we
177
+ # need to alias in imports, so we can safely skip it. The only way I've
178
+ # found to do that though is to evaluate `Module.nesting` from the event's
179
+ # binding. This is weird, but it works!
180
+ #
181
+ next if event.binding.eval("Module.nesting").any?(&:singleton_class?)
182
+
183
+ if resolved = $:.resolve_feature_path(event.path)
166
184
  resolved_path = resolved[1]
167
- if Im.registry.key?(resolved_path)
168
- (Im.registry[resolved_path].modules << event.self).uniq!
169
- else
170
- Im.registry[resolved_path] = Require.new(resolved_path, Im.current_import, [event.self])
171
- end
185
+ Im.registry[resolved_path] ||= Require.new(resolved_path, Im.current_import)
186
+ Im.registry[resolved_path].defined_constants[name] = event.self
172
187
  end
173
188
  end
174
189
 
@@ -176,5 +191,3 @@ module Im
176
191
 
177
192
  extend self
178
193
  end
179
-
180
- Object.extend Im::RootNamespaceRedirect
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: im
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Salzberg
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-09-22 00:00:00.000000000 Z
11
+ date: 2022-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -94,7 +94,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
94
  - !ruby/object:Gem::Version
95
95
  version: '0'
96
96
  requirements: []
97
- rubygems_version: 3.4.0.dev
97
+ rubygems_version: 3.3.7
98
98
  signing_key:
99
99
  specification_version: 4
100
100
  summary: Module import system.