librato-metrics 0.6.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +1 -0
- data/CHANGELOG.md +8 -0
- data/Gemfile +6 -1
- data/lib/librato/metrics.rb +2 -1
- data/lib/librato/metrics/aggregator.rb +33 -17
- data/lib/librato/metrics/client.rb +33 -3
- data/lib/librato/metrics/connection.rb +1 -0
- data/lib/librato/metrics/errors.rb +1 -0
- data/lib/librato/metrics/processor.rb +7 -2
- data/lib/librato/metrics/queue.rb +46 -7
- data/lib/librato/metrics/version.rb +1 -1
- data/spec/integration/metrics_spec.rb +61 -0
- data/spec/spec_helper.rb +6 -2
- data/spec/unit/metrics/aggregator_spec.rb +14 -0
- data/spec/unit/metrics/connection_spec.rb +9 -0
- data/spec/unit/metrics/queue_spec.rb +95 -0
- metadata +4 -3
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
## Changelog
|
2
2
|
|
3
|
+
### Version 0.7.0
|
4
|
+
* Add ability to update metric properties (Christoph Bünte)
|
5
|
+
* Add ability to merge queue and aggregator data into a queue
|
6
|
+
* Aggregator supports custom source by measurement
|
7
|
+
* Add option to clear queued measurements after failed submit
|
8
|
+
* Custom user agent support
|
9
|
+
* Documentation improvements
|
10
|
+
|
3
11
|
### Version 0.6.1
|
4
12
|
* Loosen restrictions to older versions of faraday and multi_json
|
5
13
|
* Fix symbol casting issue in jruby with metric delete
|
data/Gemfile
CHANGED
data/lib/librato/metrics.rb
CHANGED
@@ -63,6 +63,7 @@ module Librato
|
|
63
63
|
extend SingleForwardable
|
64
64
|
|
65
65
|
TYPES = [:counter, :gauge]
|
66
|
+
PLURAL_TYPES = [:counters, :gauges]
|
66
67
|
MIN_MEASURE_TIME = (Time.now-(3600*24*365)).to_i
|
67
68
|
|
68
69
|
# Expose class methods of Simple via Metrics itself.
|
@@ -70,7 +71,7 @@ module Librato
|
|
70
71
|
def_delegators :client, :agent_identifier, :api_endpoint,
|
71
72
|
:api_endpoint=, :authenticate, :connection, :delete,
|
72
73
|
:fetch, :list, :persistence, :persistence=, :persister,
|
73
|
-
:submit
|
74
|
+
:submit, :update
|
74
75
|
|
75
76
|
# The Librato::Metrics::Client being used by module-level
|
76
77
|
# access.
|
@@ -5,8 +5,10 @@ module Librato
|
|
5
5
|
module Metrics
|
6
6
|
|
7
7
|
class Aggregator
|
8
|
-
|
8
|
+
SOURCE_SEPARATOR = '%%' # must not be in valid source name criteria
|
9
9
|
|
10
|
+
include Processor
|
11
|
+
|
10
12
|
attr_reader :source
|
11
13
|
|
12
14
|
def initialize(options={})
|
@@ -16,14 +18,21 @@ module Librato
|
|
16
18
|
|
17
19
|
# Add a metric entry to the metric set:
|
18
20
|
#
|
19
|
-
# @param Hash
|
20
|
-
# @return Aggregator returns self
|
21
|
-
def add(
|
22
|
-
|
23
|
-
|
21
|
+
# @param [Hash] measurements measurements to add
|
22
|
+
# @return [Aggregator] returns self
|
23
|
+
def add(measurements)
|
24
|
+
measurements.each do |metric, data|
|
25
|
+
if data.respond_to?(:each) # hash form
|
26
|
+
value = data[:value]
|
27
|
+
if data[:source]
|
28
|
+
metric = "#{metric}#{SOURCE_SEPARATOR}#{data[:source]}"
|
29
|
+
end
|
30
|
+
else
|
31
|
+
value = data
|
32
|
+
end
|
24
33
|
|
25
|
-
@aggregated[
|
26
|
-
@aggregated[
|
34
|
+
@aggregated[metric] ||= Aggregate.new
|
35
|
+
@aggregated[metric] << value
|
27
36
|
end
|
28
37
|
autosubmit_check
|
29
38
|
self
|
@@ -38,25 +47,32 @@ module Librato
|
|
38
47
|
|
39
48
|
# Remove all queued metrics
|
40
49
|
#
|
41
|
-
def
|
50
|
+
def clear
|
42
51
|
@aggregated = {}
|
43
52
|
end
|
44
|
-
alias :
|
53
|
+
alias :flush :clear
|
45
54
|
|
46
55
|
def queued
|
47
56
|
gauges = []
|
48
57
|
|
49
|
-
@aggregated.each do |
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
58
|
+
@aggregated.each do |metric, data|
|
59
|
+
source = nil
|
60
|
+
metric = metric.to_s
|
61
|
+
if metric.include?(SOURCE_SEPARATOR)
|
62
|
+
metric, source = metric.split(SOURCE_SEPARATOR)
|
63
|
+
end
|
64
|
+
entry = {
|
65
|
+
:name => metric,
|
66
|
+
:count => data.count,
|
67
|
+
:sum => data.sum,
|
54
68
|
|
55
69
|
# TODO: make float/non-float consistent in the gem
|
56
|
-
:min =>
|
57
|
-
:max =>
|
70
|
+
:min => data.min.to_f,
|
71
|
+
:max => data.max.to_f
|
58
72
|
# TODO: expose v.sum2 and include
|
59
73
|
}
|
74
|
+
entry[:source] = source if source
|
75
|
+
gauges << entry
|
60
76
|
end
|
61
77
|
|
62
78
|
req = { :gauges => gauges }
|
@@ -60,6 +60,19 @@ module Librato
|
|
60
60
|
@connection ||= Connection.new(:client => self, :api_endpoint => api_endpoint)
|
61
61
|
end
|
62
62
|
|
63
|
+
# Overrride user agent for this client's connections. If you
|
64
|
+
# are trying to specify an agent identifier for developer
|
65
|
+
# program, see #agent_identifier.
|
66
|
+
#
|
67
|
+
def custom_user_agent=(agent)
|
68
|
+
@user_agent = agent
|
69
|
+
@connection = nil
|
70
|
+
end
|
71
|
+
|
72
|
+
def custom_user_agent
|
73
|
+
@user_agent
|
74
|
+
end
|
75
|
+
|
63
76
|
# Completely delete metrics with the given names. Be
|
64
77
|
# careful with this, this is instant and permanent.
|
65
78
|
#
|
@@ -91,7 +104,7 @@ module Librato
|
|
91
104
|
#
|
92
105
|
# @example Get 20 most recent data points for a specific source
|
93
106
|
# data = Librato::Metrics.fetch :temperature, :count => 20,
|
94
|
-
#
|
107
|
+
# :source => 'app1'
|
95
108
|
#
|
96
109
|
# @example Get the 20 most recent 15 minute data point rollups
|
97
110
|
# data = Librato::Metrics.fetch :temperature, :count => 20,
|
@@ -172,7 +185,7 @@ module Librato
|
|
172
185
|
|
173
186
|
# Set persistence type to use when saving metrics.
|
174
187
|
#
|
175
|
-
# @param [Symbol]
|
188
|
+
# @param [Symbol] persist_method
|
176
189
|
def persistence=(persist_method)
|
177
190
|
@persistence = persist_method
|
178
191
|
end
|
@@ -185,10 +198,27 @@ module Librato
|
|
185
198
|
# Submit all queued metrics.
|
186
199
|
#
|
187
200
|
def submit(args)
|
188
|
-
@queue ||= Queue.new(:client => self,
|
201
|
+
@queue ||= Queue.new(:client => self,
|
202
|
+
:skip_measurement_times => true,
|
203
|
+
:clear_failures => true)
|
189
204
|
@queue.add args
|
190
205
|
@queue.submit
|
191
206
|
end
|
207
|
+
|
208
|
+
# Update metric with the given name.
|
209
|
+
#
|
210
|
+
# @example Update metric 'temperature'
|
211
|
+
# Librato::Metrics.update :temperature, :period => 15, :attributes => { :color => 'F00' }
|
212
|
+
#
|
213
|
+
# @example Update metric 'humidity', creating it if it doesn't exist
|
214
|
+
# Librato::Metrics.update 'humidity', :type => :gauge, :period => 60, :display_name => 'Humidity'
|
215
|
+
#
|
216
|
+
def update(metric, options = {})
|
217
|
+
connection.put do |request|
|
218
|
+
request.url connection.build_url("metrics/#{metric}")
|
219
|
+
request.body = MultiJson.dump(options)
|
220
|
+
end
|
221
|
+
end
|
192
222
|
|
193
223
|
private
|
194
224
|
|
@@ -30,16 +30,20 @@ module Librato
|
|
30
30
|
options = {:per_request => @per_request}
|
31
31
|
if persister.persist(self.client, self.queued, options)
|
32
32
|
@last_submit_time = Time.now
|
33
|
-
|
33
|
+
clear and return true
|
34
34
|
end
|
35
35
|
false
|
36
|
+
rescue ClientError
|
37
|
+
# clean up if we hit exceptions if asked to
|
38
|
+
clear if @clear_on_failure
|
39
|
+
raise
|
36
40
|
end
|
37
41
|
|
38
42
|
# Capture execution time for a block and queue
|
39
43
|
# it as the value for a metric. Times are recorded
|
40
44
|
# in milliseconds.
|
41
45
|
#
|
42
|
-
# Options are the same as for
|
46
|
+
# Options are the same as for #add.
|
43
47
|
#
|
44
48
|
# @example Queue API request response time
|
45
49
|
# queue.time :api_request_time do
|
@@ -79,6 +83,7 @@ module Librato
|
|
79
83
|
@per_request = options[:per_request] || MEASUREMENTS_PER_REQUEST
|
80
84
|
@source = options[:source]
|
81
85
|
@create_time = Time.now
|
86
|
+
@clear_on_failure = options[:clear_failures] || false
|
82
87
|
end
|
83
88
|
|
84
89
|
def autosubmit_check
|
@@ -16,10 +16,10 @@ module Librato
|
|
16
16
|
|
17
17
|
# Add a metric entry to the metric set:
|
18
18
|
#
|
19
|
-
# @param Hash
|
20
|
-
# @return Queue returns self
|
21
|
-
def add(
|
22
|
-
|
19
|
+
# @param [Hash] measurements measurements to add
|
20
|
+
# @return [Queue] returns self
|
21
|
+
def add(measurements)
|
22
|
+
measurements.each do |key, value|
|
23
23
|
if value.respond_to?(:each)
|
24
24
|
metric = value
|
25
25
|
metric[:name] = key.to_s
|
@@ -57,11 +57,10 @@ module Librato
|
|
57
57
|
|
58
58
|
# Remove all queued metrics
|
59
59
|
#
|
60
|
-
def
|
60
|
+
def clear
|
61
61
|
@queued = {}
|
62
62
|
end
|
63
|
-
alias :
|
64
|
-
alias :flush_queued :flush
|
63
|
+
alias :flush :clear
|
65
64
|
|
66
65
|
# Currently queued gauges
|
67
66
|
#
|
@@ -69,6 +68,35 @@ module Librato
|
|
69
68
|
def gauges
|
70
69
|
@queued[:gauges] || []
|
71
70
|
end
|
71
|
+
|
72
|
+
# Combines queueable measures from the given object
|
73
|
+
# into this queue.
|
74
|
+
#
|
75
|
+
# @example Merging queues for more performant submission
|
76
|
+
# queue1.merge!(queue2)
|
77
|
+
# queue1.submit # submits combined contents
|
78
|
+
#
|
79
|
+
# @return self
|
80
|
+
def merge!(mergeable)
|
81
|
+
if mergeable.respond_to?(:queued)
|
82
|
+
to_merge = mergeable.queued
|
83
|
+
elsif mergeable.respond_to?(:has_key?)
|
84
|
+
to_merge = mergeable
|
85
|
+
else
|
86
|
+
raise NotMergeable
|
87
|
+
end
|
88
|
+
Metrics::PLURAL_TYPES.each do |type|
|
89
|
+
if to_merge[type]
|
90
|
+
measurements = reconcile_source(to_merge[type], to_merge[:source])
|
91
|
+
if @queued[type]
|
92
|
+
@queued[type] += measurements
|
93
|
+
else
|
94
|
+
@queued[type] = measurements
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
self
|
99
|
+
end
|
72
100
|
|
73
101
|
# All currently queued metrics
|
74
102
|
#
|
@@ -96,6 +124,17 @@ module Librato
|
|
96
124
|
end
|
97
125
|
end
|
98
126
|
|
127
|
+
def reconcile_source(measurements, source)
|
128
|
+
return measurements if !source || source == @source
|
129
|
+
measurements.map! do |measurement|
|
130
|
+
unless measurement[:source]
|
131
|
+
measurement[:source] = source
|
132
|
+
end
|
133
|
+
measurement
|
134
|
+
end
|
135
|
+
measurements
|
136
|
+
end
|
137
|
+
|
99
138
|
def submit_check
|
100
139
|
autosubmit_check # in Processor
|
101
140
|
if @autosubmit_count && self.length >= @autosubmit_count
|
@@ -150,8 +150,69 @@ module Librato
|
|
150
150
|
data['baz'][0]['value'] == 456.0
|
151
151
|
end
|
152
152
|
end
|
153
|
+
|
154
|
+
it "should not retain errors" do
|
155
|
+
delete_all_metrics
|
156
|
+
Metrics.submit :foo => {:type => :counter, :value => 12}
|
157
|
+
lambda {
|
158
|
+
Metrics.submit :foo => 15 # submitting as gauge
|
159
|
+
}.should raise_error
|
160
|
+
lambda {
|
161
|
+
Metrics.submit :foo => {:type => :counter, :value => 17}
|
162
|
+
}.should_not raise_error
|
163
|
+
end
|
153
164
|
|
154
165
|
end
|
166
|
+
|
167
|
+
describe "#update" do
|
168
|
+
|
169
|
+
context "with existing metric" do
|
170
|
+
before do
|
171
|
+
delete_all_metrics
|
172
|
+
Metrics.submit :foo => 123
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should upate the metric" do
|
176
|
+
Metrics.update :foo, :display_name => "Foo Metric",
|
177
|
+
:period => 15,
|
178
|
+
:attributes => {
|
179
|
+
:display_max => 1000
|
180
|
+
}
|
181
|
+
foo = Metrics.fetch :foo
|
182
|
+
foo['display_name'].should == 'Foo Metric'
|
183
|
+
foo['period'].should == 15
|
184
|
+
foo['attributes'].should == {'display_max' => 1000}
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
context "without an existing metric" do
|
189
|
+
it "should create the metric if type specified" do
|
190
|
+
delete_all_metrics
|
191
|
+
Metrics.update :foo, :display_name => "Foo Metric",
|
192
|
+
:type => :gauge,
|
193
|
+
:period => 15,
|
194
|
+
:attributes => {
|
195
|
+
:display_max => 1000
|
196
|
+
}
|
197
|
+
foo = Metrics.fetch :foo
|
198
|
+
foo['display_name'].should == 'Foo Metric'
|
199
|
+
foo['period'].should == 15
|
200
|
+
foo['attributes'].should == {'display_max' => 1000}
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should raise error if no type specified" do
|
204
|
+
delete_all_metrics
|
205
|
+
lambda {
|
206
|
+
Metrics.update :foo, :display_name => "Foo Metric",
|
207
|
+
:period => 15,
|
208
|
+
:attributes => {
|
209
|
+
:display_max => 1000
|
210
|
+
}
|
211
|
+
}.should raise_error
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|
155
216
|
|
156
217
|
end
|
157
218
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -70,9 +70,13 @@ end
|
|
70
70
|
# @example
|
71
71
|
# {:foo => [1,3,2]}.should equal_unordered({:foo => [1,2,3]})
|
72
72
|
RSpec::Matchers.define :equal_unordered do |result|
|
73
|
-
result.each
|
73
|
+
result.each do |key, value|
|
74
|
+
result[key] = value.to_set if value.respond_to?(:to_set)
|
75
|
+
end
|
74
76
|
match do |target|
|
75
|
-
target.each
|
77
|
+
target.each do |key, value|
|
78
|
+
target[key] = value.to_set if value.respond_to?(:to_set)
|
79
|
+
end
|
76
80
|
target == result
|
77
81
|
end
|
78
82
|
end
|
@@ -76,6 +76,20 @@ module Librato
|
|
76
76
|
}
|
77
77
|
subject.queued.should equal_unordered(expected)
|
78
78
|
end
|
79
|
+
|
80
|
+
it "should respect source argument" do
|
81
|
+
subject.add :foo => {:source => 'alpha', :value => 1}
|
82
|
+
subject.add :foo => 5
|
83
|
+
subject.add :foo => {:source => :alpha, :value => 6}
|
84
|
+
subject.add :foo => 10
|
85
|
+
expected = { :gauges => [
|
86
|
+
{ :name => 'foo', :source => 'alpha', :count => 2,
|
87
|
+
:sum => 7.0, :min => 1.0, :max => 6.0 },
|
88
|
+
{ :name => 'foo', :count => 2,
|
89
|
+
:sum => 15.0, :min => 5.0, :max => 10.0 }
|
90
|
+
]}
|
91
|
+
subject.queued.should equal_unordered(expected)
|
92
|
+
end
|
79
93
|
end
|
80
94
|
|
81
95
|
context "with multiple hash arguments" do
|
@@ -37,6 +37,15 @@ module Librato
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
+
context "with a custom user agent set" do
|
41
|
+
it "should use custom user agent" do
|
42
|
+
client = Client.new
|
43
|
+
client.custom_user_agent = 'foo agent'
|
44
|
+
connection = Connection.new(:client => client)
|
45
|
+
connection.user_agent.should == 'foo agent'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
40
49
|
# TODO: verify user agent is being sent with rackup test
|
41
50
|
end
|
42
51
|
|
@@ -163,6 +163,101 @@ module Librato
|
|
163
163
|
end
|
164
164
|
end
|
165
165
|
|
166
|
+
describe "#merge!" do
|
167
|
+
context "with another queue" do
|
168
|
+
it "should merge gauges" do
|
169
|
+
q1 = Queue.new
|
170
|
+
q1.add :foo => 123, :bar => 456
|
171
|
+
q2 = Queue.new
|
172
|
+
q2.add :baz => 678
|
173
|
+
q2.merge!(q1)
|
174
|
+
expected = {:gauges=>[{:name=>"foo", :value=>123, :measure_time => @time},
|
175
|
+
{:name=>"bar", :value=>456, :measure_time => @time},
|
176
|
+
{:name=>"baz", :value=>678, :measure_time => @time}]}
|
177
|
+
q2.queued.should equal_unordered(expected)
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should merge counters" do
|
181
|
+
q1 = Queue.new
|
182
|
+
q1.add :users => {:type => :counter, :value => 1000}
|
183
|
+
q1.add :sales => {:type => :counter, :value => 250}
|
184
|
+
q2 = Queue.new
|
185
|
+
q2.add :signups => {:type => :counter, :value => 500}
|
186
|
+
q2.merge!(q1)
|
187
|
+
expected = {:counters=>[{:name=>"users", :value=>1000, :measure_time => @time},
|
188
|
+
{:name=>"sales", :value=>250, :measure_time => @time},
|
189
|
+
{:name=>"signups", :value=>500, :measure_time => @time}]}
|
190
|
+
q2.queued.should equal_unordered(expected)
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should maintain specified sources" do
|
194
|
+
q1 = Queue.new
|
195
|
+
q1.add :neo => {:source => 'matrix', :value => 123}
|
196
|
+
q2 = Queue.new(:source => 'red_pill')
|
197
|
+
q2.merge!(q1)
|
198
|
+
q2.queued[:gauges][0][:source].should == 'matrix'
|
199
|
+
end
|
200
|
+
|
201
|
+
it "should not change default source" do
|
202
|
+
q1 = Queue.new(:source => 'matrix')
|
203
|
+
q1.add :neo => 456
|
204
|
+
q2 = Queue.new(:source => 'red_pill')
|
205
|
+
q2.merge!(q1)
|
206
|
+
q2.queued[:source].should == 'red_pill'
|
207
|
+
end
|
208
|
+
|
209
|
+
it "should track previous default source" do
|
210
|
+
q1 = Queue.new(:source => 'matrix')
|
211
|
+
q1.add :neo => 456
|
212
|
+
q2 = Queue.new(:source => 'red_pill')
|
213
|
+
q2.add :morpheus => 678
|
214
|
+
q2.merge!(q1)
|
215
|
+
q2.queued[:gauges].each do |gauge|
|
216
|
+
if gauge[:name] == 'neo'
|
217
|
+
gauge[:source].should == 'matrix'
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
it "should handle empty cases" do
|
223
|
+
q1 = Queue.new
|
224
|
+
q1.add :foo => 123, :users => {:type => :counter, :value => 1000}
|
225
|
+
q2 = Queue.new
|
226
|
+
q2.merge!(q1)
|
227
|
+
expected = {:counters => [{:name=>"users", :value=>1000, :measure_time => @time}],
|
228
|
+
:gauges => [{:name=>"foo", :value=>123, :measure_time => @time}]}
|
229
|
+
q2.queued.should == expected
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
context "with an aggregator" do
|
234
|
+
it "should merge" do
|
235
|
+
aggregator = Aggregator.new(:source => 'aggregator')
|
236
|
+
aggregator.add :timing => 102
|
237
|
+
aggregator.add :timing => 203
|
238
|
+
queue = Queue.new(:source => 'queue')
|
239
|
+
queue.add :gauge => 42
|
240
|
+
queue.merge!(aggregator)
|
241
|
+
expected = {:gauges=>[{:name=>"gauge", :value=>42, :measure_time=>@time},
|
242
|
+
{:name=>"timing", :count=>2, :sum=>305.0, :min=>102.0, :max=>203.0, :source=>"aggregator"}],
|
243
|
+
:source=>'queue'}
|
244
|
+
queue.queued.should equal_unordered(expected)
|
245
|
+
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
context "with a hash" do
|
250
|
+
it "should merge" do
|
251
|
+
to_merge = {:gauges=>[{:name => 'foo', :value => 123}],
|
252
|
+
:counters=>[{:name => 'bar', :value => 456}]}
|
253
|
+
q = Queue.new
|
254
|
+
q.merge!(to_merge)
|
255
|
+
q.gauges.length.should == 1
|
256
|
+
q.counters.length.should == 1
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
166
261
|
describe "#per_request" do
|
167
262
|
it "should default to 500" do
|
168
263
|
subject.per_request.should == 500
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: librato-metrics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-07-
|
12
|
+
date: 2012-07-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: faraday
|
@@ -163,6 +163,7 @@ extra_rdoc_files:
|
|
163
163
|
- LICENSE
|
164
164
|
files:
|
165
165
|
- .gitignore
|
166
|
+
- .rspec
|
166
167
|
- .travis.yml
|
167
168
|
- CHANGELOG.md
|
168
169
|
- Gemfile
|
@@ -214,7 +215,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
214
215
|
version: '0'
|
215
216
|
segments:
|
216
217
|
- 0
|
217
|
-
hash: -
|
218
|
+
hash: -1999246465148166572
|
218
219
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
219
220
|
none: false
|
220
221
|
requirements:
|