pulse-meter 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
data/examples/basic.ru CHANGED
@@ -26,7 +26,7 @@ layout = PulseMeter::Visualizer.draw do |l|
26
26
  c.timespan 1200
27
27
  end
28
28
 
29
- p.spline "Rhino & Lama count comparison" do |c|
29
+ p.spline "Rhino & Lama & Goose count comparison" do |c|
30
30
  c.redraw_interval 5
31
31
  c.values_label 'Count'
32
32
  c.width 5
@@ -35,9 +35,10 @@ layout = PulseMeter::Visualizer.draw do |l|
35
35
 
36
36
  c.sensor :rhino_count, color: '#AAAAAA'
37
37
  c.sensor :lama_count, color: '#CC1155'
38
+ c.sensor :goose_count
38
39
  end
39
40
 
40
- p.pie "Rhino & Lama count comparison" do |c|
41
+ p.pie "Rhino & Lama & Gooze count comparison" do |c|
41
42
  c.redraw_interval 5
42
43
  c.values_label 'Count'
43
44
  c.width 5
@@ -46,6 +47,7 @@ layout = PulseMeter::Visualizer.draw do |l|
46
47
 
47
48
  c.sensor :rhino_count, color: '#AAAAAA'
48
49
  c.sensor :lama_count, color: '#CC1155'
50
+ c.sensor :goose_count
49
51
  end
50
52
 
51
53
  end
@@ -22,6 +22,12 @@ rhino_counter = PulseMeter::Sensor::Timelined::Counter.new(:rhino_count,
22
22
  ttl: 3600
23
23
  )
24
24
 
25
+ goose_counter = PulseMeter::Sensor::Timelined::HashedCounter.new(:goose_count,
26
+ annotation: 'Goose Count',
27
+ interval: 10,
28
+ ttl: 3600
29
+ )
30
+
25
31
  rhino_average_age = PulseMeter::Sensor::Timelined::Average.new(:rhino_average_age,
26
32
  annotation: 'Rhino average age',
27
33
  interval: 20,
@@ -35,4 +41,9 @@ while true
35
41
  rhino_counter.event(2)
36
42
  lama_average_age.event(Random.rand(50))
37
43
  rhino_average_age.event(Random.rand(100))
44
+
45
+ 10.times do
46
+ goose_n = Random.rand(4)
47
+ goose_counter.event("goose_#{goose_n}" => 1)
48
+ end
38
49
  end
@@ -1,3 +1,3 @@
1
1
  module PulseMeter
2
- VERSION = "0.1.6"
2
+ VERSION = "0.1.7"
3
3
  end
@@ -1,3 +1,5 @@
1
+ require "pulse-meter/visualize/series_extractor"
2
+
1
3
  module PulseMeter
2
4
  module Visualize
3
5
  class Sensor
@@ -6,7 +8,7 @@ module PulseMeter
6
8
 
7
9
  def initialize(args)
8
10
  raise ArgumentError unless args.respond_to?('[]')
9
- @name = args[:sensor] or raise ArgumentError, ":sensor_name not specified"
11
+ @name = args[:sensor] or raise ArgumentError, ":sensor not specified"
10
12
  @color = args[:color]
11
13
  end
12
14
 
@@ -27,24 +29,26 @@ module PulseMeter
27
29
  end
28
30
 
29
31
  def last_point_data(need_incomplete=false)
30
- res = {
31
- name: real_sensor.annotation,
32
- y: to_float(last_value(need_incomplete))
33
- }
34
- res[:color] = color if color
35
- res
32
+ extractor.point_data(last_value(need_incomplete))
36
33
  end
37
34
 
38
35
  def timeline_data(time_span, need_incomplete = false)
39
36
  sensor = real_sensor
40
- data = sensor.timeline(time_span).map{|sd| {x: sd.start_time.to_i*1000, y: to_float(sd.value)}}
41
- data.pop unless need_incomplete
42
- res = {
43
- name: sensor.annotation,
44
- data: data
45
- }
46
- res[:color] = color if color
47
- res
37
+ timeline_data = sensor.timeline(time_span)
38
+ timeline_data.pop unless need_incomplete
39
+ extractor.series_data(timeline_data)
40
+ end
41
+
42
+ def annotation
43
+ real_sensor.annotation
44
+ end
45
+
46
+ def type
47
+ real_sensor.class
48
+ end
49
+
50
+ def extractor
51
+ PulseMeter::Visualize.extractor(self)
48
52
  end
49
53
 
50
54
  protected
@@ -54,9 +58,6 @@ module PulseMeter
54
58
  PulseMeter::Sensor::Base.restore(@name)
55
59
  end
56
60
 
57
- def to_float(val)
58
- val && val.to_f
59
- end
60
61
 
61
62
  end
62
63
  end
@@ -0,0 +1,96 @@
1
+ module PulseMeter
2
+ module Visualize
3
+ module SeriesExtractor
4
+ class Simple
5
+ def initialize(sensor)
6
+ @sensor = sensor
7
+ end
8
+
9
+ def opts_to_add
10
+ opts = {}
11
+ opts[:color] = @sensor.color if @sensor.color
12
+ opts[:name] = @sensor.annotation
13
+ opts
14
+ end
15
+
16
+ def series_data(timeline_data)
17
+ {
18
+ data: timeline_data.map{|sd| {x: sd.start_time.to_i*1000, y: to_float(sd.value)}}
19
+ }.merge(opts_to_add)
20
+ end
21
+
22
+ def point_data(value)
23
+ {
24
+ y: to_float(value)
25
+ }.merge(opts_to_add)
26
+ end
27
+
28
+ protected
29
+
30
+ def to_float(val)
31
+ val && val.to_f
32
+ end
33
+ end
34
+
35
+
36
+ class Hashed < Simple
37
+
38
+ def parse_data(value)
39
+ if value
40
+ if value.is_a?(String)
41
+ JSON.parse(value)
42
+ else
43
+ value
44
+ end
45
+ else
46
+ {}
47
+ end
48
+ end
49
+
50
+ def point_data(value)
51
+ data = parse_data(value)
52
+ data.keys.map do |k|
53
+ {
54
+ y: to_float(data[k]),
55
+ name: k
56
+ }
57
+ end
58
+ end
59
+
60
+ def series_data(timeline_data)
61
+ series_data = {}
62
+ parsed_data = timeline_data.map do |sd|
63
+ data = parse_data(sd.value)
64
+ data.keys.each{|k| series_data[k] ||= {name: k, data: []}}
65
+ [sd.start_time.to_i*1000, data]
66
+ end
67
+
68
+ series_names = series_data.keys.sort
69
+ parsed_data.each do |data|
70
+ series_names.each do |k|
71
+ series_data[k][:data] << {x: data[0], y: to_float(data[1][k])}
72
+ end
73
+ end
74
+ series_data.values
75
+ end
76
+ end
77
+ end
78
+
79
+ SPECIAL_SERIES_EXTRACTORS = {
80
+ 'HashedCounter' => SeriesExtractor::Hashed
81
+ }.freeze
82
+
83
+ DEFAULT_SERIES_EXTRACTOR = SeriesExtractor::Simple
84
+
85
+ def extractor(sensor)
86
+ key = sensor.type.to_s.split('::').last
87
+ extractor_class = SPECIAL_SERIES_EXTRACTORS[key] || DEFAULT_SERIES_EXTRACTOR
88
+ extractor_class.new(sensor)
89
+ end
90
+
91
+ module_function :extractor
92
+
93
+ end
94
+ end
95
+
96
+
@@ -51,16 +51,14 @@ module PulseMeter
51
51
  end
52
52
 
53
53
  def line_series_data(tspan)
54
- sensors.map do |s|
55
- s.timeline_data(tspan, show_last_point)
56
- end
54
+ sensors.map{ |s| s.timeline_data(tspan, show_last_point) }.flatten(1)
57
55
  end
58
56
 
59
57
  def pie_series_data
60
58
  [{
61
59
  type: type,
62
60
  name: values_label,
63
- data: sensors.map{|s| s.last_point_data(show_last_point)}
61
+ data: sensors.map{|s| s.last_point_data(show_last_point)}.flatten(1)
64
62
  }]
65
63
  end
66
64
 
@@ -0,0 +1,80 @@
1
+ require "spec_helper"
2
+
3
+ describe PulseMeter::Visualize::SeriesExtractor do
4
+ let(:interval){ 100 }
5
+ let!(:real_simple_sensor){ PulseMeter::Sensor::Timelined::Counter.new(:simple_sensor,
6
+ ttl: 1000,
7
+ interval: interval,
8
+ annotation: 'simple sensor'
9
+ ) }
10
+ let!(:real_hashed_sensor){ PulseMeter::Sensor::Timelined::HashedCounter.new(:hashed_sensor,
11
+ ttl: 1000,
12
+ interval: interval,
13
+ annotation: 'hashed sensor'
14
+ ) }
15
+
16
+ let!(:simple_sensor){PulseMeter::Visualize::Sensor.new(sensor: :simple_sensor)}
17
+ let!(:hashed_sensor){PulseMeter::Visualize::Sensor.new(sensor: :hashed_sensor)}
18
+
19
+ describe "simple extractor" do
20
+
21
+ let(:extractor) {PulseMeter::Visualize.extractor(simple_sensor)}
22
+
23
+ it "should be created for simple sensors" do
24
+ extractor.should be_kind_of(PulseMeter::Visualize::SeriesExtractor::Simple)
25
+ end
26
+
27
+ it "should create point data correctly" do
28
+ extractor.point_data(123).should == {y: 123, name: 'simple sensor'}
29
+ end
30
+
31
+ it "should create timeline data correctly" do
32
+ tl_data = [
33
+ PulseMeter::SensorData.new(Time.at(1), 11),
34
+ PulseMeter::SensorData.new(Time.at(2), "22")
35
+ ]
36
+ extractor.series_data(tl_data).should == {
37
+ name: 'simple sensor',
38
+ data: [{x: 1000, y: 11}, {x: 2000, y: 22}]
39
+ }
40
+ end
41
+
42
+ end
43
+
44
+ describe "hash extractor" do
45
+ let(:extractor) {PulseMeter::Visualize.extractor(hashed_sensor)}
46
+
47
+ it "should be created for hash sensors" do
48
+ extractor.should be_kind_of(PulseMeter::Visualize::SeriesExtractor::Hashed)
49
+ end
50
+
51
+ it "should create point data correctly" do
52
+ extractor.point_data('{"x": 123, "y": 321}').should == [
53
+ {y: 123, name: 'x'},
54
+ {y: 321, name: 'y'}
55
+ ]
56
+ end
57
+
58
+ it "should create timeline data correctly" do
59
+ tl_data = [
60
+ PulseMeter::SensorData.new(Time.at(1), {"a" => 5, "b" => 6}),
61
+ PulseMeter::SensorData.new(Time.at(2), '{"c": 7, "b": 6}')
62
+ ]
63
+ extractor.series_data(tl_data).should == [
64
+ {
65
+ name: 'a',
66
+ data: [{x: 1000, y: 5}, {x: 2000, y: nil}]
67
+ },
68
+ {
69
+ name: 'b',
70
+ data: [{x: 1000, y: 6}, {x: 2000, y: 6}]
71
+ },
72
+ {
73
+ name: 'c',
74
+ data: [{x: 1000, y: nil}, {x: 2000, y: 7}]
75
+ }
76
+ ]
77
+ end
78
+ end
79
+
80
+ 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.1.6
4
+ version: 0.1.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -339,6 +339,7 @@ files:
339
339
  - lib/pulse-meter/visualize/public/js/json2.js
340
340
  - lib/pulse-meter/visualize/public/js/underscore-min.js
341
341
  - lib/pulse-meter/visualize/sensor.rb
342
+ - lib/pulse-meter/visualize/series_extractor.rb
342
343
  - lib/pulse-meter/visualize/views/main.haml
343
344
  - lib/pulse-meter/visualize/widget.rb
344
345
  - lib/pulse-meter/visualizer.rb
@@ -365,6 +366,7 @@ files:
365
366
  - spec/pulse_meter/visualize/layout_spec.rb
366
367
  - spec/pulse_meter/visualize/page_spec.rb
367
368
  - spec/pulse_meter/visualize/sensor_spec.rb
369
+ - spec/pulse_meter/visualize/series_extractor_spec.rb
368
370
  - spec/pulse_meter/visualize/widget_spec.rb
369
371
  - spec/pulse_meter/visualizer_spec.rb
370
372
  - spec/pulse_meter_spec.rb
@@ -420,6 +422,7 @@ test_files:
420
422
  - spec/pulse_meter/visualize/layout_spec.rb
421
423
  - spec/pulse_meter/visualize/page_spec.rb
422
424
  - spec/pulse_meter/visualize/sensor_spec.rb
425
+ - spec/pulse_meter/visualize/series_extractor_spec.rb
423
426
  - spec/pulse_meter/visualize/widget_spec.rb
424
427
  - spec/pulse_meter/visualizer_spec.rb
425
428
  - spec/pulse_meter_spec.rb