im 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
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.