im 0.1.3 → 0.1.5

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: 3f60f56fa26101e6aeec8d3a9123f1ce8196a60ff559931ec91418316cef13e2
4
- data.tar.gz: 445bf0961717077dd35e5ab900b1ab235b25a834a0b1123ed6936c2770439872
3
+ metadata.gz: 707475c4bc1ad6a6bf6207ca9f892a92b72a911f2fcb3cf0561e203041ede864
4
+ data.tar.gz: c4ad0fc4bb0f0da2dc2b31d64ba904db9f8c3f3e87fb97def63dbbdc91cd3cf8
5
5
  SHA512:
6
- metadata.gz: d0c2063a12bc66f6e86565a27d1e58e2079a88466a61c42a9830fbb0705864ee33f1c780f367dbe61e55b1e21a741cd6c05fc2e4cb7c50ee2bca1625096898c1
7
- data.tar.gz: 4ba1c608ba252e26625ddd136fcaddb3ac8b9f6a5f79db80796ce82ebd8b96da1560b946c79d31a8e658c1fbe5e727d6e68c793dd6a8944e6ceb60b62dd01182
6
+ metadata.gz: 4bd14ecfb9804594795da0db412840cc5cb8a11500a335f66dbb88424575e04bfb6b4ead19480edcdf3f68fa957be0665a3c3a317c6c832a043fb645044bfa16
7
+ data.tar.gz: '0048891c47b3f9bd6785141c71412c10f2ce63d746dbed8ac4e515b968e26dfe26a524ddbf8e9629eb2aa4b8fe11ef9c26ced56fa0ba6fa7d401185036e99aa8'
data/CHANGELOG.md CHANGED
@@ -1,6 +1,15 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.1.2] - 2022-09-16
3
+ ## [0.1.5] - 2022-09-22
4
+ - Rename Im::Dependency -> Im::Require
5
+ - Handle dynamic requires (require called from method body after file has been imported)
6
+ - Refactor: move require/autoload patch logic to Im handler methods
7
+
8
+
9
+ ## [0.1.4] - 2022-09-19
10
+ - Correctly assign constants imported via recursive requires
11
+
12
+ ## [0.1.3] - 2022-09-16
4
13
  - Fix gemspec
5
14
 
6
15
  ## [0.1.1] - 2022-09-16
data/Gemfile CHANGED
@@ -6,3 +6,5 @@ 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,12 +1,144 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- im (0.1.2)
4
+ im (0.1.4)
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)
9
77
  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)
10
142
  rake (13.0.6)
11
143
  rake-compiler (1.2.0)
12
144
  rake
@@ -23,15 +155,28 @@ GEM
23
155
  diff-lcs (>= 1.2.0, < 2.0)
24
156
  rspec-support (~> 3.11.0)
25
157
  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)
26
169
 
27
170
  PLATFORMS
28
171
  x86_64-linux
29
172
 
30
173
  DEPENDENCIES
31
174
  im!
175
+ rails
32
176
  rake (~> 13.0)
33
177
  rake-compiler
34
178
  rspec (~> 3.0)
179
+ sqlite3
35
180
 
36
181
  BUNDLED WITH
37
182
  2.4.0.dev
data/lib/im/kernel.rb CHANGED
@@ -4,35 +4,16 @@ module Kernel
4
4
  alias_method :im_original_require, :require
5
5
 
6
6
  def require(path)
7
- if Im.autoloads.key?(path)
8
- return Im.with_context(Im.autoloads.delete(path)) do |_context|
9
- !!Im.import(path)
10
- end
7
+ Im.handle_require(path, caller_locations(1, 1).first.path) do
8
+ im_original_require(path)
11
9
  end
10
+ end
12
11
 
13
- loaded = im_original_require(path)
14
- return loaded unless Im.current_import
15
-
16
- if resolved = $LOAD_PATH.resolve_feature_path(path)
17
- if Im.registry.key?(resolved_path = resolved[1])
18
- _, modules = Im.registry[resolved_path]
19
-
20
- modules.each do |m|
21
- next unless name = m.name
22
-
23
- # Do not assign constants that are aliased to root namespace
24
- root = name.split("::", 2)[0]
25
- next if Object.const_defined?(root) &&
26
- Im.current_import.const_defined?(root, false) &&
27
- Object.const_get(root) == Im.current_import.const_get(root)
12
+ alias_method :im_original_autoload, :autoload
28
13
 
29
- Im.current_import.const_set(name, m) unless Im.current_import.const_defined?(name, false)
30
- end
31
- else
32
- Im.registry[resolved_path] ||= [Im.current_import, []] if Im.current_import
33
- end
14
+ def autoload(name, path)
15
+ Im.handle_autoload(path) do
16
+ im_original_autoload(name, path)
34
17
  end
35
-
36
- return loaded
37
18
  end
38
19
  end
data/lib/im/module.rb CHANGED
@@ -2,7 +2,8 @@ class Module
2
2
  alias_method :im_original_autoload, :autoload
3
3
 
4
4
  def autoload(name, path)
5
- Im.autoloads[path] = Im.current_import if Im.current_import
6
- im_original_autoload(name, path)
5
+ Im.handle_autoload(path) do
6
+ im_original_autoload(name, path)
7
+ end
7
8
  end
8
9
  end
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.3"
4
+ VERSION = "0.1.5"
5
5
  end
data/lib/im.rb CHANGED
@@ -2,27 +2,93 @@
2
2
 
3
3
  module Im
4
4
  load $LOAD_PATH.resolve_feature_path("im/ruby_version_check")[1], true
5
+
6
+ @constants = Object.constants.reject { |c| Kernel.autoload?(c) }.dup
7
+ @autoloads = {}
8
+ @registry = {}
9
+
5
10
  require "im/version"
6
11
  require "im/kernel"
7
12
 
8
13
  class << self
9
- attr_reader :current_import
10
- attr_reader :tracer
14
+ attr_reader :current_import, :registry, :autoloads, :constants
15
+
16
+ def with_import(import)
17
+ original_import = current_import
18
+ @current_import = import || Im.current_import
19
+
20
+ unless tracer_originally_enabled = @tracer.enabled?
21
+ @tracer.enable
22
+ end
23
+
24
+ yield(import)
11
25
 
12
- def with_context(context)
13
- original_context = current_import
14
- @current_import = context
15
- yield(context)
16
26
  ensure
17
- @current_import = original_context
27
+ @current_import = original_import
28
+ @tracer.disable unless tracer_originally_enabled
18
29
  end
19
30
 
20
- def registry
21
- @registry ||= {}
31
+ def importing?
32
+ !!Im.current_import
22
33
  end
23
34
 
24
- def autoloads
25
- @autoloads ||= {}
35
+ def handle_require(path, caller_path)
36
+ resolved_path = resolve_path(path)
37
+
38
+ return yield unless resolved_path
39
+
40
+ if autoloaded = autoloads.delete(resolved_path)
41
+ return with_import(autoloaded) do |_import|
42
+ !!import(path)
43
+ end
44
+ end
45
+
46
+ if importing?
47
+ registry[resolved_path] ||= Require.new(resolved_path, current_import)
48
+ elsif registry.key?(caller_path)
49
+ return with_import(registry[caller_path].import) do |_import|
50
+ !!import(resolved_path)
51
+ end
52
+ end
53
+
54
+ loaded = yield # super
55
+
56
+ if required = registry[resolved_path]
57
+ if loaded && registry.key?(caller_path)
58
+ registry[caller_path].requires << required
59
+ end
60
+
61
+ required.requires.each { |r| require r.path }
62
+ import = current_import || Object
63
+
64
+ required.modules.each do |m|
65
+ name = m.name
66
+
67
+ # Do not assign constants that are aliased to root namespace
68
+ root = name.split("::", 2)[0]
69
+ next if Object.const_defined?(root) &&
70
+ import.const_defined?(root, false) &&
71
+ Object.const_get(root) == import.const_get(root)
72
+
73
+ begin
74
+ import.const_set(name, m) unless import.const_defined?(name, false)
75
+ rescue NameError
76
+ end
77
+ end
78
+ 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]
26
92
  end
27
93
  end
28
94
 
@@ -30,8 +96,10 @@ module Im
30
96
  def initialize(root)
31
97
  @root = root
32
98
  super()
33
- Im::CONSTANTS.each do |const|
34
- self.const_set(const, Object.const_get(const))
99
+ Im.with_import(self) do
100
+ Im.constants.each do |const|
101
+ self.const_set(const, Object.const_get(const))
102
+ end
35
103
  end
36
104
  end
37
105
 
@@ -40,6 +108,12 @@ module Im
40
108
  end
41
109
  end
42
110
 
111
+ Require = Struct.new(:path, :import, :modules, :requires) do
112
+ def initialize(path, import, modules = [], requires = [])
113
+ super(path, import, modules, requires)
114
+ end
115
+ end
116
+
43
117
  def import(path)
44
118
  if resolved = $LOAD_PATH.resolve_feature_path(path)
45
119
  resolved_path = resolved[1]
@@ -54,23 +128,30 @@ module Im
54
128
 
55
129
  $LOADED_FEATURES << resolved_path
56
130
 
57
- context = Im.current_import || Import.new(path)
58
-
59
- Im.with_context(context) do
60
- originally_enabled = Im.tracer.enabled?
61
- Im.tracer.enable
62
- load resolved_path, context
63
- Im.tracer.disable unless originally_enabled
131
+ import = Im.current_import || Import.new(path)
132
+ (Im.registry[resolved_path] ||= Require.new(resolved_path, import)).tap do
133
+ Im.with_import(import) do
134
+ load resolved_path, import
135
+ end
64
136
  end
65
-
66
- Im.registry[resolved_path] ||= [context, []]
67
- end[0]
137
+ end&.import
68
138
  end
69
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.
70
147
  module RootNamespaceRedirect
71
148
  def const_missing(name)
72
- if Im.current_import && Im.current_import.const_defined?(name)
73
- Im.current_import.const_get(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)
74
155
  else
75
156
  super
76
157
  end
@@ -78,19 +159,20 @@ module Im
78
159
  end
79
160
 
80
161
  @tracer = TracePoint.new(:class) do |event|
162
+ next unless (name = event.self.name)
163
+ next if Im.constants.include?(name.to_sym)
164
+
81
165
  if resolved = $LOAD_PATH.resolve_feature_path(event.path)
82
166
  resolved_path = resolved[1]
83
167
  if Im.registry.key?(resolved_path)
84
- (Im.registry[resolved_path][1] << event.self).uniq!
168
+ (Im.registry[resolved_path].modules << event.self).uniq!
85
169
  else
86
- Im.registry[resolved_path] = [Im.current_import, [event.self]]
170
+ Im.registry[resolved_path] = Require.new(resolved_path, Im.current_import, [event.self])
87
171
  end
88
172
  end
89
173
  end
90
174
 
91
175
  require "im/module"
92
- require "im/autoload"
93
- require "im/constants"
94
176
 
95
177
  extend self
96
178
  end
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.3
4
+ version: 0.1.5
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-16 00:00:00.000000000 Z
11
+ date: 2022-09-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -66,8 +66,6 @@ files:
66
66
  - README.md
67
67
  - Rakefile
68
68
  - lib/im.rb
69
- - lib/im/autoload.rb
70
- - lib/im/constants.rb
71
69
  - lib/im/kernel.rb
72
70
  - lib/im/module.rb
73
71
  - lib/im/ruby_version_check.rb
data/lib/im/autoload.rb DELETED
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Im
4
- module Autoload
5
- def autoload(name, path)
6
- Im.autoloads[path] = Im.current_import if Im.current_import
7
- super(name, path)
8
- end
9
- end
10
- end
data/lib/im/constants.rb DELETED
@@ -1,103 +0,0 @@
1
- module Im
2
- # It's faster to just hard-code constants than to introspect them at runtime
3
- CONSTANTS = [
4
- :ArgumentError,
5
- :Array,
6
- :BasicObject,
7
- :Binding,
8
- :Class,
9
- :ClosedQueueError,
10
- :Comparable,
11
- :Complex,
12
- :ConditionVariable,
13
- :DidYouMean,
14
- :Dir,
15
- :Encoding,
16
- :EncodingError,
17
- :Enumerable,
18
- :Enumerator,
19
- :EOFError,
20
- :Errno,
21
- :ErrorHighlight,
22
- :Exception,
23
- :FalseClass,
24
- :Fiber,
25
- :FiberError,
26
- :File,
27
- :FileTest,
28
- :Float,
29
- :FloatDomainError,
30
- :FrozenError,
31
- :GC,
32
- :Gem,
33
- :Hash,
34
- :IndexError,
35
- :Integer,
36
- :Interrupt,
37
- :IO,
38
- :IOError,
39
- :Kernel,
40
- :KeyError,
41
- :LoadError,
42
- :LocalJumpError,
43
- :Marshal,
44
- :MatchData,
45
- :Math,
46
- :Method,
47
- :Module,
48
- :Monitor,
49
- :MonitorMixin,
50
- :Mutex,
51
- :NameError,
52
- :NilClass,
53
- :NoMatchingPatternError,
54
- :NoMatchingPatternKeyError,
55
- :NoMemoryError,
56
- :NoMethodError,
57
- :NotImplementedError,
58
- :Numeric,
59
- :Object,
60
- :ObjectSpace,
61
- :Proc,
62
- :Process,
63
- :Queue,
64
- :Ractor,
65
- :Random,
66
- :Range,
67
- :RangeError,
68
- :Rational,
69
- :RbConfig,
70
- :Refinement,
71
- :Regexp,
72
- :RegexpError,
73
- :RubyVM,
74
- :RuntimeError,
75
- :ScriptError,
76
- :SecurityError,
77
- :Set,
78
- :Signal,
79
- :SignalException,
80
- :SizedQueue,
81
- :StandardError,
82
- :StopIteration,
83
- :String,
84
- :Struct,
85
- :Symbol,
86
- :SyntaxError,
87
- :SystemCallError,
88
- :SystemExit,
89
- :SystemStackError,
90
- :Thread,
91
- :ThreadError,
92
- :ThreadGroup,
93
- :Time,
94
- :TracePoint,
95
- :TrueClass,
96
- :TypeError,
97
- :UnboundMethod,
98
- :UncaughtThrowError,
99
- :UnicodeNormalize,
100
- :Warning,
101
- :ZeroDivisionError,
102
- ]
103
- end