appmap 0.102.2 → 0.103.0

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.
data/lib/appmap/hook.rb CHANGED
@@ -1,14 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'English'
4
- require_relative './hook_log'
5
-
3
+ require "English"
4
+ require_relative "hook_log"
5
+
6
+ # rubocop:disable Metrics/ClassLength
7
+ # rubocop:disable Metrics/MethodLength
8
+ # rubocop:disable Metrics/BlockLength
9
+ # rubocop:disable Metrics/AbcSize
10
+ # rubocop:disable Complexity/CyclomaticComplexity
11
+ # rubocop:disable Complexity/PerceivedComplexity
6
12
  module AppMap
7
13
  class Hook
8
14
  OBJECT_INSTANCE_METHODS = %i[! != !~ <=> == === =~ __id__ __send__ class clone define_singleton_method display dup
9
- enum_for eql? equal? extend freeze frozen? hash inspect instance_eval instance_exec instance_of? instance_variable_defined? instance_variable_get instance_variable_set instance_variables is_a? itself kind_of? method methods nil? object_id private_methods protected_methods public_method public_methods public_send remove_instance_variable respond_to? send singleton_class singleton_method singleton_methods taint tainted? tap then to_enum to_s to_h to_a trust untaint untrust untrusted? yield_self].freeze
15
+ enum_for eql? equal? extend freeze frozen? hash inspect instance_eval instance_exec instance_of? instance_variable_defined? instance_variable_get instance_variable_set instance_variables is_a? itself kind_of? method methods nil? object_id private_methods protected_methods public_method public_methods public_send remove_instance_variable respond_to? send singleton_class singleton_method singleton_methods taint tainted? tap then to_enum to_s to_h to_a trust untaint untrust untrusted? yield_self].freeze
10
16
  OBJECT_STATIC_METHODS = %i[! != !~ < <= <=> == === =~ > >= __id__ __send__ alias_method allocate ancestors attr
11
- attr_accessor attr_reader attr_writer autoload autoload? class class_eval class_exec class_variable_defined? class_variable_get class_variable_set class_variables clone const_defined? const_get const_missing const_set constants define_method define_singleton_method deprecate_constant display dup enum_for eql? equal? extend freeze frozen? hash include include? included_modules inspect instance_eval instance_exec instance_method instance_methods instance_of? instance_variable_defined? instance_variable_get instance_variable_set instance_variables is_a? itself kind_of? method method_defined? methods module_eval module_exec name new nil? object_id prepend private_class_method private_constant private_instance_methods private_method_defined? private_methods protected_instance_methods protected_method_defined? protected_methods public_class_method public_constant public_instance_method public_instance_methods public_method public_method_defined? public_methods public_send remove_class_variable remove_instance_variable remove_method respond_to? send singleton_class singleton_class? singleton_method singleton_methods superclass taint tainted? tap then to_enum to_s trust undef_method untaint untrust untrusted? yield_self].freeze
17
+ attr_accessor attr_reader attr_writer autoload autoload? class class_eval class_exec class_variable_defined? class_variable_get class_variable_set class_variables clone const_defined? const_get const_missing const_set constants define_method define_singleton_method deprecate_constant display dup enum_for eql? equal? extend freeze frozen? hash include include? included_modules inspect instance_eval instance_exec instance_method instance_methods instance_of? instance_variable_defined? instance_variable_get instance_variable_set instance_variables is_a? itself kind_of? method method_defined? methods module_eval module_exec name new nil? object_id prepend private_class_method private_constant private_instance_methods private_method_defined? private_methods protected_instance_methods protected_method_defined? protected_methods public_class_method public_constant public_instance_method public_instance_methods public_method public_method_defined? public_methods public_send remove_class_variable remove_instance_variable remove_method respond_to? send singleton_class singleton_class? singleton_method singleton_methods superclass taint tainted? tap then to_enum to_s trust undef_method untaint untrust untrusted? yield_self].freeze
12
18
  SLOW_PACKAGE_THRESHOLD = 0.001
13
19
 
14
20
  @unbound_method_arity = ::UnboundMethod.instance_method(:arity)
@@ -39,9 +45,9 @@ module AppMap
39
45
  def qualify_method_name(method)
40
46
  if method.owner.singleton_class?
41
47
  class_name = singleton_method_owner_name(method)
42
- [class_name, '.', method.name]
48
+ [class_name, ".", method.name]
43
49
  else
44
- [method.owner.name, '#', method.name]
50
+ [method.owner.name, "#", method.name]
45
51
  end
46
52
  end
47
53
  end
@@ -55,7 +61,7 @@ module AppMap
55
61
 
56
62
  # Observe class loading and hook all methods which match the config.
57
63
  def enable(&block)
58
- require 'appmap/hook/method'
64
+ require "appmap/hook/method"
59
65
 
60
66
  hook_builtins
61
67
 
@@ -66,7 +72,7 @@ module AppMap
66
72
  @module_load_times = Hash.new { |memo, k| memo[k] = 0 }
67
73
  @slow_packages = Set.new
68
74
 
69
- if ENV['APPMAP_PROFILE_HOOK'] == 'true'
75
+ if ENV["APPMAP_PROFILE_HOOK"] == "true"
70
76
  dump_times = lambda do
71
77
  @module_load_times
72
78
  .keys
@@ -80,7 +86,7 @@ module AppMap
80
86
  end
81
87
  end
82
88
 
83
- at_exit &dump_times
89
+ at_exit(&dump_times)
84
90
  Thread.new do
85
91
  while true
86
92
  dump_times.call
@@ -102,7 +108,7 @@ module AppMap
102
108
  hooks_by_class.each do |class_name, hooks|
103
109
  Array(hooks).each do |hook|
104
110
  HookLog.builtin class_name do
105
- if builtin && hook.package.require_name && hook.package.require_name != 'ruby'
111
+ if builtin && hook.package.require_name && hook.package.require_name != "ruby"
106
112
  begin
107
113
  require hook.package.require_name
108
114
  rescue
@@ -110,39 +116,59 @@ module AppMap
110
116
  next
111
117
  end
112
118
  end
113
-
119
+
114
120
  begin
115
121
  base_cls = Object.const_get class_name
116
122
  rescue NameError
117
123
  HookLog.load_error class_name, "Class #{class_name} not found in global scope" if HookLog.enabled?
118
124
  next
119
125
  end
120
-
126
+
121
127
  Array(hook.method_names).each do |method_name|
122
128
  method_name = method_name.to_sym
123
-
129
+
124
130
  hook_method = lambda do |entry|
125
131
  cls, method = entry
126
132
  next if config.never_hook?(cls, method)
127
-
133
+
128
134
  hook.package.handler_class.new(hook.package, cls, method).activate
129
135
  end
130
-
136
+
131
137
  methods = []
132
138
  # irb(main):001:0> Kernel.public_instance_method(:system)
133
139
  # (irb):1:in `public_instance_method': method `system' for module `Kernel' is private (NameError)
134
140
  if base_cls == Kernel
135
- methods << [base_cls, base_cls.instance_method(method_name)] rescue nil
141
+ begin
142
+ methods << [base_cls, base_cls.instance_method(method_name)]
143
+ rescue
144
+ nil
145
+ end
146
+ end
147
+ begin
148
+ methods << [base_cls, base_cls.public_instance_method(method_name)]
149
+ rescue
150
+ nil
151
+ end
152
+ begin
153
+ methods << [base_cls, base_cls.protected_instance_method(method_name)]
154
+ rescue
155
+ nil
136
156
  end
137
- methods << [base_cls, base_cls.public_instance_method(method_name)] rescue nil
138
- methods << [base_cls, base_cls.protected_instance_method(method_name)] rescue nil
139
157
  if base_cls.respond_to?(:singleton_class)
140
- methods << [base_cls.singleton_class, base_cls.singleton_class.public_instance_method(method_name)] rescue nil
141
- methods << [base_cls.singleton_class, base_cls.singleton_class.protected_instance_method(method_name)] rescue nil
158
+ begin
159
+ methods << [base_cls.singleton_class, base_cls.singleton_class.public_instance_method(method_name)]
160
+ rescue
161
+ nil
162
+ end
163
+ begin
164
+ methods << [base_cls.singleton_class, base_cls.singleton_class.protected_instance_method(method_name)]
165
+ rescue
166
+ nil
167
+ end
142
168
  end
143
169
  methods.compact!
144
170
  if methods.empty?
145
- HookLog.load_error [ base_cls.name, method_name ].join('[#.]'), "Method #{method_name} not found on #{base_cls.name}" if HookLog.enabled?
171
+ HookLog.load_error [base_cls.name, method_name].join("[#.]"), "Method #{method_name} not found on #{base_cls.name}" if HookLog.enabled?
146
172
  else
147
173
  methods.each(&hook_method)
148
174
  end
@@ -152,13 +178,13 @@ module AppMap
152
178
  end
153
179
  end
154
180
 
155
- hook_loaded_code.(config.builtin_hooks, true)
181
+ hook_loaded_code.call(config.builtin_hooks, true)
156
182
  end
157
183
 
158
184
  protected
159
185
 
160
186
  def trace_location(trace_point)
161
- [trace_point.path, trace_point.lineno].join(':')
187
+ [trace_point.path, trace_point.lineno].join(":")
162
188
  end
163
189
 
164
190
  def trace_end(trace_point)
@@ -168,7 +194,7 @@ module AppMap
168
194
  path = trace_point.path
169
195
  enabled = !@notrace_paths.member?(path) && config.path_enabled?(path)
170
196
  unless enabled
171
- HookLog.log 'Not hooking - path is not enabled' if HookLog.enabled?
197
+ HookLog.log "Not hooking - path is not enabled" if HookLog.enabled?
172
198
  @notrace_paths << path
173
199
  next
174
200
  end
@@ -178,31 +204,31 @@ module AppMap
178
204
  instance_methods = cls.public_instance_methods(false) + cls.protected_instance_methods(false) - OBJECT_INSTANCE_METHODS
179
205
  # NoMethodError: private method `singleton_class' called for Rack::MiniProfiler:Class
180
206
  class_methods = begin
181
- if cls.respond_to?(:singleton_class)
182
- cls.singleton_class.public_instance_methods(false) + cls.singleton_class.protected_instance_methods(false) - instance_methods - OBJECT_STATIC_METHODS
183
- else
184
- []
185
- end
186
- rescue NameError
207
+ if cls.respond_to?(:singleton_class)
208
+ cls.singleton_class.public_instance_methods(false) + cls.singleton_class.protected_instance_methods(false) - instance_methods - OBJECT_STATIC_METHODS
209
+ else
187
210
  []
188
211
  end
212
+ rescue NameError
213
+ []
214
+ end
189
215
 
190
216
  hook = lambda do |hook_cls|
191
217
  lambda do |method_id|
192
218
  method = begin
193
- hook_cls.instance_method(method_id)
194
- rescue NameError
195
- HookLog.load_error [ hook_cls, method_id ].join('[#.]'), "Method #{hook_cls} #{method_id} is not accessible: #{$!}" if HookLog.enabled?
196
- next
197
- end
219
+ hook_cls.instance_method(method_id)
220
+ rescue NameError
221
+ HookLog.load_error [hook_cls, method_id].join("[#.]"), "Method #{hook_cls} #{method_id} is not accessible: #{$!}" if HookLog.enabled?
222
+ next
223
+ end
198
224
 
199
- package = config.lookup_package(hook_cls, method)
225
+ hook_config = config.lookup_hook_config(hook_cls, method)
200
226
  # doing this check first returned early in 98.7% of cases in sample_app_6th_ed
201
- next unless package
227
+ next unless hook_config
202
228
 
203
229
  # Don't try and trace the AppMap methods or there will be
204
230
  # a stack overflow in the defined hook method.
205
- next if %w[Marshal AppMap ActiveSupport].member?((hook_cls&.name || '').split('::')[0])
231
+ next if %w[Marshal AppMap ActiveSupport].member?((hook_cls&.name || "").split("::")[0])
206
232
 
207
233
  next if method_id == :call
208
234
 
@@ -215,15 +241,19 @@ module AppMap
215
241
  # TODO: Figure out how to tell the difference?
216
242
  next unless disasm
217
243
 
218
- package.handler_class.new(package, hook_cls, method).activate
244
+ record_around = Config::RECORD_AROUND_LABELS.find { |label| hook_config.labels.include?(label) }
245
+
246
+ HookLog.log "Detected labels: #{hook_config.labels.join(", ")} (record_around: #{record_around})" if !hook_config.labels.empty? && HookLog.enabled?
247
+
248
+ hook_config.package.handler_class.new(hook_config.package, hook_cls, method, record_around: record_around).activate
219
249
  end
220
250
  end
221
251
 
222
252
  start = Time.now
223
- instance_methods.each(&hook.(cls))
253
+ instance_methods.each(&hook.call(cls))
224
254
  begin
225
255
  # NoMethodError: private method `singleton_class' called for Rack::MiniProfiler:Class
226
- class_methods.each(&hook.(cls.singleton_class)) if cls.respond_to?(:singleton_class)
256
+ class_methods.each(&hook.call(cls.singleton_class)) if cls.respond_to?(:singleton_class)
227
257
  rescue NameError
228
258
  # NameError:
229
259
  # uninitialized constant Faraday::Connection
@@ -231,12 +261,12 @@ module AppMap
231
261
  end
232
262
  elapsed = Time.now - start
233
263
  if location.index(Bundler.bundle_path.to_s) == 0
234
- package_tokens = location[Bundler.bundle_path.to_s.length + 1..-1].split('/')
264
+ package_tokens = location[Bundler.bundle_path.to_s.length + 1..-1].split("/")
235
265
  @module_load_times[package_tokens[1]] += elapsed
236
266
  else
237
267
  file_path = location[Dir.pwd.length + 1..-1]
238
268
  if file_path
239
- location = file_path.split('/', 3)[0..1].join('/')
269
+ location = file_path.split("/", 3)[0..1].join("/")
240
270
  @module_load_times[location] += elapsed
241
271
  end
242
272
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'appmap/util'
3
+ require "appmap/util"
4
4
 
5
5
  module AppMap
6
6
  module Metadata
@@ -9,12 +9,12 @@ module AppMap
9
9
  {
10
10
  app: AppMap.configuration.name,
11
11
  language: {
12
- name: 'ruby',
12
+ name: "ruby",
13
13
  engine: RUBY_ENGINE,
14
14
  version: RUBY_VERSION
15
15
  },
16
16
  client: {
17
- name: 'appmap',
17
+ name: "appmap",
18
18
  url: AppMap::URL,
19
19
  version: AppMap::VERSION
20
20
  }
@@ -22,7 +22,7 @@ module AppMap
22
22
  if defined?(::Rails) && defined?(::Rails.version)
23
23
  m[:frameworks] ||= []
24
24
  m[:frameworks] << {
25
- name: 'rails',
25
+ name: "rails",
26
26
  version: ::Rails.version
27
27
  }
28
28
  end
@@ -33,30 +33,18 @@ module AppMap
33
33
  protected
34
34
 
35
35
  def git_available
36
- @git_available = system('git status 2>&1 > /dev/null') if @git_available.nil?
36
+ @git_available = system("git status 2>&1 > /dev/null") if @git_available.nil?
37
37
  end
38
38
 
39
39
  def git_metadata
40
40
  git_repo = `git config --get remote.origin.url`.strip
41
41
  git_branch = `git rev-parse --abbrev-ref HEAD`.strip
42
42
  git_sha = `git rev-parse HEAD`.strip
43
- git_status = `git status -s`.split("\n").map(&:strip)
44
- git_last_annotated_tag = `git describe --abbrev=0 2>/dev/null`.strip
45
- git_last_annotated_tag = nil if Util.blank?(git_last_annotated_tag)
46
- git_last_tag = `git describe --abbrev=0 --tags 2>/dev/null`.strip
47
- git_last_tag = nil if Util.blank?(git_last_tag)
48
- git_commits_since_last_annotated_tag = `git describe`.strip =~ /-(\d+)-(\w+)$/[1] rescue 0 if git_last_annotated_tag
49
- git_commits_since_last_tag = `git describe --tags`.strip =~ /-(\d+)-(\w+)$/[1] rescue 0 if git_last_tag
50
43
 
51
44
  {
52
45
  repository: git_repo,
53
46
  branch: git_branch,
54
- commit: git_sha,
55
- status: git_status,
56
- git_last_annotated_tag: git_last_annotated_tag,
57
- git_last_tag: git_last_tag,
58
- git_commits_since_last_annotated_tag: git_commits_since_last_annotated_tag,
59
- git_commits_since_last_tag: git_commits_since_last_tag
47
+ commit: git_sha
60
48
  }
61
49
  end
62
50
  end
@@ -6,7 +6,7 @@ module AppMap
6
6
  # It can also be enabled to emit an AppMap for each request.
7
7
  class RemoteRecording
8
8
  def initialize(app)
9
- require 'json'
9
+ require "json"
10
10
 
11
11
  @app = app
12
12
  end
@@ -23,18 +23,18 @@ module AppMap
23
23
  end
24
24
 
25
25
  def ws_start_recording
26
- return [ 409, 'Recording is already in progress' ] if @tracer
26
+ return [409, "Recording is already in progress"] if @tracer
27
27
 
28
28
  @events = []
29
29
  @tracer = AppMap.tracing.trace
30
30
  @event_thread = Thread.new { event_loop }
31
31
  @event_thread.abort_on_exception = true
32
32
 
33
- [ 200 ]
33
+ [200]
34
34
  end
35
35
 
36
36
  def ws_stop_recording(req)
37
- return [ 404, 'No recording is in progress' ] unless @tracer
37
+ return [404, "No recording is in progress"] unless @tracer
38
38
 
39
39
  tracer = @tracer
40
40
  @tracer = nil
@@ -50,7 +50,7 @@ module AppMap
50
50
  is_control_command_event = lambda do |event|
51
51
  event[:event] == :call &&
52
52
  event[:http_server_request] &&
53
- event[:http_server_request][:path_info] == '/_appmap/record'
53
+ event[:http_server_request][:path_info] == "/_appmap/record"
54
54
  end
55
55
  control_command_events = @events.select(&is_control_command_event)
56
56
 
@@ -63,8 +63,8 @@ module AppMap
63
63
 
64
64
  metadata = AppMap.detect_metadata
65
65
  metadata[:recorder] = {
66
- name: 'remote_recording',
67
- type: 'remote'
66
+ name: "remote_recording",
67
+ type: "remote"
68
68
  }
69
69
 
70
70
  response = JSON.generate \
@@ -73,7 +73,7 @@ module AppMap
73
73
  metadata: metadata,
74
74
  events: @events
75
75
 
76
- [ 200, response ]
76
+ [200, response]
77
77
  end
78
78
 
79
79
  def call(env)
@@ -82,7 +82,7 @@ module AppMap
82
82
  # 0
83
83
 
84
84
  req = Rack::Request.new(env)
85
- return handle_record_request(req) if AppMap.recording_enabled?(:remote) && req.path == '/_appmap/record'
85
+ return handle_record_request(req) if AppMap.recording_enabled?(:remote) && req.path == "/_appmap/record"
86
86
 
87
87
  start_time = Time.now
88
88
  # Support multi-threaded web server such as Puma by recording each thread
@@ -100,20 +100,19 @@ module AppMap
100
100
  event_fields = events.map(&:keys).flatten.map(&:to_sym).uniq.sort
101
101
  return unless %i[http_server_request http_server_response].all? { |field| event_fields.include?(field) }
102
102
 
103
- path = req.path.gsub(/\/{2,}/, '/') # Double slashes have been observed
104
- appmap_name = "#{req.request_method} #{path} (#{status}) - #{start_time.strftime('%T.%L')}"
105
- appmap_file_name = AppMap::Util.scenario_filename([ start_time.to_f, req.url ].join('_'))
106
- output_dir = File.join(AppMap::DEFAULT_APPMAP_DIR, 'requests')
103
+ path = req.path.gsub(/\/{2,}/, "/") # Double slashes have been observed
104
+ appmap_name = "#{req.request_method} #{path} (#{status}) - #{start_time.strftime("%T.%L")}"
105
+ appmap_file_name = AppMap::Util.scenario_filename([start_time.to_f, req.url].join("_"))
106
+ output_dir = File.join(AppMap.output_dir, "requests")
107
107
  appmap_file_path = File.join(output_dir, appmap_file_name)
108
108
 
109
109
  metadata = AppMap.detect_metadata
110
110
  metadata[:name] = appmap_name
111
- metadata[:timestamp] = start_time.to_f
112
111
  metadata[:recorder] = {
113
- name: 'rack',
114
- type: 'requests'
112
+ name: "rack",
113
+ type: "requests"
115
114
  }
116
-
115
+
117
116
  appmap = {
118
117
  version: AppMap::APPMAP_FORMAT_VERSION,
119
118
  classMap: AppMap.class_map(tracer.event_methods),
@@ -124,36 +123,36 @@ module AppMap
124
123
  FileUtils.mkdir_p(output_dir)
125
124
  File.write(appmap_file_path, JSON.generate(appmap))
126
125
 
127
- headers['AppMap-Name'] = File.expand_path(appmap_name)
128
- headers['AppMap-File-Name'] = File.expand_path(appmap_file_path)
126
+ headers["AppMap-Name"] = File.expand_path(appmap_name)
127
+ headers["AppMap-File-Name"] = File.expand_path(appmap_file_path)
129
128
  end
130
129
 
131
130
  @app.call(env).tap(&record_request)
132
131
  end
133
132
 
134
133
  def recording_state
135
- [ 200, JSON.generate({ enabled: recording? }) ]
134
+ [200, JSON.generate({enabled: recording?})]
136
135
  end
137
136
 
138
137
  def handle_record_request(req)
139
- method = req.env['REQUEST_METHOD']
138
+ method = req.env["REQUEST_METHOD"]
140
139
 
141
140
  status, body = \
142
- if method.eql?('GET')
141
+ if method.eql?("GET")
143
142
  recording_state
144
- elsif method.eql?('POST')
143
+ elsif method.eql?("POST")
145
144
  ws_start_recording
146
- elsif method.eql?('DELETE')
145
+ elsif method.eql?("DELETE")
147
146
  ws_stop_recording(req)
148
147
  else
149
- [ 404, '' ]
148
+ [404, ""]
150
149
  end
151
150
 
152
- [status, { 'Content-Type' => 'application/json' }, [body || '']]
151
+ [status, {"Content-Type" => "application/json"}, [body || ""]]
153
152
  end
154
153
 
155
154
  def html_response?(headers)
156
- headers['Content-Type'] && headers['Content-Type'] =~ /html/
155
+ headers["Content-Type"] && headers["Content-Type"] =~ /html/
157
156
  end
158
157
 
159
158
  def record_all_requests?
@@ -1,18 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../appmap'
4
- require_relative './util'
5
- require_relative './detect_enabled'
6
- require 'fileutils'
7
- require 'active_support'
8
- require 'active_support/core_ext'
3
+ require_relative "../appmap"
4
+ require_relative "util"
5
+ require_relative "detect_enabled"
6
+ require "fileutils"
7
+ require "active_support"
8
+ require "active_support/core_ext"
9
9
 
10
10
  module AppMap
11
11
  # Integration of AppMap with Minitest. When enabled with APPMAP=true, the AppMap tracer will
12
12
  # be activated around each test.
13
13
  module Minitest
14
- APPMAP_OUTPUT_DIR = 'tmp/appmap/minitest'
15
- LOG = (ENV['APPMAP_DEBUG'] == 'true' || ENV['DEBUG'] == 'true')
14
+ APPMAP_OUTPUT_DIR = File.join(AppMap.output_dir, "minitest")
15
+ LOG = (ENV["APPMAP_DEBUG"] == "true" || ENV["DEBUG"] == "true")
16
16
 
17
17
  def self.metadata
18
18
  AppMap.detect_metadata
@@ -28,13 +28,13 @@ module AppMap
28
28
 
29
29
  def source_location
30
30
  location = test.method(test_name).source_location
31
- [ Util.normalize_path(location.first), location.last ].join(':')
31
+ [Util.normalize_path(location.first), location.last].join(":")
32
32
  end
33
33
 
34
34
  def finish(failures, exception)
35
35
  failed = failures.any? || exception
36
36
  if AppMap::Minitest::LOG
37
- warn "Finishing recording of #{failed ? 'failed ' : ''} test #{test.class}.#{test.name}"
37
+ warn "Finishing recording of #{failed ? "failed " : ""} test #{test.class}.#{test.name}"
38
38
  end
39
39
  warn "Exception: #{exception}" if exception && AppMap::Minitest::LOG
40
40
 
@@ -53,17 +53,17 @@ module AppMap
53
53
 
54
54
  class_map = AppMap.class_map(@trace.event_methods)
55
55
 
56
- feature_group = test.class.name.underscore.split('_')[0...-1].join('_').capitalize
57
- feature_name = test.name.split('_')[1..-1].join(' ')
58
- scenario_name = [feature_group, feature_name].join(' ')
56
+ feature_group = test.class.name.underscore.split("_")[0...-1].join("_").capitalize
57
+ feature_name = test.name.split("_")[1..-1].join(" ")
58
+ scenario_name = [feature_group, feature_name].join(" ")
59
59
 
60
60
  AppMap::Minitest.save name: scenario_name,
61
- class_map: class_map,
62
- source_location: source_location,
63
- test_status: failed ? 'failed' : 'succeeded',
64
- test_failure: test_failure,
65
- exception: exception,
66
- events: events
61
+ class_map: class_map,
62
+ source_location: source_location,
63
+ test_status: failed ? "failed" : "succeeded",
64
+ test_failure: test_failure,
65
+ exception: exception,
66
+ events: events
67
67
  end
68
68
  end
69
69
 
@@ -96,7 +96,7 @@ module AppMap
96
96
  end
97
97
 
98
98
  def config
99
- @config or raise 'AppMap is not configured'
99
+ @config or raise "AppMap is not configured"
100
100
  end
101
101
 
102
102
  def add_event_methods(event_methods)
@@ -110,12 +110,12 @@ module AppMap
110
110
  m[:app] = AppMap.configuration.name
111
111
  m[:frameworks] ||= []
112
112
  m[:frameworks] << {
113
- name: 'minitest',
114
- version: Gem.loaded_specs['minitest']&.version&.to_s
113
+ name: "minitest",
114
+ version: Gem.loaded_specs["minitest"]&.version&.to_s
115
115
  }
116
116
  m[:recorder] = {
117
- name: 'minitest',
118
- type: 'tests'
117
+ name: "minitest",
118
+ type: "tests"
119
119
  }
120
120
  m[:test_status] = test_status
121
121
  m[:test_failure] = test_failure if test_failure
@@ -145,11 +145,11 @@ module AppMap
145
145
  end
146
146
 
147
147
  if AppMap::Minitest.enabled?
148
- require 'appmap'
149
- require 'minitest/test'
148
+ require "appmap"
149
+ require "minitest/test"
150
150
 
151
151
  class ::Minitest::Test
152
- alias run_without_hook run
152
+ alias_method :run_without_hook, :run
153
153
 
154
154
  def run
155
155
  AppMap::Minitest.begin_test self, name