scout_apm 2.6.0 → 2.6.1
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.
- 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
|