appmap 0.102.2 → 0.103.0

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