pulse-meter 0.2.7 → 0.2.8
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/pulse-meter/extensions/enumerable.rb +24 -0
- data/lib/pulse-meter/mixins/cmd.rb +2 -28
- data/lib/pulse-meter/sensor/configuration.rb +14 -0
- data/lib/pulse-meter/sensor/hashed_counter.rb +4 -1
- data/lib/pulse-meter/sensor/timeline.rb +22 -20
- data/lib/pulse-meter/sensor/timelined/hashed_counter.rb +4 -1
- data/lib/pulse-meter/version.rb +1 -1
- data/spec/pulse_meter/extensions/enumerable_spec.rb +58 -0
- data/spec/pulse_meter/mixins/cmd_spec.rb +112 -0
- data/spec/pulse_meter/sensor/hashed_counter_spec.rb +6 -2
- data/spec/pulse_meter/sensor/timelined/hashed_counter_spec.rb +3 -3
- data/spec/shared_examples/timeline_sensor.rb +25 -5
- metadata +8 -3
@@ -0,0 +1,24 @@
|
|
1
|
+
module Enumerable
|
2
|
+
require 'csv'
|
3
|
+
require 'terminal-table'
|
4
|
+
|
5
|
+
def convert_time
|
6
|
+
map {|el| el.is_a?(Time) ? el.to_i : el}
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_table(format = nil)
|
10
|
+
if "csv" == format.to_s
|
11
|
+
CSV.generate(:col_sep => ';') do |csv|
|
12
|
+
self.each {|row| csv << row.convert_time}
|
13
|
+
end
|
14
|
+
else
|
15
|
+
self.each_with_object(Terminal::Table.new) do |row, table|
|
16
|
+
table << if row.respond_to?(:map)
|
17
|
+
row.map(&:to_s)
|
18
|
+
else
|
19
|
+
row
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -1,30 +1,4 @@
|
|
1
|
-
|
2
|
-
def convert_time
|
3
|
-
map do |el|
|
4
|
-
if el.is_a?(Time)
|
5
|
-
el.to_i
|
6
|
-
else
|
7
|
-
el
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
def to_table(format = nil)
|
13
|
-
if "csv" == format
|
14
|
-
CSV.generate(:col_sep => ';') do |csv|
|
15
|
-
self.each {|row| csv << row.convert_time}
|
16
|
-
end
|
17
|
-
else
|
18
|
-
self.each_with_object(Terminal::Table.new) do |row, table|
|
19
|
-
table << if row.respond_to?(:map)
|
20
|
-
row.map(&:to_s)
|
21
|
-
else
|
22
|
-
row
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
1
|
+
require 'pulse-meter/extensions/enumerable'
|
28
2
|
|
29
3
|
module PulseMeter
|
30
4
|
module Mixins
|
@@ -52,7 +26,7 @@ module PulseMeter
|
|
52
26
|
data = [
|
53
27
|
["Name", "Class", "ttl", "raw data ttl", "interval", "reduce delay"],
|
54
28
|
]
|
55
|
-
data << :separator unless
|
29
|
+
data << :separator unless 'csv' == format.to_s
|
56
30
|
all_sensors.each do |s|
|
57
31
|
if s.kind_of? PulseMeter::Sensor::Timeline
|
58
32
|
data << [s.name, s.class, s.ttl, s.raw_data_ttl, s.interval, s.reduce_delay]
|
@@ -1,11 +1,16 @@
|
|
1
1
|
module PulseMeter
|
2
2
|
module Sensor
|
3
|
+
# Constructs multiple sensors from configuration passed
|
3
4
|
class Configuration
|
4
5
|
include PulseMeter::Mixins::Utils
|
5
6
|
include Enumerable
|
6
7
|
|
8
|
+
# @!attribute [r] sensors
|
9
|
+
# @return [Hash] hash of sensors with names as keys and sensors as values
|
7
10
|
attr_reader :sensors
|
8
11
|
|
12
|
+
# Initializes sensors
|
13
|
+
# @param opts [Hash] sensors' configuration
|
9
14
|
def initialize(opts = {})
|
10
15
|
@sensors = {}
|
11
16
|
opts.each do |name, opts|
|
@@ -13,6 +18,9 @@ module PulseMeter
|
|
13
18
|
end
|
14
19
|
end
|
15
20
|
|
21
|
+
# Adds sensor
|
22
|
+
# @param name [Symbol] sensor name
|
23
|
+
# @param opts [Hash] sensor options
|
16
24
|
def add_sensor(name, opts)
|
17
25
|
sensor_type = opts.respond_to?(:sensor_type) ? opts.sensor_type : opts[:sensor_type]
|
18
26
|
klass_s = sensor_class(sensor_type)
|
@@ -22,16 +30,22 @@ module PulseMeter
|
|
22
30
|
@sensors[name.to_s] = klass.new(name, symbolize_keys(args.to_hash))
|
23
31
|
end
|
24
32
|
|
33
|
+
# Returns previously initialized sensor by name
|
34
|
+
# @param name [Symbol] sensor name
|
35
|
+
# @return [Sensor] sensor
|
25
36
|
def sensor(name)
|
26
37
|
@sensors[name.to_s]
|
27
38
|
end
|
28
39
|
|
40
|
+
# Iterates over each sensor
|
29
41
|
def each
|
30
42
|
@sensors.each_value do |sensor|
|
31
43
|
yield(sensor)
|
32
44
|
end
|
33
45
|
end
|
34
46
|
|
47
|
+
# Invokes event for any sensor
|
48
|
+
# @raise [ArgumentError] unless sensor exists
|
35
49
|
def method_missing(name, *args)
|
36
50
|
name = name.to_s
|
37
51
|
if @sensors.has_key?(name)
|
@@ -25,7 +25,10 @@ module PulseMeter
|
|
25
25
|
# @param data [Hash] hash where keys represent counter keys
|
26
26
|
# and values are increments for their keys
|
27
27
|
def process_event(data)
|
28
|
-
data.each_pair
|
28
|
+
data.each_pair do |k, v|
|
29
|
+
redis.hincrby(value_key, k, v.to_i)
|
30
|
+
redis.hincrby(value_key, :total, v.to_i)
|
31
|
+
end
|
29
32
|
end
|
30
33
|
|
31
34
|
end
|
@@ -108,12 +108,17 @@ module PulseMeter
|
|
108
108
|
# Returts sensor data within given time
|
109
109
|
# @param from [Time] lower bound
|
110
110
|
# @param till [Time] upper bound
|
111
|
+
# @param skip_optimization [Boolean] must be set to true to skip interval optimization
|
111
112
|
# @return [Array<SensorData>]
|
112
113
|
# @raise ArgumentError if argumets are not valid time objects
|
113
|
-
def timeline_within(from, till)
|
114
|
+
def timeline_within(from, till, skip_optimization = false)
|
114
115
|
raise ArgumentError unless from.kind_of?(Time) && till.kind_of?(Time)
|
115
116
|
start_time, end_time = from.to_i, till.to_i
|
116
|
-
actual_interval =
|
117
|
+
actual_interval = if skip_optimization
|
118
|
+
interval
|
119
|
+
else
|
120
|
+
optimized_interval(start_time, end_time)
|
121
|
+
end
|
117
122
|
current_interval_id = get_interval_id(start_time) + actual_interval
|
118
123
|
keys = []
|
119
124
|
ids = []
|
@@ -134,19 +139,6 @@ module PulseMeter
|
|
134
139
|
res
|
135
140
|
end
|
136
141
|
|
137
|
-
# Makes interval optimization so that the requested timespan contains less than MAX_TIMESPAN_POINTS values
|
138
|
-
# @param start_time [Fixnum] unix timestamp of timespan start
|
139
|
-
# @param end_time [Fixnum] unix timestamp of timespan start
|
140
|
-
# @return [Fixnum] optimized interval in seconds.
|
141
|
-
def optimized_inteval(start_time, end_time)
|
142
|
-
res_interval = interval
|
143
|
-
timespan = end_time - start_time
|
144
|
-
while timespan / res_interval > MAX_TIMESPAN_POINTS - 1
|
145
|
-
res_interval *= 2
|
146
|
-
end
|
147
|
-
res_interval
|
148
|
-
end
|
149
|
-
|
150
142
|
# Returns sensor data for given interval making in-memory summarization
|
151
143
|
# and returns calculated value
|
152
144
|
# @param interval_id [Fixnum]
|
@@ -174,11 +166,7 @@ module PulseMeter
|
|
174
166
|
keys << raw_data_key(current_interval_id)
|
175
167
|
current_interval_id += interval
|
176
168
|
end
|
177
|
-
|
178
|
-
0
|
179
|
-
else
|
180
|
-
redis.del(*keys)
|
181
|
-
end
|
169
|
+
keys.empty? ? 0 : redis.del(*keys)
|
182
170
|
end
|
183
171
|
|
184
172
|
# Returns Redis key by which raw data for current interval is stored
|
@@ -255,6 +243,20 @@ module PulseMeter
|
|
255
243
|
end
|
256
244
|
end
|
257
245
|
|
246
|
+
# Makes interval optimization so that the requested timespan contains less than MAX_TIMESPAN_POINTS values
|
247
|
+
# @param start_time [Fixnum] unix timestamp of timespan start
|
248
|
+
# @param end_time [Fixnum] unix timestamp of timespan start
|
249
|
+
# @return [Fixnum] optimized interval in seconds.
|
250
|
+
def optimized_interval(start_time, end_time)
|
251
|
+
res_interval = interval
|
252
|
+
timespan = end_time - start_time
|
253
|
+
while timespan / res_interval > MAX_TIMESPAN_POINTS - 1
|
254
|
+
res_interval *= 2
|
255
|
+
end
|
256
|
+
res_interval
|
257
|
+
end
|
258
|
+
|
259
|
+
|
258
260
|
end
|
259
261
|
end
|
260
262
|
end
|
@@ -7,7 +7,10 @@ module PulseMeter
|
|
7
7
|
# Good replacement for multiple counters to be visualized together
|
8
8
|
class HashedCounter < Timeline
|
9
9
|
def aggregate_event(key, data)
|
10
|
-
data.each_pair
|
10
|
+
data.each_pair do |k, v|
|
11
|
+
redis.hincrby(key, k, v)
|
12
|
+
redis.hincrby(key, :total, v)
|
13
|
+
end
|
11
14
|
end
|
12
15
|
|
13
16
|
def summarize(key)
|
data/lib/pulse-meter/version.rb
CHANGED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pulse-meter/extensions/enumerable'
|
3
|
+
|
4
|
+
describe Enumerable do
|
5
|
+
let!(:time) {Time.new}
|
6
|
+
describe "#convert_time" do
|
7
|
+
it "converts Time objects to unixtime" do
|
8
|
+
[time].convert_time.should == [time.to_i]
|
9
|
+
end
|
10
|
+
|
11
|
+
it "does not change other members" do
|
12
|
+
[1, 2, 3].convert_time.should == [1, 2 ,3]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#to_table" do
|
17
|
+
context "when format is csv" do
|
18
|
+
it "returns csv as string" do
|
19
|
+
[].to_table(:csv).should be_instance_of(String)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "returns csv containing each subarray as a row" do
|
23
|
+
[[:a, :b], [:c, :d]].to_table(:csv).should == "a;b\nc;d\n"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "converts Time objects to unixtime" do
|
27
|
+
[[time]].to_table(:csv).should == "#{time.to_i}\n"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "takes format argument both as string and as symbol" do
|
31
|
+
[[:foo]].to_table("csv").should == "foo\n"
|
32
|
+
[[:foo]].to_table(:csv).should == "foo\n"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when format is table" do
|
37
|
+
it "return Terminal::Table instance" do
|
38
|
+
[].to_table.should be_instance_of(Terminal::Table)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "returns table containing each subarray as a row" do
|
42
|
+
data = [[:a, :b], [:c, :d]]
|
43
|
+
table = [[:a, :b], [:c, :d]].to_table
|
44
|
+
table.rows.map do |row|
|
45
|
+
row.cells.map(&:to_s).map(&:strip).map(&:to_sym)
|
46
|
+
end.should == data
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it "uses table format as default" do
|
51
|
+
[].to_table.should be_instance_of(Terminal::Table)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "uses table format unless it is :csv or 'csv'" do
|
55
|
+
[].to_table(:unknown_format).should be_instance_of(Terminal::Table)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PulseMeter::Mixins::Cmd do
|
4
|
+
class Dummy
|
5
|
+
extend PulseMeter::Mixins::Cmd
|
6
|
+
|
7
|
+
def self.options
|
8
|
+
{host: :localhost, port: 6379, db: 0}
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:dummy){ Dummy }
|
13
|
+
before {PulseMeter.redis = Redis.new}
|
14
|
+
|
15
|
+
describe "#fail!" do
|
16
|
+
it "prints given message and exits" do
|
17
|
+
STDOUT.should_receive(:puts).with(:msg)
|
18
|
+
lambda {dummy.fail!(:msg)}.should raise_error(SystemExit)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#with_redis' do
|
23
|
+
it "initializes redies and yields a block" do
|
24
|
+
PulseMeter.redis = nil
|
25
|
+
dummy.with_redis do
|
26
|
+
PulseMeter.redis.should_not be_nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#with_safe_restore_of" do
|
32
|
+
it "restores sensor by name and passes it to block" do
|
33
|
+
sensor = PulseMeter::Sensor::Counter.new(:foo)
|
34
|
+
dummy.with_safe_restore_of(:foo) do |s|
|
35
|
+
s.should be_instance_of(sensor.class)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it "prints error and exits if sensor cannot be restored" do
|
40
|
+
STDOUT.should_receive(:puts).with("Sensor nonexistant is unknown or cannot be restored")
|
41
|
+
lambda {dummy.with_safe_restore_of(:nonexistant) {|s| s}}.should raise_error(SystemExit)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#all_sensors" do
|
46
|
+
it "is just an alias to PulseMeter::Sensor::Timeline.list_objects" do
|
47
|
+
PulseMeter::Sensor::Timeline.should_receive(:list_objects)
|
48
|
+
dummy.all_sensors
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#all_sensors_table" do
|
53
|
+
before {PulseMeter.redis.flushall}
|
54
|
+
let(:init_values){ {:ttl => 1, :raw_data_ttl => 2, :interval => 3, :reduce_delay => 4} }
|
55
|
+
let!(:s1) {PulseMeter::Sensor::Counter.new(:s1)}
|
56
|
+
let!(:s2) {PulseMeter::Sensor::Timelined::Counter.new(:s2, init_values)}
|
57
|
+
let!(:table) {dummy.all_sensors_table}
|
58
|
+
let!(:csv) {dummy.all_sensors_table(:csv)}
|
59
|
+
let!(:parsed_csv) {CSV.parse(csv, col_sep: ";")}
|
60
|
+
|
61
|
+
def rows(format)
|
62
|
+
if "csv" == format.to_s
|
63
|
+
parsed_csv
|
64
|
+
else
|
65
|
+
table.rows.map do |row|
|
66
|
+
row.cells.map(&:to_s).map(&:strip)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def sensor_row(name, format)
|
72
|
+
rows(format).select {|row| row[0] == name}.first
|
73
|
+
end
|
74
|
+
|
75
|
+
[:csv, :table].each do |format|
|
76
|
+
context "when format is #{format}" do
|
77
|
+
|
78
|
+
if "csv" == format.to_s
|
79
|
+
it "returns csv as string" do
|
80
|
+
csv.should be_instance_of(String)
|
81
|
+
end
|
82
|
+
else
|
83
|
+
it "returns Terminal::Table instance" do
|
84
|
+
table.should be_instance_of(Terminal::Table)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
it "has title row" do
|
89
|
+
rows(format)[0].should == ["Name", "Class", "ttl", "raw data ttl", "interval", "reduce delay"]
|
90
|
+
end
|
91
|
+
|
92
|
+
it "has one row for each sensor (and a title)" do
|
93
|
+
rows(format).count.should == 3
|
94
|
+
end
|
95
|
+
|
96
|
+
it "can display timelined sensors" do
|
97
|
+
sensor_row("s2", format).should == [
|
98
|
+
s2.name, s2.class, s2.ttl, s2.raw_data_ttl, s2.interval, s2.reduce_delay
|
99
|
+
].map(&:to_s)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "can display static sensors" do
|
103
|
+
sensor_row("s1", format).should == [
|
104
|
+
s1.name, s1.class, "", "", "", ""
|
105
|
+
].map(&:to_s)
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
@@ -15,6 +15,10 @@ describe PulseMeter::Sensor::HashedCounter do
|
|
15
15
|
expect{ sensor.event({"foo" => 10.4}) }.to change{ sensor.value["foo"] }.from(0).to(10)
|
16
16
|
expect{ sensor.event({"foo" => 15.1}) }.to change{ sensor.value["foo"] }.from(10).to(25)
|
17
17
|
end
|
18
|
+
|
19
|
+
it "should increment total value" do
|
20
|
+
expect{ sensor.event({"foo" => 1, "bar" => 2}) }.to change{sensor.value["total"]}.from(0).to(3)
|
21
|
+
end
|
18
22
|
end
|
19
23
|
|
20
24
|
describe "#value" do
|
@@ -24,8 +28,8 @@ describe PulseMeter::Sensor::HashedCounter do
|
|
24
28
|
|
25
29
|
it "should store redis hash by value_key" do
|
26
30
|
sensor.event({"foo" => 1})
|
27
|
-
sensor.value.should == {"foo" => 1}
|
28
|
-
redis.hgetall(sensor.value_key).should == {"foo" => "1"}
|
31
|
+
sensor.value.should == {"foo" => 1, "total" => 1}
|
32
|
+
redis.hgetall(sensor.value_key).should == {"foo" => "1", "total" => "1"}
|
29
33
|
end
|
30
34
|
end
|
31
35
|
|
@@ -2,7 +2,7 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe PulseMeter::Sensor::Timelined::HashedCounter do
|
4
4
|
it_should_behave_like "timeline sensor", {}, {:foo => 1}
|
5
|
-
it_should_behave_like "timelined subclass", [{:foo => 1}, {:foo => 2}], {:foo => 3}.to_json
|
6
|
-
it_should_behave_like "timelined subclass", [{:foo => 1}, {:foo => :bad_value}], {:foo => 1}.to_json
|
7
|
-
it_should_behave_like "timelined subclass", [{:foo => 1}, {:boo => 2}], {:foo => 1, :boo => 2}.to_json
|
5
|
+
it_should_behave_like "timelined subclass", [{:foo => 1}, {:foo => 2}], {:foo => 3, :total => 3}.to_json
|
6
|
+
it_should_behave_like "timelined subclass", [{:foo => 1}, {:foo => :bad_value}], {:foo => 1, :total => 1}.to_json
|
7
|
+
it_should_behave_like "timelined subclass", [{:foo => 1}, {:boo => 2}], {:foo => 1, :boo => 2, :total => 3}.to_json
|
8
8
|
end
|
@@ -242,12 +242,32 @@ shared_examples_for "timeline sensor" do |extra_init_values, default_event|
|
|
242
242
|
end
|
243
243
|
end
|
244
244
|
|
245
|
-
|
246
|
-
max
|
247
|
-
(1..10).each do |i|
|
248
|
-
timespan = sensor.interval * max * (2**i)
|
249
|
-
sensor.timeline_within(Time.now, Time.now - timespan).size.should < max
|
245
|
+
context "to avoid getting to much data" do
|
246
|
+
let(:max) {PulseMeter::Sensor::Timeline::MAX_TIMESPAN_POINTS}
|
250
247
|
|
248
|
+
it "should skip some points not to exceed MAX_TIMESPAN_POINTS" do
|
249
|
+
count = max * 2
|
250
|
+
sensor.timeline_within(
|
251
|
+
Time.at(@start_of_interval - 1),
|
252
|
+
Time.at(@start_of_interval + count * interval)
|
253
|
+
).size.should < max
|
254
|
+
end
|
255
|
+
|
256
|
+
it "should not skip any points when timeline orginal size is less then MAX_TIMESPAN_POINTS" do
|
257
|
+
count = max - 1
|
258
|
+
sensor.timeline_within(
|
259
|
+
Time.at(@start_of_interval - 1),
|
260
|
+
Time.at(@start_of_interval + count * interval)
|
261
|
+
).size.should == count
|
262
|
+
end
|
263
|
+
|
264
|
+
it "should give full data in case skip_optimization parameter set to true" do
|
265
|
+
count = max * 2
|
266
|
+
sensor.timeline_within(
|
267
|
+
Time.at(@start_of_interval - 1),
|
268
|
+
Time.at(@start_of_interval + count * interval),
|
269
|
+
true
|
270
|
+
).size.should == count
|
251
271
|
end
|
252
272
|
end
|
253
273
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pulse-meter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.8
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-08-02 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: gon-sinatra
|
@@ -333,6 +333,7 @@ files:
|
|
333
333
|
- examples/server_config.yml
|
334
334
|
- lib/cmd.rb
|
335
335
|
- lib/pulse-meter.rb
|
336
|
+
- lib/pulse-meter/extensions/enumerable.rb
|
336
337
|
- lib/pulse-meter/mixins/cmd.rb
|
337
338
|
- lib/pulse-meter/mixins/dumper.rb
|
338
339
|
- lib/pulse-meter/mixins/utils.rb
|
@@ -405,6 +406,8 @@ files:
|
|
405
406
|
- lib/pulse-meter/visualize/widgets/timeline.rb
|
406
407
|
- lib/pulse-meter/visualizer.rb
|
407
408
|
- pulse-meter.gemspec
|
409
|
+
- spec/pulse_meter/extensions/enumerable_spec.rb
|
410
|
+
- spec/pulse_meter/mixins/cmd_spec.rb
|
408
411
|
- spec/pulse_meter/mixins/dumper_spec.rb
|
409
412
|
- spec/pulse_meter/mixins/utils_spec.rb
|
410
413
|
- spec/pulse_meter/sensor/base_spec.rb
|
@@ -472,7 +475,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
472
475
|
version: '0'
|
473
476
|
segments:
|
474
477
|
- 0
|
475
|
-
hash: -
|
478
|
+
hash: -2299028715226414900
|
476
479
|
requirements: []
|
477
480
|
rubyforge_project:
|
478
481
|
rubygems_version: 1.8.24
|
@@ -481,6 +484,8 @@ specification_version: 3
|
|
481
484
|
summary: Lightweight Redis-based metrics aggregator and processor with CLI and simple
|
482
485
|
and customizable WEB interfaces
|
483
486
|
test_files:
|
487
|
+
- spec/pulse_meter/extensions/enumerable_spec.rb
|
488
|
+
- spec/pulse_meter/mixins/cmd_spec.rb
|
484
489
|
- spec/pulse_meter/mixins/dumper_spec.rb
|
485
490
|
- spec/pulse_meter/mixins/utils_spec.rb
|
486
491
|
- spec/pulse_meter/sensor/base_spec.rb
|