pulse_meter_visualizer 0.4.11

Sign up to get free protection for your applications and to get access to all the features.
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
+