scout_apm 2.6.0 → 2.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.markdown +5 -0
- data/lib/scout_apm/agent_context.rb +7 -0
- data/lib/scout_apm/auto_instrument/instruction_sequence.rb +4 -2
- data/lib/scout_apm/auto_instrument/layer.rb +2 -1
- data/lib/scout_apm/auto_instrument/rails.rb +14 -1
- data/lib/scout_apm/config.rb +7 -3
- data/lib/scout_apm/instant/middleware.rb +2 -1
- data/lib/scout_apm/layer.rb +3 -0
- data/lib/scout_apm/periodic_work.rb +14 -0
- data/lib/scout_apm/request_histograms.rb +4 -0
- data/lib/scout_apm/tracked_request.rb +8 -4
- data/lib/scout_apm/version.rb +1 -1
- data/test/unit/auto_instrument/assignments-instrumented.rb +11 -11
- data/test/unit/auto_instrument/controller-instrumented.rb +14 -14
- data/test/unit/auto_instrument_test.rb +9 -11
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 302bcce1cb8a4e8e1a000857fed8764438486e8d9a1c7df47c4cd9af475d6468
|
4
|
+
data.tar.gz: ff41334b370a15f45262c5fc6e215400c100f13beb41cd4bbafcbe2800e1ad9f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50e3e4e094927f4add2b1839a9f4b5d8ded24785fc52fce7e37d5931c12e685b0be0234c3c2c5714cc366dcf4dc3dbe0c8f3d8d949e871a552011c558d65e6a5
|
7
|
+
data.tar.gz: 83f98b354e219d40b449df8e7ae121bf0f084e8ac7d7ac7c0d71c32c295791779a6c8720551e92e73f7a4592dfad9d10d709c47e619dc797c6557a8ac7523679
|
data/CHANGELOG.markdown
CHANGED
@@ -103,6 +103,13 @@ module ScoutApm
|
|
103
103
|
@slow_job_policy ||= ScoutApm::SlowJobPolicy.new(self)
|
104
104
|
end
|
105
105
|
|
106
|
+
# Maintains a Histogram of insignificant/significant autoinstrument layers.
|
107
|
+
# significant = 1
|
108
|
+
# insignificant = 0
|
109
|
+
def auto_instruments_layer_histograms
|
110
|
+
@auto_instruments_layer_histograms ||= ScoutApm::RequestHistograms.new
|
111
|
+
end
|
112
|
+
|
106
113
|
# Histogram of the cumulative requests since the start of the process
|
107
114
|
def request_histograms
|
108
115
|
@request_histograms ||= ScoutApm::RequestHistograms.new
|
@@ -5,15 +5,17 @@ module ScoutApm
|
|
5
5
|
module AutoInstrument
|
6
6
|
module InstructionSequence
|
7
7
|
def load_iseq(path)
|
8
|
-
if Rails.controller_path?(path)
|
8
|
+
if Rails.controller_path?(path) & !Rails.ignore?(path)
|
9
9
|
begin
|
10
10
|
new_code = Rails.rewrite(path)
|
11
11
|
return self.compile(new_code, File.basename(path), path)
|
12
12
|
rescue
|
13
13
|
warn "Failed to apply auto-instrumentation to #{path}: #{$!}"
|
14
14
|
end
|
15
|
+
elsif Rails.ignore?(path)
|
16
|
+
warn "AutoInstruments are ignored for path=#{path}."
|
15
17
|
end
|
16
|
-
|
18
|
+
|
17
19
|
return self.compile_file(path)
|
18
20
|
end
|
19
21
|
end
|
@@ -1,11 +1,12 @@
|
|
1
1
|
|
2
2
|
module ScoutApm
|
3
|
-
def self.AutoInstrument(name, backtrace
|
3
|
+
def self.AutoInstrument(name, backtrace, file_name)
|
4
4
|
request = ScoutApm::RequestManager.lookup
|
5
5
|
|
6
6
|
begin
|
7
7
|
layer = ScoutApm::Layer.new('AutoInstrument', name)
|
8
8
|
layer.backtrace = backtrace
|
9
|
+
layer.file_name = file_name
|
9
10
|
|
10
11
|
request.start_layer(layer)
|
11
12
|
started_layer = true
|
@@ -17,6 +17,19 @@ module ScoutApm
|
|
17
17
|
CONTROLLER_FILE.match(path) && !GEM_FILE.match(path)
|
18
18
|
end
|
19
19
|
|
20
|
+
# Autoinstruments increases overhead when applied to many code expressions that perform little work.
|
21
|
+
# You can exclude files from autoinstruments via the `auto_instruments_ignore` option.
|
22
|
+
def self.ignore?(path)
|
23
|
+
res = false
|
24
|
+
ScoutApm::Agent.instance.context.config.value('auto_instruments_ignore').each do |ignored_file_name|
|
25
|
+
if path.include?(ignored_file_name)
|
26
|
+
res = true
|
27
|
+
break
|
28
|
+
end
|
29
|
+
end
|
30
|
+
res
|
31
|
+
end
|
32
|
+
|
20
33
|
def self.rewrite(path, code = nil)
|
21
34
|
code ||= File.read(path)
|
22
35
|
|
@@ -60,7 +73,7 @@ module ScoutApm
|
|
60
73
|
bt = ["#{file_name}:#{line}:in `#{method_name}'"]
|
61
74
|
|
62
75
|
return [
|
63
|
-
"::ScoutApm::AutoInstrument("+ source.dump + ",#{bt}" + "){",
|
76
|
+
"::ScoutApm::AutoInstrument("+ source.dump + ",#{bt}" + ",'#{file_name}'" + "){",
|
64
77
|
"}"
|
65
78
|
]
|
66
79
|
end
|
data/lib/scout_apm/config.rb
CHANGED
@@ -34,6 +34,7 @@ require 'scout_apm/environment'
|
|
34
34
|
# start_resque_server_instrument - Used in special situations with certain Resque installs
|
35
35
|
# timeline_traces - true/false to enable sending of of the timeline trace format.
|
36
36
|
# auto_instruments - true/false whether to install autoinstruments. Only installed if on a supported Ruby version.
|
37
|
+
# auto_instruments_ignore - An array of file names to exclude from autoinstruments (Ex: ['application_controller']).
|
37
38
|
#
|
38
39
|
# Any of these config settings can be set with an environment variable prefixed
|
39
40
|
# by SCOUT_ and uppercasing the key: SCOUT_LOG_LEVEL for instance.
|
@@ -77,7 +78,8 @@ module ScoutApm
|
|
77
78
|
'uri_reporting',
|
78
79
|
'instrument_http_url_length',
|
79
80
|
'timeline_traces',
|
80
|
-
'auto_instruments'
|
81
|
+
'auto_instruments',
|
82
|
+
'auto_instruments_ignore'
|
81
83
|
]
|
82
84
|
|
83
85
|
################################################################################
|
@@ -171,7 +173,8 @@ module ScoutApm
|
|
171
173
|
'instrument_http_url_length' => IntegerCoercion.new,
|
172
174
|
'start_resque_server_instrument' => BooleanCoercion.new,
|
173
175
|
'timeline_traces' => BooleanCoercion.new,
|
174
|
-
'auto_instruments' => BooleanCoercion.new
|
176
|
+
'auto_instruments' => BooleanCoercion.new,
|
177
|
+
'auto_instruments_ignore' => JsonCoercion.new,
|
175
178
|
}
|
176
179
|
|
177
180
|
|
@@ -280,7 +283,8 @@ module ScoutApm
|
|
280
283
|
'start_resque_server_instrument' => true, # still only starts if Resque is detected
|
281
284
|
'collect_remote_ip' => true,
|
282
285
|
'timeline_traces' => true,
|
283
|
-
'auto_instruments' => false
|
286
|
+
'auto_instruments' => false,
|
287
|
+
'auto_instruments_ignore' => []
|
284
288
|
}.freeze
|
285
289
|
|
286
290
|
def value(key)
|
@@ -94,7 +94,8 @@ module ScoutApm
|
|
94
94
|
|
95
95
|
def preconditions_met?
|
96
96
|
if dev_trace_disabled?
|
97
|
-
|
97
|
+
# The line below is very noise as it is called on every request.
|
98
|
+
# logger.debug("DevTrace: isn't activated via config. Try: SCOUT_DEV_TRACE=true rails server")
|
98
99
|
return false
|
99
100
|
end
|
100
101
|
|
data/lib/scout_apm/layer.rb
CHANGED
@@ -38,6 +38,9 @@ module ScoutApm
|
|
38
38
|
# backtrace of where it occurred.
|
39
39
|
attr_accessor :backtrace
|
40
40
|
|
41
|
+
# The file name associated with the layer. Only used for autoinstruments overhead logging.
|
42
|
+
attr_accessor :file_name
|
43
|
+
|
41
44
|
# As we go through a part of a request, instrumentation can store additional data
|
42
45
|
# Known Keys:
|
43
46
|
# :record_count - The number of rows returned by an AR query (From notification instantiation.active_record)
|
@@ -12,10 +12,24 @@ module ScoutApm
|
|
12
12
|
ScoutApm::Debug.instance.call_periodic_hooks
|
13
13
|
@reporting.process_metrics
|
14
14
|
clean_old_percentiles
|
15
|
+
log_layer_histograms
|
15
16
|
end
|
16
17
|
|
17
18
|
private
|
18
19
|
|
20
|
+
def log_layer_histograms
|
21
|
+
# Ex key/value -
|
22
|
+
# "/Users/dlite/projects/scout/apm/app/controllers/application_controller.rb"=>[[0.0, 689], [1.0, 16]]
|
23
|
+
hists = context.auto_instruments_layer_histograms.as_json
|
24
|
+
hists_summary = hists.map { |k,v|
|
25
|
+
[
|
26
|
+
k,
|
27
|
+
{:total => total=v.map(&:last).inject(:+), :significant => (v.last.last/total.to_f).round(2)}
|
28
|
+
]
|
29
|
+
}.to_h
|
30
|
+
context.logger.debug("AutoInstrument Significant Layer Histograms: #{hists_summary.pretty_inspect}")
|
31
|
+
end
|
32
|
+
|
19
33
|
# XXX: Move logic into a RequestHistogramsByTime class that can keep the timeout logic in it
|
20
34
|
def clean_old_percentiles
|
21
35
|
context.
|
@@ -180,14 +180,18 @@ module ScoutApm
|
|
180
180
|
false
|
181
181
|
end
|
182
182
|
|
183
|
+
# Returns +true+ if the total call time of AutoInstrument layers exceeds +AUTO_INSTRUMENT_TIMING_THRESHOLD+ and
|
184
|
+
# records a Histogram of insignificant / significant layers by file name.
|
183
185
|
def layer_insignificant?(layer)
|
186
|
+
result = false # default is significant
|
184
187
|
if layer.type == 'AutoInstrument'
|
185
188
|
if layer.total_call_time < AUTO_INSTRUMENT_TIMING_THRESHOLD
|
186
|
-
|
187
|
-
return true
|
189
|
+
result = true # not significant
|
188
190
|
end
|
191
|
+
# 0 = not significant, 1 = significant
|
192
|
+
@agent_context.auto_instruments_layer_histograms.add(layer.file_name, (result ? 0 : 1))
|
189
193
|
end
|
190
|
-
|
194
|
+
result
|
191
195
|
end
|
192
196
|
|
193
197
|
# Maintains a lookup Hash of call counts by layer name. Used to determine if we should capture a backtrace.
|
@@ -329,7 +333,7 @@ module ScoutApm
|
|
329
333
|
memo
|
330
334
|
end
|
331
335
|
walker.walk
|
332
|
-
converter_results = converter_instances.inject({}) do |memo, (slug,i)|
|
336
|
+
converter_results = converter_instances.inject({}) do |memo, (slug,i)|
|
333
337
|
memo[slug] = i.record!
|
334
338
|
memo
|
335
339
|
end
|
data/lib/scout_apm/version.rb
CHANGED
@@ -1,26 +1,26 @@
|
|
1
1
|
|
2
2
|
class Assignments
|
3
3
|
def nested_assignment
|
4
|
-
@email ||= if (email = ::ScoutApm::AutoInstrument("session[\"email\"]",["BACKTRACE"]){session["email"]}).present?
|
5
|
-
::ScoutApm::AutoInstrument("User.where(email: email).first",["BACKTRACE"]){User.where(email: email).first}
|
4
|
+
@email ||= if (email = ::ScoutApm::AutoInstrument("session[\"email\"]",["BACKTRACE"],'FILE_NAME'){session["email"]}).present?
|
5
|
+
::ScoutApm::AutoInstrument("User.where(email: email).first",["BACKTRACE"],'FILE_NAME'){User.where(email: email).first}
|
6
6
|
else
|
7
7
|
nil
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
11
|
def paginate_collection(coll)
|
12
|
-
page = (::ScoutApm::AutoInstrument("params[:page].present?",["BACKTRACE"]){params[:page].to_i} : 1)
|
13
|
-
per_page = (::ScoutApm::AutoInstrument("params[:per_page].present?",["BACKTRACE"]){params[:per_page].to_i} : 20)
|
14
|
-
pagination, self.collection = ::ScoutApm::AutoInstrument("pagy(...",["BACKTRACE"]){pagy(
|
12
|
+
page = (::ScoutApm::AutoInstrument("params[:page].present?",["BACKTRACE"],'FILE_NAME'){params[:page].to_i} : 1)
|
13
|
+
per_page = (::ScoutApm::AutoInstrument("params[:per_page].present?",["BACKTRACE"],'FILE_NAME'){params[:per_page].to_i} : 20)
|
14
|
+
pagination, self.collection = ::ScoutApm::AutoInstrument("pagy(...",["BACKTRACE"],'FILE_NAME'){pagy(
|
15
15
|
coll,
|
16
16
|
items: per_page,
|
17
17
|
page: page
|
18
18
|
)}
|
19
|
-
::ScoutApm::AutoInstrument("headers[PAGINATION_TOTAL_HEADER] = pagination.count.to_s",["BACKTRACE"]){headers[PAGINATION_TOTAL_HEADER] = pagination.count.to_s}
|
20
|
-
::ScoutApm::AutoInstrument("headers[PAGINATION_TOTAL_PAGES_HEADER] = pagination.pages.to_s",["BACKTRACE"]){headers[PAGINATION_TOTAL_PAGES_HEADER] = pagination.pages.to_s}
|
21
|
-
::ScoutApm::AutoInstrument("headers[PAGINATION_PER_PAGE_HEADER] = per_page.to_s",["BACKTRACE"]){headers[PAGINATION_PER_PAGE_HEADER] = per_page.to_s}
|
22
|
-
::ScoutApm::AutoInstrument("headers[PAGINATION_PAGE_HEADER] = pagination.page.to_s",["BACKTRACE"]){headers[PAGINATION_PAGE_HEADER] = pagination.page.to_s}
|
23
|
-
::ScoutApm::AutoInstrument("headers[PAGINATION_NEXT_PAGE_HEADER] = pagination.next.to_s",["BACKTRACE"]){headers[PAGINATION_NEXT_PAGE_HEADER] = pagination.next.to_s}
|
24
|
-
::ScoutApm::AutoInstrument("collection",["BACKTRACE"]){collection}
|
19
|
+
::ScoutApm::AutoInstrument("headers[PAGINATION_TOTAL_HEADER] = pagination.count.to_s",["BACKTRACE"],'FILE_NAME'){headers[PAGINATION_TOTAL_HEADER] = pagination.count.to_s}
|
20
|
+
::ScoutApm::AutoInstrument("headers[PAGINATION_TOTAL_PAGES_HEADER] = pagination.pages.to_s",["BACKTRACE"],'FILE_NAME'){headers[PAGINATION_TOTAL_PAGES_HEADER] = pagination.pages.to_s}
|
21
|
+
::ScoutApm::AutoInstrument("headers[PAGINATION_PER_PAGE_HEADER] = per_page.to_s",["BACKTRACE"],'FILE_NAME'){headers[PAGINATION_PER_PAGE_HEADER] = per_page.to_s}
|
22
|
+
::ScoutApm::AutoInstrument("headers[PAGINATION_PAGE_HEADER] = pagination.page.to_s",["BACKTRACE"],'FILE_NAME'){headers[PAGINATION_PAGE_HEADER] = pagination.page.to_s}
|
23
|
+
::ScoutApm::AutoInstrument("headers[PAGINATION_NEXT_PAGE_HEADER] = pagination.next.to_s",["BACKTRACE"],'FILE_NAME'){headers[PAGINATION_NEXT_PAGE_HEADER] = pagination.next.to_s}
|
24
|
+
::ScoutApm::AutoInstrument("collection",["BACKTRACE"],'FILE_NAME'){collection}
|
25
25
|
end
|
26
26
|
end
|
@@ -3,47 +3,47 @@ class ClientsController < ApplicationController
|
|
3
3
|
before_action :check_authorization
|
4
4
|
|
5
5
|
def index
|
6
|
-
if ::ScoutApm::AutoInstrument("params[:status] == \"activated\"",["BACKTRACE"]){params[:status] == "activated"}
|
7
|
-
@clients = ::ScoutApm::AutoInstrument("Client.activated",["BACKTRACE"]){Client.activated}
|
6
|
+
if ::ScoutApm::AutoInstrument("params[:status] == \"activated\"",["BACKTRACE"],'FILE_NAME'){params[:status] == "activated"}
|
7
|
+
@clients = ::ScoutApm::AutoInstrument("Client.activated",["BACKTRACE"],'FILE_NAME'){Client.activated}
|
8
8
|
else
|
9
|
-
@clients = ::ScoutApm::AutoInstrument("Client.inactivated",["BACKTRACE"]){Client.inactivated}
|
9
|
+
@clients = ::ScoutApm::AutoInstrument("Client.inactivated",["BACKTRACE"],'FILE_NAME'){Client.inactivated}
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
13
|
def create
|
14
|
-
@client = ::ScoutApm::AutoInstrument("Client.new(params[:client])",["BACKTRACE"]){Client.new(params[:client])}
|
15
|
-
if ::ScoutApm::AutoInstrument("@client.save",["BACKTRACE"]){@client.save}
|
16
|
-
::ScoutApm::AutoInstrument("redirect_to @client",["BACKTRACE"]){redirect_to @client}
|
14
|
+
@client = ::ScoutApm::AutoInstrument("Client.new(params[:client])",["BACKTRACE"],'FILE_NAME'){Client.new(params[:client])}
|
15
|
+
if ::ScoutApm::AutoInstrument("@client.save",["BACKTRACE"],'FILE_NAME'){@client.save}
|
16
|
+
::ScoutApm::AutoInstrument("redirect_to @client",["BACKTRACE"],'FILE_NAME'){redirect_to @client}
|
17
17
|
else
|
18
18
|
# This line overrides the default rendering behavior, which
|
19
19
|
# would have been to render the "create" view.
|
20
|
-
::ScoutApm::AutoInstrument("render \"new\"",["BACKTRACE"]){render "new"}
|
20
|
+
::ScoutApm::AutoInstrument("render \"new\"",["BACKTRACE"],'FILE_NAME'){render "new"}
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
24
|
def edit
|
25
|
-
@client = ::ScoutApm::AutoInstrument("Client.new(params[:client])",["BACKTRACE"]){Client.new(params[:client])}
|
25
|
+
@client = ::ScoutApm::AutoInstrument("Client.new(params[:client])",["BACKTRACE"],'FILE_NAME'){Client.new(params[:client])}
|
26
26
|
|
27
|
-
if ::ScoutApm::AutoInstrument("request.post?",["BACKTRACE"]){request.post?}
|
28
|
-
::ScoutApm::AutoInstrument("@client.transaction do...",["BACKTRACE"]){@client.transaction do
|
27
|
+
if ::ScoutApm::AutoInstrument("request.post?",["BACKTRACE"],'FILE_NAME'){request.post?}
|
28
|
+
::ScoutApm::AutoInstrument("@client.transaction do...",["BACKTRACE"],'FILE_NAME'){@client.transaction do
|
29
29
|
@client.update_attributes(params[:client])
|
30
30
|
end}
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
34
|
def data
|
35
|
-
@clients = ::ScoutApm::AutoInstrument("Client.all",["BACKTRACE"]){Client.all}
|
35
|
+
@clients = ::ScoutApm::AutoInstrument("Client.all",["BACKTRACE"],'FILE_NAME'){Client.all}
|
36
36
|
|
37
|
-
formatter = ::ScoutApm::AutoInstrument("proc do |row|...",["BACKTRACE"]){proc do |row|
|
37
|
+
formatter = ::ScoutApm::AutoInstrument("proc do |row|...",["BACKTRACE"],'FILE_NAME'){proc do |row|
|
38
38
|
row.to_json
|
39
39
|
end}
|
40
40
|
|
41
|
-
::ScoutApm::AutoInstrument("respond_with @clients.each(&formatter).join(\"\\n\"), :content_type => '
|
41
|
+
::ScoutApm::AutoInstrument("respond_with @clients.each(&formatter).join(\"\\n\"), :content_type => 'FILE_NAME'}
|
42
42
|
end
|
43
43
|
|
44
44
|
def things
|
45
45
|
x = {}
|
46
46
|
x[:this] ||= 'foo'
|
47
|
-
x[:that] &&= ::ScoutApm::AutoInstrument("'
|
47
|
+
x[:that] &&= ::ScoutApm::AutoInstrument("'FILE_NAME'.size}
|
48
48
|
end
|
49
49
|
end
|
@@ -19,35 +19,33 @@ class AutoInstrumentTest < Minitest::Test
|
|
19
19
|
# test controller.rb file, which will be different on different environments.
|
20
20
|
# This normalizes backtraces across environments.
|
21
21
|
def normalize_backtrace(string)
|
22
|
-
string
|
22
|
+
string
|
23
|
+
.gsub(/\[".+auto_instrument\/.+?:.+?"\]/,'["BACKTRACE"]')
|
24
|
+
.gsub(/'.+auto_instrument\/.+'/,"'FILE_NAME'")
|
23
25
|
end
|
24
26
|
|
25
27
|
# Use this to automatically update the test fixtures.
|
26
28
|
def update_instrumented_source(name)
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
)
|
29
|
+
source = ::ScoutApm::AutoInstrument::Rails.rewrite(source_path(name))
|
30
|
+
source = normalize_backtrace(source)
|
31
|
+
File.write(instrumented_path(name),source)
|
31
32
|
end
|
32
33
|
|
33
34
|
def test_controller_rewrite
|
35
|
+
# update_instrumented_source("controller")
|
34
36
|
assert_equal instrumented_source("controller"),
|
35
37
|
normalize_backtrace(::ScoutApm::AutoInstrument::Rails.rewrite(source_path("controller")))
|
36
|
-
|
37
|
-
# update_instrumented_source("controller")
|
38
38
|
end
|
39
39
|
|
40
40
|
def test_rescue_from_rewrite
|
41
|
+
# update_instrumented_source("rescue_from")
|
41
42
|
assert_equal instrumented_source("rescue_from"),
|
42
43
|
normalize_backtrace(::ScoutApm::AutoInstrument::Rails.rewrite(source_path("rescue_from")))
|
43
|
-
|
44
|
-
# update_instrumented_source("rescue_from")
|
45
44
|
end
|
46
45
|
|
47
46
|
def test_assignments_rewrite
|
47
|
+
# update_instrumented_source("assignments")
|
48
48
|
assert_equal instrumented_source("assignments"),
|
49
49
|
normalize_backtrace(::ScoutApm::AutoInstrument::Rails.rewrite(source_path("assignments")))
|
50
|
-
|
51
|
-
# update_instrumented_source("assignments")
|
52
50
|
end
|
53
51
|
end if defined? ScoutApm::AutoInstrument
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scout_apm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.6.
|
4
|
+
version: 2.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Derek Haynes
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2019-09-
|
12
|
+
date: 2019-09-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: minitest
|