pulse-meter 0.1.6 → 0.1.7

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/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