im 0.1.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Im::ModuleConstAdded
4
+ UNBOUND_METHOD_MODULE_NAME = Module.instance_method(:name)
5
+ private_constant :UNBOUND_METHOD_MODULE_NAME
6
+
7
+ # We patch Module#const_added to track every time a constant is added to a
8
+ # permanently-named module pointing to an Im-autoloaded constant. This is
9
+ # important because the moment that an Im-autoloaded constant is attached to
10
+ # a permanently named module, its name changes permanently. Although Im
11
+ # internally avoids the use of absolute cpaths, ExplicitNamespace must use
12
+ # them and thus we need to update its internal registry accordingly.
13
+ #
14
+ # @sig (Symbol) -> void
15
+ def const_added(const_name)
16
+ # If we are called from an autoload, no need to track.
17
+ return super if autoload?(const_name)
18
+
19
+ # Get the name of this module and only continue if it is a permanent name.
20
+ return unless cpath = Im.permanent_cpath(self)
21
+
22
+ # We know this is not an autoloaded constant, so it is safe to fetch the
23
+ # value. We fetch the value, get it's object_id, and check the registry to
24
+ # see if it is an Im-autoloaded module.
25
+ relative_cpath, loader, references = Im::Registry.autoloaded_modules[const_get(const_name).object_id]
26
+ return super unless loader
27
+
28
+ # Update the context for this const add. This is important for reloading so
29
+ # we can reset inbound references when the autoloaded module is unloaded.
30
+ references << [self, const_name]
31
+
32
+ # Update all absolute cpath references to this module by replacing all
33
+ # references to the original cpath with the new, permanently-named cpath.
34
+ #
35
+ # For example, if we had a module loader::Foo::Bar, and loader::Foo was
36
+ # assigned to Baz like this:
37
+ #
38
+ # Baz = loader::Foo
39
+ #
40
+ # then we must update cpaths from a string like
41
+ #
42
+ # "#<Im::Loader ...>::Foo::Bar"
43
+ #
44
+ # to
45
+ #
46
+ # "Baz::Bar"
47
+ #
48
+ # To do this, we take the loader's module_prefix ("#<Im::Loader ...>::"),
49
+ # append to it the relative cpath of the constant ("Foo") and replace that by the new
50
+ # name ("Baz"), roughly like this:
51
+ #
52
+ # "#<Im::Loader ...>::Foo::Bar".gsub(/^#{"#<Im::Loader ...>::Foo"}/, "Baz")
53
+ #
54
+ prefix = relative_cpath ? "#{loader.module_prefix}#{relative_cpath}" : loader.module_prefix.delete_suffix("::")
55
+ ::Im::ExplicitNamespace.__update_cpaths(prefix, "#{cpath}::#{const_name}")
56
+
57
+ super
58
+ rescue NameError
59
+ super
60
+ end
61
+ end
62
+
63
+ ::Module.prepend(Im::ModuleConstAdded)
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Im
4
+ module Registry # :nodoc: all
5
+ class << self
6
+ # Keeps track of all loaders. Useful to broadcast messages and to prevent
7
+ # them from being garbage collected.
8
+ #
9
+ # @private
10
+ # @sig Array[Im::Loader]
11
+ attr_reader :loaders
12
+
13
+ # Registers gem loaders to let `for_gem` be idempotent in case of reload.
14
+ #
15
+ # @private
16
+ # @sig Hash[String, Im::Loader]
17
+ attr_reader :gem_loaders_by_root_file
18
+
19
+ # Maps absolute paths to the loaders responsible for them.
20
+ #
21
+ # This information is used by our decorated `Kernel#require` to be able to
22
+ # invoke callbacks and autovivify modules.
23
+ #
24
+ # @private
25
+ # @sig Hash[String, Im::Loader]
26
+ attr_reader :autoloads
27
+
28
+ # @private
29
+ # @sig Hash[String, Im::Loader]
30
+ attr_reader :paths
31
+
32
+ # This hash table addresses an edge case in which an autoload is ignored.
33
+ #
34
+ # For example, let's suppose we want to autoload in a gem like this:
35
+ #
36
+ # # lib/my_gem.rb
37
+ # loader = Im::Loader.new
38
+ # loader.push_dir(__dir__)
39
+ # loader.setup
40
+ #
41
+ # module loader::MyGem
42
+ # end
43
+ #
44
+ # if you require "my_gem", as Bundler would do, this happens while setting
45
+ # up autoloads:
46
+ #
47
+ # 1. Object.autoload?(:MyGem) returns `nil` because the autoload for
48
+ # the constant is issued by Im while the same file is being
49
+ # required.
50
+ # 2. The constant `MyGem` is undefined while setup runs.
51
+ #
52
+ # Therefore, a directory `lib/my_gem` would autovivify a module according to
53
+ # the existing information. But that would be wrong.
54
+ #
55
+ # To overcome this fundamental limitation, we keep track of the constant
56
+ # paths that are in this situation ---in the example above, "MyGem"--- and
57
+ # take this collection into account for the autovivification logic.
58
+ #
59
+ # Note that you cannot generally address this by moving the setup code
60
+ # below the constant definition, because we want libraries to be able to
61
+ # use managed constants in the module body:
62
+ #
63
+ # module loader::MyGem
64
+ # include MyConcern
65
+ # end
66
+ #
67
+ # @private
68
+ # @sig Hash[String, [String, Im::Loader]]
69
+ attr_reader :inceptions
70
+
71
+ # @private
72
+ # @sig Hash[Integer, [Im::Loader, String, Array]]
73
+ attr_reader :autoloaded_modules
74
+
75
+ # Registers a loader.
76
+ #
77
+ # @private
78
+ # @sig (Im::Loader) -> void
79
+ def register_loader(loader)
80
+ loaders << loader
81
+ end
82
+
83
+ # @private
84
+ # @sig (Im::Loader) -> void
85
+ def unregister_loader(loader)
86
+ loaders.delete(loader)
87
+ gem_loaders_by_root_file.delete_if { |_, l| l == loader }
88
+ autoloads.delete_if { |_, l| l == loader }
89
+ paths.delete_if { |_, l| l == loader }
90
+ inceptions.delete_if { |_, (_, l)| l == loader }
91
+ autoloaded_modules.delete_if { |_, (_, l, _)| l == loader }
92
+ end
93
+
94
+ # This method returns always a loader, the same instance for the same root
95
+ # file. That is how Im::Loader.for_gem is idempotent.
96
+ #
97
+ # @private
98
+ # @sig (String) -> Im::Loader
99
+ def loader_for_gem(root_file, warn_on_extra_files:)
100
+ gem_loaders_by_root_file[root_file] ||= GemLoader._new(root_file, warn_on_extra_files: warn_on_extra_files)
101
+ end
102
+
103
+ # @private
104
+ # @sig (Im::Loader, String) -> String
105
+ def register_autoload(loader, abspath)
106
+ paths[abspath] = autoloads[abspath] = loader
107
+ end
108
+
109
+ # @private
110
+ # @sig (String) -> void
111
+ def unregister_autoload(abspath)
112
+ autoloads.delete(abspath)
113
+ end
114
+
115
+ # @private
116
+ # @sig (Im::Loader, String) -> String
117
+ def register_path(loader, abspath)
118
+ paths[abspath] = loader
119
+ end
120
+
121
+ # @private
122
+ # @sig (String) -> void
123
+ def unregister_path(abspath)
124
+ paths.delete(abspath)
125
+ end
126
+
127
+ # @private
128
+ # @sig (String, String, Im::Loader) -> void
129
+ def register_inception(cpath, abspath, loader)
130
+ inceptions[cpath] = [abspath, loader]
131
+ end
132
+
133
+ # @private
134
+ # @sig (String) -> String?
135
+ def inception?(cpath)
136
+ if pair = inceptions[cpath]
137
+ pair.first
138
+ end
139
+ end
140
+
141
+ def register_autoloaded_module(mod, module_name, loader)
142
+ autoloaded_modules[mod.object_id] = [module_name, loader, []]
143
+ end
144
+
145
+ # @private
146
+ # @sig (String) -> Im::Loader?
147
+ def loader_for(path)
148
+ paths[path]
149
+ end
150
+
151
+ # @private
152
+ # @sig (Im::Loader) -> void
153
+ def on_unload(loader)
154
+ autoloads.delete_if { |_path, object| object == loader }
155
+ inceptions.delete_if { |_cpath, (_path, object)| object == loader }
156
+ end
157
+ end
158
+
159
+ @loaders = []
160
+ @gem_loaders_by_root_file = {}
161
+ @autoloads = {}
162
+ @paths = {}
163
+ @inceptions = {}
164
+ @autoloaded_modules = {}
165
+ end
166
+ 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.6"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/im.rb CHANGED
@@ -1,193 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Im
4
- load $:.resolve_feature_path("im/ruby_version_check")[1], true
5
-
6
- @toplevel_constants = Object.constants.reject { |c| Object.autoload?(c) }
7
- @autoloads = {}
8
- @registry = {}
9
- @current_imports = []
10
-
11
- require "im/version"
12
- require "im/kernel"
13
-
14
- class << self
15
- attr_reader :current_imports, :registry, :autoloads, :toplevel_constants
16
-
17
- def with_import(import)
18
- @current_imports.push(import || current_import)
19
-
20
- unless tracer_originally_enabled = @tracer.enabled?
21
- @tracer.enable
22
- end
23
-
24
- yield
25
- ensure
26
- @current_imports.pop
27
- @tracer.disable unless tracer_originally_enabled
28
- end
29
-
30
- def current_import
31
- current_imports.last
32
- end
33
-
34
- def importing?
35
- !!current_import
36
- end
37
-
38
- def handle_require(path, caller_path)
39
- resolved_path = resolve_path(path)
40
-
41
- return yield unless resolved_path
42
-
43
- if autoloaded = autoloads.delete(resolved_path)
44
- return with_import(autoloaded) do
45
- !!import(path)
46
- end
47
- end
48
-
49
- if importing?
50
- registry[resolved_path] ||= Require.new(resolved_path, current_import)
51
- elsif registry.key?(caller_path)
52
- return with_import(registry[caller_path].import) do
53
- !!import(resolved_path)
54
- end
55
- end
56
-
57
- loaded = yield # super
58
-
59
- if required = registry[resolved_path]
60
- if loaded && registry.key?(caller_path)
61
- registry[caller_path].requires << required
62
- end
63
-
64
- imports = importing? ? current_imports : [Object]
65
- import_constants(required, imports)
66
- end
67
-
68
- loaded
69
- end
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|
89
- # Do not assign constants that are aliased to root namespace
90
- root = name.to_s.split("::", 2)[0]
91
- next if Object.const_defined?(root) &&
92
- import.const_defined?(root, false) &&
93
- Object.const_get(root) == import.const_get(root)
94
-
95
- begin
96
- import.const_set(name, mod) unless import.const_defined?(name, false)
97
- rescue NameError
98
- end
99
- end
100
- end
101
- end
102
- end
103
-
104
- class Import < Module
105
- def initialize(root)
106
- @root = root
107
- super()
108
- Im.with_import(self) do
109
- Im.toplevel_constants.each do |const|
110
- self.const_set(const, Object.const_get(const))
111
- end
112
- end
113
- end
114
-
115
- def inspect
116
- @inspect ||= "<#Im::Import root: #{@root}>"
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
126
- end
127
-
128
- Require = Struct.new(:path, :import, :defined_constants, :requires) do
129
- def initialize(path, import, defined_constants = {}, requires = [])
130
- super
131
- end
132
- end
133
-
4
+ require_relative "im/const_path"
5
+ require_relative "im/internal"
6
+ require_relative "im/loader"
7
+ require_relative "im/gem_loader"
8
+ require_relative "im/registry"
9
+ require_relative "im/explicit_namespace"
10
+ require_relative "im/module_const_added"
11
+ require_relative "im/inflector"
12
+ require_relative "im/gem_inflector"
13
+ require_relative "im/kernel"
14
+ require_relative "im/error"
15
+ require_relative "im/version"
16
+
17
+ extend Im::ConstPath
18
+
19
+ # @sig (String) -> Im::Loader?
134
20
  def import(path)
135
- if resolved = $:.resolve_feature_path(path)
136
- resolved_path = resolved[1]
137
- raise LoadError, "import can only import ruby files" unless resolved[0] == :rb
138
- else
139
- raise LoadError, "cannot load such file -- #{path}"
140
- end
141
-
142
- required = Im.registry.fetch(resolved_path) do
143
- # handle autoload within import
144
- return nil if $LOADED_FEATURES.include?(resolved_path)
145
-
146
- $LOADED_FEATURES << resolved_path
147
-
148
- import = Im.current_import || Import.new(path)
149
- (Im.registry[resolved_path] ||= Require.new(resolved_path, import)).tap do
150
- Im.with_import(import) do
151
- load resolved_path, import
152
- end
153
- end
154
- end
155
-
156
- Im.import_constants(required, Im.current_imports)
157
-
158
- required&.import
21
+ _, feature_path = $:.resolve_feature_path(path)
22
+ Registry.loader_for(feature_path) if feature_path
159
23
  end
160
24
 
161
- @tracer = TracePoint.new(:class) do |event|
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)
184
- resolved_path = resolved[1]
185
- Im.registry[resolved_path] ||= Require.new(resolved_path, Im.current_import)
186
- Im.registry[resolved_path].defined_constants[name] = event.self
187
- end
188
- end
189
-
190
- require "im/module"
191
-
192
25
  extend self
193
26
  end
metadata CHANGED
@@ -1,84 +1,48 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: im
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Salzberg
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-03 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: rake
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '13.0'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '13.0'
27
- - !ruby/object:Gem::Dependency
28
- name: rake-compiler
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: rspec
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '3.0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '3.0'
55
- description: Import code without side-effects.
56
- email:
57
- - chris@dejimata.com
11
+ date: 2023-01-28 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: " Im is a thread-safe code loader for anonymous-rooted namespaces.\n"
14
+ email: chris@dejimata.com
58
15
  executables: []
59
16
  extensions: []
60
17
  extra_rdoc_files: []
61
18
  files:
62
- - CHANGELOG.md
63
- - Gemfile
64
- - Gemfile.lock
65
- - LICENSE.txt
19
+ - MIT-LICENSE
66
20
  - README.md
67
- - Rakefile
68
21
  - lib/im.rb
22
+ - lib/im/const_path.rb
23
+ - lib/im/error.rb
24
+ - lib/im/explicit_namespace.rb
25
+ - lib/im/gem_inflector.rb
26
+ - lib/im/gem_loader.rb
27
+ - lib/im/inflector.rb
28
+ - lib/im/internal.rb
69
29
  - lib/im/kernel.rb
70
- - lib/im/module.rb
71
- - lib/im/ruby_version_check.rb
30
+ - lib/im/loader.rb
31
+ - lib/im/loader/callbacks.rb
32
+ - lib/im/loader/config.rb
33
+ - lib/im/loader/eager_load.rb
34
+ - lib/im/loader/helpers.rb
35
+ - lib/im/module_const_added.rb
36
+ - lib/im/registry.rb
72
37
  - lib/im/version.rb
73
38
  homepage: https://github.com/shioyama/im
74
39
  licenses:
75
40
  - MIT
76
41
  metadata:
77
42
  homepage_uri: https://github.com/shioyama/im
43
+ changelog_uri: https://github.com/shioyama/im/blob/master/CHANGELOG.md
78
44
  source_code_uri: https://github.com/shioyama/im
79
45
  bug_tracker_uri: https://github.com/shioyama/im/issues
80
- changelog_uri: https://github.com/shioyama/im/CHANGELOG.md
81
- rubygems_mfa_required: 'true'
82
46
  post_install_message:
83
47
  rdoc_options: []
84
48
  require_paths:
@@ -87,15 +51,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
87
51
  requirements:
88
52
  - - ">="
89
53
  - !ruby/object:Gem::Version
90
- version: 3.1.0
54
+ version: '3.2'
91
55
  required_rubygems_version: !ruby/object:Gem::Requirement
92
56
  requirements:
93
57
  - - ">="
94
58
  - !ruby/object:Gem::Version
95
59
  version: '0'
96
60
  requirements: []
97
- rubygems_version: 3.3.7
61
+ rubygems_version: 3.4.0.dev
98
62
  signing_key:
99
63
  specification_version: 4
100
- summary: Module import system.
64
+ summary: Multiverse autoloader
101
65
  test_files: []
data/CHANGELOG.md DELETED
@@ -1,31 +0,0 @@
1
- ## [Unreleased]
2
-
3
- ## [0.1.6] - 2022-10-03
4
- - Remove `Object.const_missing` patch (Ruby patch now handles dynamic toplevel
5
- references)
6
-
7
- ## [0.1.5] - 2022-09-22
8
- - Rename Im::Dependency -> Im::Require
9
- - Handle dynamic requires (require called from method body after file has been imported)
10
- - Refactor: move require/autoload patch logic to Im handler methods
11
-
12
- ## [0.1.4] - 2022-09-19
13
- - Correctly assign constants imported via recursive requires
14
-
15
- ## [0.1.3] - 2022-09-16
16
- - Fix gemspec
17
-
18
- ## [0.1.1] - 2022-09-16
19
-
20
- - Fix TracePoint event
21
- - Simplify import inspect
22
- - Remove unnecessary Kernel#autoload patch
23
- - Encode comprehensive list of top-level constants
24
-
25
- ## [0.1.0] - 2022-09-15
26
-
27
- - Initial release, requires patched version of Ruby.
28
-
29
- ## [0.0.1] - 2022-07-13
30
-
31
- - Stub
data/Gemfile DELETED
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source "https://rubygems.org"
4
-
5
- # Specify your gem's dependencies in im.gemspec
6
- gemspec
7
-
8
- gem "rspec", "~> 3.0"
data/Gemfile.lock DELETED
@@ -1,37 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- im (0.1.6)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- diff-lcs (1.5.0)
10
- rake (13.0.6)
11
- rake-compiler (1.2.0)
12
- rake
13
- rspec (3.11.0)
14
- rspec-core (~> 3.11.0)
15
- rspec-expectations (~> 3.11.0)
16
- rspec-mocks (~> 3.11.0)
17
- rspec-core (3.11.0)
18
- rspec-support (~> 3.11.0)
19
- rspec-expectations (3.11.0)
20
- diff-lcs (>= 1.2.0, < 2.0)
21
- rspec-support (~> 3.11.0)
22
- rspec-mocks (3.11.1)
23
- diff-lcs (>= 1.2.0, < 2.0)
24
- rspec-support (~> 3.11.0)
25
- rspec-support (3.11.0)
26
-
27
- PLATFORMS
28
- x86_64-linux
29
-
30
- DEPENDENCIES
31
- im!
32
- rake (~> 13.0)
33
- rake-compiler
34
- rspec (~> 3.0)
35
-
36
- BUNDLED WITH
37
- 2.3.18
data/LICENSE.txt DELETED
@@ -1,21 +0,0 @@
1
- The MIT License (MIT)
2
-
3
- Copyright (c) 2022 Chris Salzberg
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.
data/Rakefile DELETED
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "bundler/gem_tasks"
4
- require "rspec/core/rake_task"
5
-
6
- RSpec::Core::RakeTask.new(:spec)
7
-
8
- task default: :spec
data/lib/im/module.rb DELETED
@@ -1,9 +0,0 @@
1
- class Module
2
- alias_method :im_original_autoload, :autoload
3
-
4
- def autoload(name, path)
5
- Im.handle_autoload(path) do
6
- im_original_autoload(name, path)
7
- end
8
- end
9
- end