Skip to content

Commit 6fb09b8

Browse files
committed
fix: Use a hybrid strategy to auto-requiring appmap modules
First check if the corresponding framework library is defined. If not, use TracePoint to watch the code getting loaded, and require the appmap module when its corresponding framework library is loaded.
1 parent f4d5b11 commit 6fb09b8

File tree

1 file changed

+51
-13
lines changed

1 file changed

+51
-13
lines changed

lib/appmap.rb

+51-13
Original file line numberDiff line numberDiff line change
@@ -112,19 +112,57 @@ def detect_metadata
112112
end
113113
end
114114

115-
if Gem.loaded_specs['rails']
116-
require 'active_support'
117-
require 'active_support/core_ext'
118-
require 'rails'
119-
require 'appmap/railtie'
120-
end
115+
lambda do
116+
Initializer = Struct.new(:class_name, :module_name, :gem_module_name)
117+
118+
INITIALIZERS = {
119+
'Rails::Railtie' => Initializer.new('AppMap::Railtie', 'appmap/railtie', 'railtie'),
120+
'RSpec' => Initializer.new('AppMap::RSpec', 'appmap/rspec', 'rspec-core'),
121+
'Minitest::Unit::TestCase' => Initializer.new('AppMap::Minitest', 'appmap/minitest', 'minitest')
122+
}
123+
124+
print_msg = if defined?(::Rails) && Rails.logger
125+
Rails.logger
126+
elsif ENV['DEBUG'] == 'true'
127+
Object.method(:warn)
128+
else
129+
->(msg) {}
130+
end
121131

122-
if Gem.loaded_specs['rspec-core']
123-
require 'appmap/rspec'
124-
end
132+
TracePoint.new(:class) do |tp|
133+
cls_name = tp.self.name
134+
initializers = INITIALIZERS.delete(cls_name)
135+
if initializers
136+
initializers = [ initializers ] unless initializers.is_a?(Array)
137+
next if Object.const_defined?(initializers.first.class_name)
138+
139+
gem_module_name = initializers.first.gem_module_name
140+
141+
print_msg.call AppMap::Util.color(<<~LOAD_MSG, :magenta)
142+
When 'appmap' was loaded, '#{gem_module_name}' had not been loaded yet. Now '#{gem_module_name}' has
143+
just been loaded, so the following AppMap modules will be automatically required:
144+
145+
#{initializers.map(&:module_name).join("\n")}
146+
147+
To suppress this message, ensure '#{gem_module_name}' appears before 'appmap' in your Gemfile.
148+
LOAD_MSG
149+
initializers.each do |init|
150+
require init.module_name
151+
end
152+
end
153+
end.enable
154+
155+
if defined?(::Rails::Railtie)
156+
require 'appmap/railtie'
157+
end
125158

126-
if Gem.loaded_specs['minitest']
127-
require 'appmap/minitest'
128-
end
159+
if defined?(::RSpec)
160+
require 'appmap/rspec'
161+
end
162+
163+
if defined?(::Minitest)
164+
require 'appmap/minitest'
165+
end
129166

130-
AppMap.initialize_configuration if ENV['APPMAP'] == 'true'
167+
AppMap.initialize_configuration
168+
end.call if ENV['APPMAP'] == 'true'

0 commit comments

Comments
 (0)