pulse_meter_visualizer 0.4.11

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.
Files changed (124) hide show
  1. data/.gitignore +19 -0
  2. data/.rbenv-version +1 -0
  3. data/.rspec +1 -0
  4. data/.rvmrc +1 -0
  5. data/.travis.yml +8 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +22 -0
  8. data/Procfile +3 -0
  9. data/README.md +40 -0
  10. data/Rakefile +72 -0
  11. data/examples/basic.ru +145 -0
  12. data/examples/basic_sensor_data.rb +96 -0
  13. data/lib/pulse_meter/visualize/app.rb +78 -0
  14. data/lib/pulse_meter/visualize/base.rb +15 -0
  15. data/lib/pulse_meter/visualize/coffee/application.coffee +40 -0
  16. data/lib/pulse_meter/visualize/coffee/collections/page_info_list.coffee +17 -0
  17. data/lib/pulse_meter/visualize/coffee/collections/sensor_info_list.coffee +4 -0
  18. data/lib/pulse_meter/visualize/coffee/collections/widget_list.coffee +14 -0
  19. data/lib/pulse_meter/visualize/coffee/extensions.coffee +26 -0
  20. data/lib/pulse_meter/visualize/coffee/models/dinamic_widget.coffee +34 -0
  21. data/lib/pulse_meter/visualize/coffee/models/page_info.coffee +2 -0
  22. data/lib/pulse_meter/visualize/coffee/models/sensor_info.coffee +2 -0
  23. data/lib/pulse_meter/visualize/coffee/models/widget.coffee +54 -0
  24. data/lib/pulse_meter/visualize/coffee/presenters/area.coffee +2 -0
  25. data/lib/pulse_meter/visualize/coffee/presenters/gauge.coffee +11 -0
  26. data/lib/pulse_meter/visualize/coffee/presenters/line.coffee +2 -0
  27. data/lib/pulse_meter/visualize/coffee/presenters/pie.coffee +20 -0
  28. data/lib/pulse_meter/visualize/coffee/presenters/series.coffee +44 -0
  29. data/lib/pulse_meter/visualize/coffee/presenters/table.coffee +10 -0
  30. data/lib/pulse_meter/visualize/coffee/presenters/timeline.coffee +13 -0
  31. data/lib/pulse_meter/visualize/coffee/presenters/widget.coffee +65 -0
  32. data/lib/pulse_meter/visualize/coffee/router.coffee +21 -0
  33. data/lib/pulse_meter/visualize/coffee/views/dynamic_chart.coffee +91 -0
  34. data/lib/pulse_meter/visualize/coffee/views/dynamic_widget.coffee +58 -0
  35. data/lib/pulse_meter/visualize/coffee/views/page_title.coffee +17 -0
  36. data/lib/pulse_meter/visualize/coffee/views/page_titles.coffee +15 -0
  37. data/lib/pulse_meter/visualize/coffee/views/sensor_info_list.coffee +19 -0
  38. data/lib/pulse_meter/visualize/coffee/views/widget.coffee +99 -0
  39. data/lib/pulse_meter/visualize/coffee/views/widget_chart.coffee +13 -0
  40. data/lib/pulse_meter/visualize/coffee/views/widget_list.coffee +15 -0
  41. data/lib/pulse_meter/visualize/dsl/base.rb +131 -0
  42. data/lib/pulse_meter/visualize/dsl/errors.rb +40 -0
  43. data/lib/pulse_meter/visualize/dsl/layout.rb +27 -0
  44. data/lib/pulse_meter/visualize/dsl/page.rb +33 -0
  45. data/lib/pulse_meter/visualize/dsl/sensor.rb +20 -0
  46. data/lib/pulse_meter/visualize/dsl/widget.rb +37 -0
  47. data/lib/pulse_meter/visualize/dsl/widgets/area.rb +20 -0
  48. data/lib/pulse_meter/visualize/dsl/widgets/gauge.rb +12 -0
  49. data/lib/pulse_meter/visualize/dsl/widgets/line.rb +21 -0
  50. data/lib/pulse_meter/visualize/dsl/widgets/pie.rb +16 -0
  51. data/lib/pulse_meter/visualize/dsl/widgets/table.rb +19 -0
  52. data/lib/pulse_meter/visualize/layout.rb +79 -0
  53. data/lib/pulse_meter/visualize/page.rb +25 -0
  54. data/lib/pulse_meter/visualize/public/css/application.css +56 -0
  55. data/lib/pulse_meter/visualize/public/css/bootstrap.css +4883 -0
  56. data/lib/pulse_meter/visualize/public/css/bootstrap.min.css +729 -0
  57. data/lib/pulse_meter/visualize/public/css/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  58. data/lib/pulse_meter/visualize/public/css/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  59. data/lib/pulse_meter/visualize/public/css/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  60. data/lib/pulse_meter/visualize/public/css/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  61. data/lib/pulse_meter/visualize/public/css/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  62. data/lib/pulse_meter/visualize/public/css/images/ui-bg_glass_75_ffffff_1x400.png +0 -0
  63. data/lib/pulse_meter/visualize/public/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  64. data/lib/pulse_meter/visualize/public/css/images/ui-bg_inset-soft_95_fef1ec_1x100.png +0 -0
  65. data/lib/pulse_meter/visualize/public/css/images/ui-icons_222222_256x240.png +0 -0
  66. data/lib/pulse_meter/visualize/public/css/images/ui-icons_2e83ff_256x240.png +0 -0
  67. data/lib/pulse_meter/visualize/public/css/images/ui-icons_454545_256x240.png +0 -0
  68. data/lib/pulse_meter/visualize/public/css/images/ui-icons_888888_256x240.png +0 -0
  69. data/lib/pulse_meter/visualize/public/css/images/ui-icons_cd0a0a_256x240.png +0 -0
  70. data/lib/pulse_meter/visualize/public/css/images/ui-icons_f6cf3b_256x240.png +0 -0
  71. data/lib/pulse_meter/visualize/public/css/jquery-ui-1.8.16.bootstrap.css +1320 -0
  72. data/lib/pulse_meter/visualize/public/favicon.ico +208 -0
  73. data/lib/pulse_meter/visualize/public/img/glyphicons-halflings-white.png +0 -0
  74. data/lib/pulse_meter/visualize/public/img/glyphicons-halflings.png +0 -0
  75. data/lib/pulse_meter/visualize/public/js/application.js +973 -0
  76. data/lib/pulse_meter/visualize/public/js/backbone-min.js +38 -0
  77. data/lib/pulse_meter/visualize/public/js/bootstrap.js +1835 -0
  78. data/lib/pulse_meter/visualize/public/js/jquery-1.7.2.min.js +4 -0
  79. data/lib/pulse_meter/visualize/public/js/jquery-ui-1.8.16.bootstrap.min.js +791 -0
  80. data/lib/pulse_meter/visualize/public/js/jquery-ui-1.8.23.custom.min.js +21 -0
  81. data/lib/pulse_meter/visualize/public/js/jquery-ui-timepicker-addon.js +1687 -0
  82. data/lib/pulse_meter/visualize/public/js/json2.js +487 -0
  83. data/lib/pulse_meter/visualize/public/js/underscore-min.js +32 -0
  84. data/lib/pulse_meter/visualize/sensor.rb +63 -0
  85. data/lib/pulse_meter/visualize/series_extractor.rb +107 -0
  86. data/lib/pulse_meter/visualize/views/main.haml +30 -0
  87. data/lib/pulse_meter/visualize/views/sensors.haml +76 -0
  88. data/lib/pulse_meter/visualize/views/widgets/area.haml +53 -0
  89. data/lib/pulse_meter/visualize/views/widgets/extend_options.haml +11 -0
  90. data/lib/pulse_meter/visualize/views/widgets/gauge.haml +13 -0
  91. data/lib/pulse_meter/visualize/views/widgets/line.haml +54 -0
  92. data/lib/pulse_meter/visualize/views/widgets/pie.haml +13 -0
  93. data/lib/pulse_meter/visualize/views/widgets/table.haml +45 -0
  94. data/lib/pulse_meter/visualize/widget.rb +38 -0
  95. data/lib/pulse_meter/visualize/widgets/gauge.rb +47 -0
  96. data/lib/pulse_meter/visualize/widgets/pie.rb +36 -0
  97. data/lib/pulse_meter/visualize/widgets/timeline.rb +114 -0
  98. data/lib/pulse_meter/visualizer.rb +38 -0
  99. data/lib/pulse_meter_visualizer.rb +2 -0
  100. data/pulse_meter_visualizer.gemspec +41 -0
  101. data/spec/pulse_meter/visualize/app_spec.rb +27 -0
  102. data/spec/pulse_meter/visualize/dsl/layout_spec.rb +64 -0
  103. data/spec/pulse_meter/visualize/dsl/page_spec.rb +62 -0
  104. data/spec/pulse_meter/visualize/dsl/sensor_spec.rb +30 -0
  105. data/spec/pulse_meter/visualize/dsl/widget_spec.rb +6 -0
  106. data/spec/pulse_meter/visualize/dsl/widgets/area_spec.rb +44 -0
  107. data/spec/pulse_meter/visualize/dsl/widgets/gauge_spec.rb +22 -0
  108. data/spec/pulse_meter/visualize/dsl/widgets/line_spec.rb +44 -0
  109. data/spec/pulse_meter/visualize/dsl/widgets/pie_spec.rb +35 -0
  110. data/spec/pulse_meter/visualize/dsl/widgets/table_spec.rb +36 -0
  111. data/spec/pulse_meter/visualize/layout_spec.rb +54 -0
  112. data/spec/pulse_meter/visualize/page_spec.rb +153 -0
  113. data/spec/pulse_meter/visualize/sensor_spec.rb +120 -0
  114. data/spec/pulse_meter/visualize/series_extractor_spec.rb +80 -0
  115. data/spec/pulse_meter/visualize/widgets/area_spec.rb +6 -0
  116. data/spec/pulse_meter/visualize/widgets/gauge_spec.rb +63 -0
  117. data/spec/pulse_meter/visualize/widgets/line_spec.rb +6 -0
  118. data/spec/pulse_meter/visualize/widgets/pie_spec.rb +73 -0
  119. data/spec/pulse_meter/visualize/widgets/table_spec.rb +6 -0
  120. data/spec/pulse_meter/visualizer_spec.rb +42 -0
  121. data/spec/shared_examples/dsl_widget.rb +106 -0
  122. data/spec/shared_examples/widget.rb +97 -0
  123. data/spec/spec_helper.rb +36 -0
  124. metadata +518 -0
@@ -0,0 +1,13 @@
1
+ %script.widget-template{type: 'text/template', 'data-widget-type' => 'pie'}
2
+ #plotarea
3
+ #chart-controls
4
+ .form-inline
5
+ %button#refresh.btn.btn-mini
6
+ %i.icon-refresh
7
+ Refresh
8
+ %span.space
9
+ %label
10
+ Refresh:
11
+ %input.btn-mini#need-refresh{type: :checkbox, checked: :true}
12
+ %hr
13
+
@@ -0,0 +1,45 @@
1
+ %script.widget-template{type: 'text/template', 'data-widget-type' => 'table'}
2
+ #plotarea
3
+ #chart-controls
4
+ .form-inline
5
+ %button#refresh.btn.btn-mini
6
+ %i.icon-refresh
7
+ Refresh
8
+ %a#configure-button.btn.btn-mini{href: "#configure", role: 'button', 'data-toggle' => 'modal'}
9
+ %i.icon-wrench
10
+ Configure...
11
+ .modal.hide.fade#configure
12
+ .modal-header
13
+ %button.close{type: 'button', 'data-dismiss' => 'modal', 'aria-hidden' => 'true'} ×
14
+ %h3 Configure
15
+ .modal-body
16
+ %p
17
+ %label
18
+ Refresh:
19
+ %input.btn-mini#need-refresh{type: :checkbox, checked: :true}
20
+ %hr
21
+ %p
22
+ %label
23
+ Timespan:
24
+ %select#extend-timespan-val.btn-mini.span3
25
+ = partial "widgets/extend_options"
26
+ %button#extend-timespan.btn.btn-mini
27
+ %i.icon-arrow-left
28
+ Extend
29
+ %button#reset-timespan.btn.btn-mini
30
+ %i.icon-arrow-right
31
+ Reset
32
+ %hr
33
+ %p
34
+ %label
35
+ From:
36
+ %span#start-time
37
+ %input.datepicker
38
+ %label
39
+ Till:
40
+ %span#end-time
41
+ %input.datepicker
42
+ %button#set-interval.btn.btn-mini
43
+ %i.icon-time
44
+ Set interval
45
+
@@ -0,0 +1,38 @@
1
+ module PulseMeter
2
+ module Visualize
3
+ class Error < StandardError; end
4
+
5
+ class Widget < Base
6
+ def initialize(opts)
7
+ super
8
+ @opts[:sensors] ||= []
9
+ end
10
+
11
+ def data
12
+ {
13
+ type: type,
14
+ title: title,
15
+ redraw_interval: redraw_interval,
16
+ width: width,
17
+ gchart_options: gchart_options,
18
+ values_title: values_label
19
+ }
20
+ end
21
+
22
+ def type
23
+ self.class.to_s.split('::').last.downcase
24
+ end
25
+
26
+ protected
27
+
28
+ def gauge_series_data
29
+ ensure_gauge_indicators!
30
+ sensors.map do |s|
31
+ [s.annotation, s.value]
32
+ end
33
+ end
34
+
35
+ end
36
+ end
37
+ end
38
+
@@ -0,0 +1,47 @@
1
+ module PulseMeter
2
+ module Visualize
3
+ module Widgets
4
+ class Gauge < PulseMeter::Visualize::Widget
5
+ class NotAnIndicatorSensorInGaugeWidget < PulseMeter::Visualize::Error; end
6
+
7
+ def data(options = {})
8
+ super().merge({
9
+ series: values_data
10
+ })
11
+ end
12
+
13
+ protected
14
+
15
+ def ensure_gauge_indicators!
16
+ sensors.each do |s|
17
+ unless s.type <= PulseMeter::Sensor::Indicator || s.type <= PulseMeter::Sensor::HashedIndicator
18
+ raise NotAnIndicatorSensorInGaugeWidget, "Sensor #{s.name} is not an indicator(PulseMeter::Sensor::Indicator or PulseMeter::Sensor::HashedIndicator)"
19
+ end
20
+ end
21
+ end
22
+
23
+ def values_data
24
+ ensure_gauge_indicators!
25
+ gauges = []
26
+ sensors.map do |s|
27
+ s_type = s.type
28
+ case
29
+ when s_type == PulseMeter::Sensor::Indicator
30
+ gauges << [s.annotation, s.value]
31
+ when s_type == PulseMeter::Sensor::HashedIndicator
32
+ s.value.each_pair do |k, v|
33
+ gauge_title = "#{s.annotation}: #{k}"
34
+ gauges << [gauge_title, v]
35
+ end
36
+ end
37
+ end
38
+ gauges
39
+ end
40
+
41
+ end
42
+ end
43
+
44
+ end
45
+ end
46
+
47
+
@@ -0,0 +1,36 @@
1
+ module PulseMeter
2
+ module Visualize
3
+ module Widgets
4
+ class Pie < PulseMeter::Visualize::Widget
5
+
6
+ def data(options = {})
7
+ super().merge({
8
+ series: slice_data
9
+ })
10
+ end
11
+
12
+ protected
13
+
14
+ def slice_data
15
+ values = []
16
+ slice_options = []
17
+ now = Time.now
18
+ sensors.each do |s|
19
+ s.last_point_data(now, show_last_point).each do |point_data|
20
+ values << [point_data[:name], point_data[:y]]
21
+ slice_options << {color: point_data[:color]}
22
+ end
23
+ end
24
+ {
25
+ data: values,
26
+ options: slice_options
27
+ }
28
+ end
29
+
30
+ end
31
+ end
32
+
33
+ end
34
+ end
35
+
36
+
@@ -0,0 +1,114 @@
1
+ module PulseMeter
2
+ module Visualize
3
+ module Widgets
4
+ class Error < StandardError; end
5
+ class Timeline < PulseMeter::Visualize::Widget
6
+
7
+ class NotATimelinedSensorInWidget < PulseMeter::Visualize::Error; end
8
+ class DifferentSensorIntervalsInWidget < PulseMeter::Visualize::Error; end
9
+
10
+ DEFAULT_TIMESPAN = 3600
11
+
12
+ def initialize(opts)
13
+ super
14
+ opts[:timespan] ||= DEFAULT_TIMESPAN
15
+ end
16
+
17
+ def data(options = {})
18
+ from, till = get_interval_borders(options)
19
+ super().merge({
20
+ values_title: values_label,
21
+ series: series_data(from, till),
22
+ timespan: timespan,
23
+ interval: interval
24
+ })
25
+ end
26
+
27
+ protected
28
+
29
+ def get_interval_borders(options)
30
+ from = if options[:start_time] && (options[:start_time] > 0)
31
+ Time.at options[:start_time]
32
+ else
33
+ tspan = options[:timespan] || timespan
34
+ Time.now - tspan
35
+ end
36
+
37
+ till = if options[:end_time] && (options[:end_time] > 0)
38
+ Time.at options[:end_time]
39
+ else
40
+ Time.now
41
+ end
42
+ [from, till]
43
+ end
44
+
45
+ def series_data(from, till)
46
+ ensure_equal_intervals!
47
+ sensor_datas = sensors.map{ |s|
48
+ s.timeline_data(from, till, show_last_point)
49
+ }
50
+ rows = []
51
+ titles = []
52
+ series_options = []
53
+ datas = []
54
+ sensor_datas.each do |sensor_data|
55
+ sensor_data.each do |tl|
56
+ titles << tl[:name]
57
+ series_options << {color: tl[:color]}
58
+ datas << tl[:data]
59
+ end
60
+ end
61
+ unless datas.empty?
62
+ first = datas.shift
63
+ first.each_with_index do |tl_data, row_num|
64
+ rows << datas.each_with_object([tl_data[:x], tl_data[:y]]) do |data_col, row|
65
+ row << data_col[row_num][:y]
66
+ end
67
+ end
68
+ end
69
+ {
70
+ titles: titles,
71
+ rows: rows,
72
+ options: series_options
73
+ }
74
+ end
75
+
76
+ def ensure_equal_intervals!
77
+ intervals = []
78
+ sensors.each do |s|
79
+ unless s.type < PulseMeter::Sensor::Timeline
80
+ raise NotATimelinedSensorInWidget, "sensor `#{s.name}' is not timelined"
81
+ end
82
+ intervals << s.interval
83
+ end
84
+
85
+ unless intervals.all?{|i| i == intervals.first}
86
+ interval_notice = sensors.map{|s| "#{s.name}: #{s.interval}"}.join(', ')
87
+ raise DifferentSensorIntervalsInWidget, "Sensors with different intervals in a single widget: #{interval_notice}"
88
+ end
89
+ end
90
+
91
+ def interval
92
+ if sensors.empty?
93
+ nil
94
+ else
95
+ sensors.first.interval
96
+ end
97
+ end
98
+
99
+ end
100
+
101
+ class Area < Timeline; end
102
+ class Line < Timeline; end
103
+
104
+ class Table < Timeline
105
+ def data(options = {})
106
+ res = super(options)
107
+ res[:series].delete(options)
108
+ res
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+
@@ -0,0 +1,38 @@
1
+ # Visualize
2
+
3
+ require 'pulse_meter/visualize/base'
4
+ require 'pulse_meter/visualize/sensor'
5
+ require 'pulse_meter/visualize/widget'
6
+ require 'pulse_meter/visualize/widgets/timeline'
7
+ require 'pulse_meter/visualize/widgets/pie'
8
+ require 'pulse_meter/visualize/widgets/gauge'
9
+ require 'pulse_meter/visualize/page'
10
+ require 'pulse_meter/visualize/layout'
11
+
12
+ # DSL
13
+
14
+ require 'pulse_meter/visualize/dsl/errors'
15
+ require 'pulse_meter/visualize/dsl/base'
16
+ require 'pulse_meter/visualize/dsl/sensor'
17
+ require 'pulse_meter/visualize/dsl/widget'
18
+ require 'pulse_meter/visualize/dsl/widgets/area'
19
+ require 'pulse_meter/visualize/dsl/widgets/line'
20
+ require 'pulse_meter/visualize/dsl/widgets/pie'
21
+ require 'pulse_meter/visualize/dsl/widgets/table'
22
+ require 'pulse_meter/visualize/dsl/widgets/gauge'
23
+ require 'pulse_meter/visualize/dsl/page'
24
+ require 'pulse_meter/visualize/dsl/layout'
25
+
26
+ # App
27
+
28
+ require 'pulse_meter/visualize/app'
29
+
30
+ module PulseMeter
31
+ class Visualizer
32
+ def self.draw(&block)
33
+ layout_cofigurator = PulseMeter::Visualize::DSL::Layout.new
34
+ yield(layout_cofigurator)
35
+ layout_cofigurator.to_data
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,2 @@
1
+ require 'pulse_meter_core'
2
+ require 'pulse_meter/visualizer'
@@ -0,0 +1,41 @@
1
+ # -*- encoding: utf-8 -*-
2
+ Gem::Specification.new do |gem|
3
+ gem.authors = ["Ilya Averyanov", "Sergey Averyanov"]
4
+ gem.email = ["av@fun-box.ru", "averyanov@gmail.com"]
5
+ gem.description = %q{Customizable web interface for PulseMeter gem}
6
+ gem.summary = %q{
7
+ Customizable web interface for lightweight Redis-based metrics aggregator and processor PulseMeter
8
+ }
9
+ gem.homepage = "https://github.com/savonarola/pulse_meter_visualizer"
10
+
11
+ gem.required_ruby_version = '>= 1.9.2'
12
+ gem.files = `git ls-files`.split($\)
13
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.name = "pulse_meter_visualizer"
16
+ gem.require_paths = ["lib"]
17
+ gem.version = "0.4.11"
18
+
19
+ gem.add_runtime_dependency('pulse_meter_core')
20
+ gem.add_runtime_dependency('gon-sinatra')
21
+ gem.add_runtime_dependency('haml')
22
+ gem.add_runtime_dependency('sinatra')
23
+ gem.add_runtime_dependency('sinatra-partial')
24
+
25
+ gem.add_development_dependency('aquarium')
26
+ gem.add_development_dependency('coffee-script')
27
+ gem.add_development_dependency('foreman')
28
+ gem.add_development_dependency('hashie')
29
+ gem.add_development_dependency('listen')
30
+ gem.add_development_dependency('mock_redis')
31
+ gem.add_development_dependency('rack-test')
32
+ gem.add_development_dependency('rake')
33
+ gem.add_development_dependency('rb-fsevent')
34
+ gem.add_development_dependency('redcarpet')
35
+ gem.add_development_dependency('rspec')
36
+ gem.add_development_dependency('simplecov')
37
+ gem.add_development_dependency('sprockets')
38
+ gem.add_development_dependency('timecop')
39
+ gem.add_development_dependency('yard')
40
+
41
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe PulseMeter::Visualize::App do
4
+ include Rack::Test::Methods
5
+ before(:each) do
6
+ @layout = PulseMeter::Visualizer.draw do |l|
7
+ l.title "Foo meters"
8
+ l.page "Foo page" do
9
+ end
10
+ end
11
+ end
12
+
13
+ def app
14
+ PulseMeter::Visualize::App.new(@layout)
15
+ end
16
+
17
+ it "responds to /" do
18
+ get '/'
19
+ last_response.should be_ok
20
+ last_response.body.should include("Foo meters")
21
+ end
22
+
23
+ it "responds to /application.js" do
24
+ get '/js/application.js'
25
+ last_response.should be_ok
26
+ end
27
+ end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ describe PulseMeter::Visualize::DSL::Layout do
4
+ let(:interval){ 100 }
5
+ let(:sensor_name) { "some_sensor" }
6
+ let!(:sensor){ PulseMeter::Sensor::Timelined::Max.new(sensor_name, :ttl => 1000, :interval => interval) }
7
+ let(:layout){ described_class.new }
8
+
9
+ describe '.new' do
10
+ it "should initialize pages, title, use_utc, gchart_options" do
11
+ l = layout.to_data
12
+ l.title.should == PulseMeter::Visualize::DSL::Layout::DEFAULT_TITLE
13
+ l.pages.should == []
14
+ l.use_utc.should be_false
15
+ l.gchart_options.should == {}
16
+ end
17
+ end
18
+
19
+ describe "#page" do
20
+ it "should add page constructed by block to pages" do
21
+ layout.page "My Foo Page" do |p|
22
+ p.pie "foo_widget", sensor: sensor_name
23
+ p.line "bar_widget" do |w|
24
+ w.sensor(sensor_name)
25
+ end
26
+ end
27
+ l = layout.to_data
28
+ l.pages.size.should == 1
29
+ p = l.pages.first
30
+ p.title.should == "My Foo Page"
31
+ p.widgets.size.should == 2
32
+ p.widgets.first.title.should == "foo_widget"
33
+ p.widgets.last.title.should == "bar_widget"
34
+ end
35
+ end
36
+
37
+ describe "#title" do
38
+ it "should set layout title" do
39
+ layout.title "Foo Title"
40
+ layout.to_data.title.should == 'Foo Title'
41
+ end
42
+ end
43
+
44
+ describe "#use_utc" do
45
+ it "should set use_utc" do
46
+ layout.use_utc false
47
+ layout.to_data.use_utc.should be_false
48
+ end
49
+ end
50
+
51
+ describe "#gchart_options" do
52
+ it "should set gchart_options" do
53
+ layout.gchart_options({b: 1})
54
+ layout.to_data.gchart_options.should == {b: 1}
55
+ end
56
+ end
57
+
58
+ describe "#to_data" do
59
+ it "should convert layout dsl data to Visualize::Layout" do
60
+ layout.to_data.should be_kind_of(PulseMeter::Visualize::Layout)
61
+ end
62
+ end
63
+ end
64
+