rorschart 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 207eb5f790581640bb554a961024807eeb918303
4
+ data.tar.gz: dbdce40762ccce890b98f80d6d1f34d69d9efebc
5
+ SHA512:
6
+ metadata.gz: d2a3b6948b0e7f94186fa15c54d66a9dcbdf7a5803951b60ae937a39d73c6046c68c5684e1ece067b41900581d82a447d9e941ac09c8d8956d223b70478f0cac
7
+ data.tar.gz: 55da3d85a93e7987a55a76b194fa50d48d37cd86263e4fcb1581b4b5c89b2422ac24fd42bdd0fdfcaf27fc205236c609dfb0a55703d757657502f36bad19db23
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rorschart.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,45 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rorschart (0.7.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activemodel (4.0.2)
10
+ activesupport (= 4.0.2)
11
+ builder (~> 3.1.0)
12
+ activerecord (4.0.2)
13
+ activemodel (= 4.0.2)
14
+ activerecord-deprecated_finders (~> 1.0.2)
15
+ activesupport (= 4.0.2)
16
+ arel (~> 4.0.0)
17
+ activerecord-deprecated_finders (1.0.3)
18
+ activesupport (4.0.2)
19
+ i18n (~> 0.6, >= 0.6.4)
20
+ minitest (~> 4.2)
21
+ multi_json (~> 1.3)
22
+ thread_safe (~> 0.1)
23
+ tzinfo (~> 0.3.37)
24
+ arel (4.0.1)
25
+ atomic (1.1.14)
26
+ builder (3.1.4)
27
+ i18n (0.6.9)
28
+ minitest (4.7.5)
29
+ multi_json (1.8.4)
30
+ rake (10.1.0)
31
+ sqlite3 (1.3.8)
32
+ thread_safe (0.1.3)
33
+ atomic
34
+ tzinfo (0.3.38)
35
+
36
+ PLATFORMS
37
+ ruby
38
+
39
+ DEPENDENCIES
40
+ activerecord
41
+ bundler (~> 1.3)
42
+ minitest
43
+ rake
44
+ rorschart!
45
+ sqlite3
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Eric Pantera, Viadeo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,18 @@
1
+ Rorschart
2
+ =========
3
+
4
+ Rorschart is a Ruby library that interprates common Ruby and Activerecord data structures for you to generate beautiful Javascript Google Chart.
5
+
6
+ * Multi-series charts directly from yours ActiveRecord queries
7
+ * Works with all Google Charts
8
+ * Detects appropriate data type to customize axes labels
9
+ * Supports asynchonous ajax data generation
10
+ * Rorschart knows how to draw charts from Array, Hash, Array of Array or Hash, ActiveRecord::Relation...
11
+
12
+ Checkout the [demonstration page](http://viadeo.github.io/rorschart).
13
+
14
+ Designed to be the perfect companion to [Snowplow-dashboard](https://github.com/viadeo/snowplow-dashboard).
15
+
16
+ ## License
17
+
18
+ Distributed under the MIT license.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ task :default => :test
5
+ Rake::TestTask.new do |t|
6
+ t.libs << "test"
7
+ t.pattern = "test/**/*_test.rb"
8
+ end
@@ -0,0 +1,122 @@
1
+ /*jslint browser: true, indent: 2, plusplus: true, vars: true */
2
+ /*global google, $*/
3
+
4
+ (function () {
5
+ 'use strict';
6
+
7
+ var rorschart, resize;
8
+
9
+ if (window.hasOwnProperty('google')) {
10
+ google.load('visualization', '1.0', {'packages': ['corechart', 'table']});
11
+ } else {
12
+ throw new Error("Please include Google Charts first.");
13
+ }
14
+
15
+ function setText(element, text) {
16
+ if (document.body.innerText) {
17
+ element.innerText = text;
18
+ } else {
19
+ element.textContent = text;
20
+ }
21
+ }
22
+
23
+ function chartError(element, message) {
24
+ setText(element, "Error Loading Chart: " + message);
25
+ element.style.color = "#ff0000";
26
+ }
27
+
28
+ function getElement(element) {
29
+ if (typeof element === "string") {
30
+ element = document.getElementById(element);
31
+ }
32
+ return element;
33
+ }
34
+
35
+ resize = function (callback) {
36
+ if (window.attachEvent) {
37
+ window.attachEvent("onresize", callback);
38
+ } else if (window.addEventListener) {
39
+ window.addEventListener("resize", callback, true);
40
+ }
41
+ callback();
42
+ };
43
+
44
+ function processDate(dataTable) {
45
+ var i, j, col, date_ISO8601;
46
+
47
+ for (i = 0; i < dataTable.cols.length; i++) {
48
+ col = dataTable.cols[i];
49
+ if ((col.type === 'date') || (col.type === 'datetime')) {
50
+ for (j = 0; j < dataTable.rows.length; j++) {
51
+ date_ISO8601 = dataTable.rows[j].c[i].v;
52
+ dataTable.rows[j].c[i].v = new Date(date_ISO8601);
53
+ }
54
+ }
55
+ }
56
+ return dataTable;
57
+ }
58
+
59
+ function drawChart(ChartClass, element, dataSource, options) {
60
+
61
+ var dataTable, type;
62
+
63
+ type = Object.prototype.toString.call(dataSource);
64
+ if (type === '[object String]') {
65
+ dataSource = JSON.parse(dataSource);
66
+ }
67
+
68
+ dataSource = Object.create(dataSource);
69
+ if (dataSource.cols == null) {
70
+ setText(element, "Empty data")
71
+ return
72
+ }
73
+
74
+ try {
75
+ dataTable = new google.visualization.DataTable(processDate(dataSource));
76
+ } catch (err) {
77
+ chartError(element, err.message);
78
+ throw err;
79
+ }
80
+
81
+ var chart = new ChartClass(element);
82
+
83
+ resize(function () {
84
+ chart.draw(dataTable, options);
85
+ });
86
+ }
87
+
88
+ function retrieveRemoteData(element, url, callback) {
89
+ $.ajax({
90
+ url: url,
91
+ statusCode: {
92
+ 202: function (data) {
93
+ //Use traditionnal polling here instead of long one. Heroku in mind.
94
+ setTimeout(function () {
95
+ retrieveRemoteData(element, url, callback);
96
+ }, 1500);
97
+ },
98
+ 200: function (data) {
99
+ callback(data);
100
+ }
101
+ },
102
+ error: function (jqXHR, textStatus, errorThrown) {
103
+ var message = (typeof errorThrown === "string") ? errorThrown : errorThrown.message;
104
+ chartError(element, message + " "+ jqXHR.responseText);
105
+ }
106
+ });
107
+ }
108
+
109
+ rorschart = function (chartClass, element, dataSource, options) {
110
+ element = getElement(element);
111
+ if (typeof dataSource === "string") {
112
+ retrieveRemoteData(element, dataSource, function (data) {
113
+ google.setOnLoadCallback(drawChart(chartClass, element, data, options));
114
+ });
115
+ } else {
116
+ google.setOnLoadCallback(drawChart(chartClass, element, dataSource, options));
117
+ }
118
+ };
119
+
120
+ window.Rorschart = rorschart;
121
+
122
+ }());
@@ -0,0 +1,34 @@
1
+ /* Table */
2
+
3
+ table {
4
+ width: 100%;
5
+ }
6
+
7
+ .header_row {
8
+ background: #FFF;
9
+ color: #000;
10
+ white-space:nowrap;
11
+ }
12
+
13
+ .header_cel {
14
+ border: 1px solid transparent;
15
+ border-bottom: 1px solid #EEE;
16
+ font-weight: bold;
17
+ padding: 7px 0;
18
+ }
19
+
20
+ .hover_table_row {
21
+ background-color: #d6e9f8;
22
+ }
23
+
24
+ .table_row {
25
+ white-space:nowrap;
26
+ }
27
+
28
+ /* layout */
29
+
30
+ .container {
31
+ width: 99%;
32
+ }
33
+
34
+
data/lib/rorschart.rb ADDED
@@ -0,0 +1,3 @@
1
+ require "rorschart/version"
2
+ require "rorschart/helper"
3
+ require "rorschart/rails" if defined?(Rails)
@@ -0,0 +1,17 @@
1
+ module Rorschart
2
+ class Engine < ::Rails::Engine
3
+
4
+ initializer "precompile", :group => :all do |app|
5
+ # use a proc instead of a string
6
+ app.config.assets.precompile << Proc.new{|path| path == "rorschart.js" }
7
+ app.config.assets.precompile << Proc.new{|path| path == "rorschart.css" }
8
+ end
9
+
10
+ initializer "helper" do |app|
11
+ ActiveSupport.on_load(:action_view) do
12
+ include Helper
13
+ end
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,264 @@
1
+ require "json"
2
+ require "erb"
3
+
4
+ module Rorschart
5
+ module Helper
6
+
7
+ def default_options
8
+ {
9
+ fontName: "'Helvetica Neue', Helvetica, Arial, sans-serif",
10
+ pointSize: 8,
11
+ lineWidth: 3,
12
+ chartArea: {
13
+ width: '100%',
14
+ height: '70%'
15
+ },
16
+ titlePosition: 'out',
17
+ axisTitlesPosition: 'in',
18
+ legend: {
19
+ textStyle: {
20
+ fontSize: 12,
21
+ color: "#444"
22
+ },
23
+ alignment: "end",
24
+ position: "top"
25
+ },
26
+ curveType: "function",
27
+ hAxis: {
28
+ textStyle: {
29
+ color: "#666",
30
+ fontSize: 12
31
+ },
32
+ gridlines: {
33
+ color: "transparent"
34
+ },
35
+ baselineColor: "#ccc",
36
+ viewWindow: {}
37
+ },
38
+ vAxis: {
39
+ textStyle: {
40
+ color: "#666",
41
+ fontSize: 12
42
+ },
43
+ textPosition: 'in',
44
+ baselineColor: "#ccc",
45
+ viewWindow: {}
46
+ },
47
+ tooltip: {
48
+ textStyle: {
49
+ color: "#666",
50
+ fontSize: 12
51
+ }
52
+ },
53
+ #A nice Color Scheme from http://www.colourlovers.com/palettes/top
54
+ colors: ['#00A0B0', '#6A4A3C', '#CC333F', '#EB6841', '#EDC951'],
55
+ # colors: ['#F8FCC1', '#CC0C39', '#E6781E', '#C8CF02', '#1693A7'],
56
+ allowHtml: true
57
+ }
58
+ end
59
+
60
+ def chart_options(klass_symbol)
61
+ {
62
+ "Table" => {
63
+ cssClassNames: {
64
+ tableRow: 'table_row',
65
+ headerRow: 'header_row',
66
+ headerCell: 'header_cel'
67
+ },
68
+ height: "100%"
69
+ },
70
+ "AreaChart" => {
71
+ isStacked: true,
72
+ },
73
+ "PieChart" => {
74
+ legend: {
75
+ alignment: "start",
76
+ position: "right"
77
+ }
78
+ }
79
+ }[klass_symbol] || {}
80
+ end
81
+
82
+ def line_chart(data_source, options = {})
83
+ rorschart_chart "LineChart", data_source, options
84
+ end
85
+
86
+ def pie_chart(data_source, options = {})
87
+ rorschart_chart "PieChart", data_source, options
88
+ end
89
+
90
+ def column_chart(data_source, options = {})
91
+ rorschart_chart "ColumnChart", data_source, options
92
+ end
93
+
94
+ def bar_chart(data_source, options = {})
95
+ rorschart_chart "BarChart", data_source, options
96
+ end
97
+
98
+ def area_chart(data_source, options = {})
99
+ rorschart_chart "AreaChart", data_source, options
100
+ end
101
+
102
+ def table_chart(data_source, options = {})
103
+ rorschart_chart "Table", data_source, options
104
+ end
105
+
106
+ def geo_chart(data_source, options = {})
107
+ rorschart_chart "GeoChart", data_source, options
108
+ end
109
+
110
+ def to_chart(data_source)
111
+ to_datatable_format(data_source).to_json
112
+ end
113
+
114
+ def rorschart_chart(klass_name, dataSource, options = {})
115
+
116
+ dataSource = format_if_needed(dataSource)
117
+ element_id = options.delete(:id) || generateChartId
118
+ options = default_options.merge(chart_options(klass_name)).deep_merge(options);
119
+ height = options.delete(:height) || "300px"
120
+
121
+ html = <<HTML
122
+ <div id="#{ERB::Util.html_escape(element_id)}" style="height: #{ERB::Util.html_escape(height)}; width:100%;">
123
+ Loading Chart data...
124
+ </div>
125
+ HTML
126
+
127
+ js = <<JS
128
+ <script type="text/javascript">
129
+ Rorschart(google.visualization.#{klass_name}, #{element_id.to_json}, #{dataSource.to_json}, #{options.to_json});
130
+ </script>
131
+ JS
132
+
133
+ (html + js).html_safe
134
+ end
135
+
136
+ private
137
+
138
+
139
+ def format_if_needed(data_source)
140
+ data_source.is_a?(String) ? data_source : to_datatable_format(data_source)
141
+ end
142
+
143
+ def to_datatable_format(data)
144
+
145
+ data = convert_objects_to_array_of_hash(data)
146
+ data = merge_series(data)
147
+
148
+ case data
149
+ when Array
150
+
151
+ case data.first
152
+ when Array
153
+ cols = columns_from_array_row(data.first)
154
+ rows = add_rows data
155
+
156
+ when Hash
157
+ cols = columns_from_hash_row(data)
158
+ rows = add_rows data.map{|row| row.values}
159
+ end
160
+
161
+ when Hash
162
+ cols = columns_from_array_row(data.first)
163
+ rows = add_rows data
164
+ end
165
+
166
+ return {cols: cols, rows: rows}
167
+ end
168
+
169
+ def merge_series(data)
170
+
171
+ return data if data.first.nil? || data.first.is_a?(Array)
172
+ prototype = flatten_array_hash(data).inject({}) { |h, (k, v)| h[k] = nil; h }
173
+ return data if prototype.values.size > 3
174
+
175
+ series = {}
176
+ data.each { |e|
177
+ key = e.values.first
178
+ series[key] = series[key] ? convert_grouped_values_into_series(series[key], e) : prototype.merge(e)
179
+ }
180
+
181
+ if series.keys[0].is_a? Date
182
+ series.sort.collect{|e| e[1]}
183
+ else
184
+ series.values
185
+ end
186
+ end
187
+
188
+ def convert_grouped_values_into_series(serieA, serieB)
189
+ # if (serieB.values.size == 3)
190
+ # serieA.merge({serieB.values[1] => serieB.values[2]})
191
+ # else
192
+ # serieA.merge(serieB)
193
+ # end
194
+ serieA.merge(serieB)
195
+ end
196
+
197
+ def flatten_array_hash(data)
198
+ data.inject({}){|row, hash| row.merge(hash)}
199
+ end
200
+
201
+ def add_rows(rows)
202
+ rows.map{|row|
203
+ {"c" =>
204
+ row.map{|col|
205
+ {"v" => col}
206
+ }
207
+ }
208
+ }
209
+ end
210
+
211
+ def generateChartId
212
+ @current_chart_id ||= 0
213
+ "chart#{@current_chart_id += 1}"
214
+ end
215
+
216
+ def convert_objects_to_array_of_hash(data)
217
+
218
+ data = data.to_a if data.is_a? ActiveRecord::Relation
219
+ data = [] << data if data.is_a? ActiveRecord::Base
220
+
221
+ if data.is_a? Array and data.first.is_a? ActiveRecord::Base
222
+ data = data.map{|m| model_to_hash_without_empty_primary_key(m)}
223
+ end
224
+
225
+ return data
226
+ end
227
+
228
+ def model_to_hash_without_empty_primary_key(object)
229
+ primary_keys = object.class.columns.map{|c| c.name if c.primary}.compact
230
+ object.attributes.except(primary_keys.first)
231
+ end
232
+
233
+ def chart_class_from_string(klass_symbol)
234
+ "google.visualization." + klass_symbol.to_s
235
+ end
236
+
237
+ def columns_from_hash_row(data)
238
+ hash_row = flatten_array_hash(data)
239
+ hash_row.map { |c|
240
+ {:type => type_to_string(c[1]), :label => c[0]}
241
+ }
242
+ end
243
+
244
+ def columns_from_array_row(array_row)
245
+ array_row.map { |c|
246
+ {:type => type_to_string(c), :label => default_label_for_type(c)}
247
+ }
248
+ end
249
+
250
+ def type_to_string(cel)
251
+ return 'number' if (cel.is_a? Integer) or (cel.is_a? Float) or cel.nil?
252
+ return 'datetime' if (cel.is_a? DateTime) or (cel.is_a? Time)
253
+ return 'date' if cel.is_a? Date
254
+ return 'boolean' if (!!cel == cel)
255
+ return 'string'
256
+ end
257
+
258
+ def default_label_for_type(cel)
259
+ return 'Date' if (cel.is_a? DateTime) or (cel.is_a? Date)
260
+ return 'Value'
261
+ end
262
+
263
+ end
264
+ end
@@ -0,0 +1,5 @@
1
+ if Rails.version >= "3.1"
2
+ require "rorschart/engine"
3
+ else
4
+ ActionView::Base.send :include, Rorschart::Helper
5
+ end
@@ -0,0 +1,3 @@
1
+ module Rorschart
2
+ VERSION = "0.7.2"
3
+ end
data/rorschart.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rorschart/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rorschart"
8
+ spec.version = Rorschart::VERSION
9
+ spec.authors = ["Eric Pantera"]
10
+ spec.email = ["eric.pantera@gmail.com"]
11
+ spec.description = %q{Interprates Rails data structures for you to generate beautiful Google Charts}
12
+ spec.summary = %q{Beautiful Google Charts from Rails data structures}
13
+ spec.homepage = "https://github.com/epantera/rorschart"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "minitest"
24
+ spec.add_development_dependency "activerecord"
25
+ spec.add_development_dependency "sqlite3"
26
+ end
@@ -0,0 +1,320 @@
1
+ require "test_helper"
2
+
3
+
4
+ class TestRorschart < Minitest::Unit::TestCase
5
+ include Rorschart::Helper
6
+
7
+ def compare_dataTable(right, left)
8
+ assert_equal right[:cols], left[:cols]
9
+ assert_equal right[:cols].count, left[:cols].count
10
+ assert_equal right.to_json, left.to_json
11
+ end
12
+
13
+ def test_from_a_simple_hash_and_detect_type_and_name
14
+
15
+ # Given
16
+ data = {
17
+ DateTime.now => 17,
18
+ DateTime.now - 1 => 18
19
+ }
20
+
21
+ # When
22
+ dataTable = to_datatable_format(data)
23
+
24
+ # Then
25
+ excepted = {
26
+ cols: [
27
+ {type: 'datetime', label: 'Date'},
28
+ {type: 'number', label: 'Value'}
29
+ ],
30
+ rows: [
31
+ {c:[{v: DateTime.now}, {v: 17}]},
32
+ {c:[{v: DateTime.now - 1}, {v: 18}]}
33
+ ]
34
+ }
35
+
36
+ compare_dataTable excepted, dataTable
37
+ end
38
+
39
+ def test_from_a_very_simple_hash_and_detect_type_and_name
40
+
41
+ # Given
42
+ data = {
43
+ "test" => DateTime.now
44
+ }
45
+
46
+ # When
47
+ dataTable = to_datatable_format(data)
48
+
49
+ # Then
50
+ excepted = {
51
+ cols: [
52
+ {type: 'string', label: 'Value'},
53
+ {type: 'datetime', label: 'Date'}
54
+ ],
55
+ rows: [
56
+ {c:[{v: "test"}, {v: DateTime.now}]}
57
+ ]
58
+ }
59
+
60
+ compare_dataTable excepted, dataTable
61
+ end
62
+
63
+ def test_from_an_array_of_hash_and_detect_type_and_reuse_column_name
64
+
65
+ # Given
66
+ data = [
67
+ {"collector_tstamp"=> Date.parse("2013-12-02"), "count"=> 44},
68
+ {"collector_tstamp"=> Date.parse("2013-11-28"), "count"=> 49}
69
+ ]
70
+
71
+ # When
72
+ dataTable = to_datatable_format(data)
73
+
74
+ # Then
75
+ excepted = {
76
+ cols: [
77
+ {type: 'date', label: 'collector_tstamp'},
78
+ {type: 'number', label: 'count'}
79
+ ],
80
+ rows: [
81
+ {c:[{v: Date.parse("2013-11-28")}, {v: 49}]},
82
+ {c:[{v: Date.parse("2013-12-02")}, {v: 44}]}
83
+ ]
84
+ }
85
+
86
+ compare_dataTable excepted, dataTable
87
+ end
88
+
89
+ def test_from_an_array_of_array
90
+
91
+ # Given
92
+ data = [
93
+ [Date.parse("2013-12-02"), 44],
94
+ [Date.parse("2013-11-28"), 49]
95
+ ]
96
+
97
+ # When
98
+ dataTable = to_datatable_format(data)
99
+
100
+ # Then
101
+ excepted = {
102
+ cols: [
103
+ {type: 'date', label: 'Date'},
104
+ {type: 'number', label: 'Value'}
105
+ ],
106
+ rows: [
107
+ {c:[{v: Date.parse("2013-12-02")}, {v: 44}]},
108
+ {c:[{v: Date.parse("2013-11-28")}, {v: 49}]}
109
+ ]
110
+ }
111
+
112
+ compare_dataTable excepted, dataTable
113
+ end
114
+
115
+
116
+ def test_from_a_model_remove_empty_primary_key
117
+
118
+ # Given
119
+ data = SampleModel.create(:username => 'John Doe', :age => 42)
120
+ # When
121
+ dataTable = to_datatable_format(data)
122
+
123
+ # Then
124
+ excepted = {
125
+ cols: [
126
+ {type: 'string', label: 'username'},
127
+ {type: 'number', label: 'age'}
128
+ ],
129
+ rows: [
130
+ {c:[{v: "John Doe"}, {v: 42}]}
131
+ ]
132
+ }
133
+
134
+ compare_dataTable excepted, dataTable
135
+ end
136
+
137
+
138
+ def test_from_an_array_of_model
139
+
140
+ # Given
141
+ data = [
142
+ SampleModel.create(:username => 'John Doe', :age => 42),
143
+ SampleModel.create(:username => 'Jc', :age => 45)
144
+ ]
145
+
146
+ # When
147
+ dataTable = to_datatable_format(data)
148
+
149
+ # Then
150
+ excepted = {
151
+ cols: [
152
+ {type: 'string', label: 'username'},
153
+ {type: 'number', label: 'age'}
154
+ ],
155
+ rows: [
156
+ {c:[{v: "John Doe"}, {v: 42}]},
157
+ {c:[{v: "Jc"}, {v: 45}]}
158
+ ]
159
+ }
160
+
161
+ compare_dataTable excepted, dataTable
162
+ end
163
+
164
+ def test_merge_two_series
165
+ # Given
166
+ data = [
167
+ {"collector_tstamp"=> Date.parse("2013-12-01"), "count"=> 1},
168
+ {"collector_tstamp"=> Date.parse("2013-12-02"), "count"=> 2},
169
+ {"collector_tstamp"=> Date.parse("2013-12-02"), "visit"=> 11},
170
+ {"collector_tstamp"=> Date.parse("2013-12-03"), "visit"=> 3}
171
+ ]
172
+
173
+ # When
174
+ series = to_datatable_format(data)
175
+
176
+ # Then
177
+ excepted = {
178
+ cols: [
179
+ {type: 'date', label: 'collector_tstamp'},
180
+ {type: 'number', label: 'count'},
181
+ {type: 'number', label: 'visit'}
182
+ ],
183
+ rows: [
184
+ {c:[{v: Date.parse("2013-12-01")}, {v: 1}, {v: nil}]},
185
+ {c:[{v: Date.parse("2013-12-02")}, {v: 2}, {v: 11}]},
186
+ {c:[{v: Date.parse("2013-12-03")}, {v: nil}, {v: 3}]}
187
+ ]
188
+ }
189
+
190
+ compare_dataTable excepted, series
191
+
192
+ end
193
+
194
+ def test_merge_two_series_with_first_serie_start_later
195
+ # Given
196
+ data = [
197
+ {"collector_tstamp"=> Date.parse("2013-12-03"), "count"=> 1},
198
+ {"collector_tstamp"=> Date.parse("2013-12-04"), "count"=> 2},
199
+ {"collector_tstamp"=> Date.parse("2013-12-05"), "count"=> 3},
200
+
201
+ {"collector_tstamp"=> Date.parse("2013-12-01"), "visit"=> 5},
202
+ {"collector_tstamp"=> Date.parse("2013-12-02"), "visit"=> 6},
203
+ {"collector_tstamp"=> Date.parse("2013-12-03"), "visit"=> 7},
204
+ {"collector_tstamp"=> Date.parse("2013-12-04"), "visit"=> 8}
205
+ ]
206
+
207
+ # When
208
+ series = to_datatable_format(data)
209
+
210
+ # Then
211
+ excepted = {
212
+ cols: [
213
+ {type: 'date', label: 'collector_tstamp'},
214
+ {type: 'number', label: 'count'},
215
+ {type: 'number', label: 'visit'}
216
+ ],
217
+ rows: [
218
+ {c:[{v: Date.parse("2013-12-01")}, {v: nil}, {v: 5}]},
219
+ {c:[{v: Date.parse("2013-12-02")}, {v: nil}, {v: 6}]},
220
+ {c:[{v: Date.parse("2013-12-03")}, {v: 1}, {v: 7}]},
221
+ {c:[{v: Date.parse("2013-12-04")}, {v: 2}, {v: 8}]},
222
+ {c:[{v: Date.parse("2013-12-05")}, {v: 3}, {v: nil}]}
223
+ ]
224
+ }
225
+
226
+ compare_dataTable excepted, series
227
+
228
+ end
229
+
230
+ # def test_convert_numeric_grouped_dy_date_and_another_field_into_multiseries
231
+
232
+ # # Given
233
+ # data = [
234
+ # {"collector_tstamp"=> Date.parse("2013-11-02"), "series" => "A", "count"=> 1},
235
+ # {"collector_tstamp"=> Date.parse("2013-11-02"), "series" => "B", "count"=> 2},
236
+ # {"collector_tstamp"=> Date.parse("2013-11-02"), "series" => "C", "count"=> 3},
237
+ # {"collector_tstamp"=> Date.parse("2013-12-01"), "series" => "A", "count"=> 4},
238
+ # {"collector_tstamp"=> Date.parse("2013-12-01"), "series" => "B", "count"=> 5}
239
+ # ]
240
+
241
+ # # When
242
+ # dataTable = to_datatable_format(data)
243
+
244
+ # # Then
245
+ # excepted = {
246
+ # cols: [
247
+ # {type: 'date', label: 'collector_tstamp'},
248
+ # {type: 'number', label: 'A'},
249
+ # {type: 'number', label: 'B'},
250
+ # {type: 'number', label: 'C'},
251
+ # ],
252
+ # rows: [
253
+ # {c:[{v: Date.parse("2013-11-02")}, {v: 1}, {v: 2}, {v: 3}]},
254
+ # {c:[{v: Date.parse("2013-12-01")}, {v: 3}, {v: 4}, {v: nil}]}
255
+ # ]
256
+ # }
257
+
258
+ # compare_dataTable excepted, dataTable
259
+ # end
260
+
261
+ # def test_convert_numeric_grouped_dy_date_and_multiple_fields_into_multiseries
262
+
263
+ # # Given
264
+ # data = [
265
+ # {"collector_tstamp"=> Date.parse("2013-11-02"), "series" => "A", "count"=> 1},
266
+ # {"collector_tstamp"=> Date.parse("2013-11-02"), "series" => "B", "count"=> 2},
267
+ # {"collector_tstamp"=> Date.parse("2013-12-01"), "series" => "A", "count"=> 3},
268
+ # {"collector_tstamp"=> Date.parse("2013-12-01"), "series" => "B", "count"=> 4}
269
+ # ]
270
+
271
+ # # When
272
+ # dataTable = to_datatable_format(data)
273
+
274
+ # # Then
275
+ # excepted = {
276
+ # cols: [
277
+ # {type: 'date', label: 'collector_tstamp'},
278
+ # {type: 'number', label: 'A'},
279
+ # {type: 'number', label: 'B'}
280
+ # ],
281
+ # rows: [
282
+ # {c:[{v: Date.parse("2013-11-02")}, {v: 1}, {v: 2}]},
283
+ # {c:[{v: Date.parse("2013-12-01")}, {v: 3}, {v: 4}]}
284
+ # ]
285
+ # }
286
+
287
+ # compare_dataTable excepted, dataTable
288
+ # end
289
+
290
+ def test_flatten_data
291
+
292
+ # Given
293
+ data = [
294
+ {:a => 1, :b => 2},
295
+ {:a => 2, :b => 3},
296
+ {:b => 2, :c => 4}
297
+ ]
298
+
299
+ # When
300
+ flat = flatten_array_hash(data)
301
+
302
+ # Then
303
+ excepted = {:a => 2, :b => 2, :c => 4}
304
+
305
+ assert_equal excepted, flat
306
+ end
307
+
308
+ end
309
+
310
+
311
+ class SampleModel < ActiveRecord::Base
312
+
313
+ def self.create_schema
314
+ schema = 'CREATE TABLE "sample_models" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "username" varchar(255), "age" INTEGER);'
315
+ ActiveRecord::Base.connection.execute(schema)
316
+ end
317
+
318
+ create_schema
319
+
320
+ end
@@ -0,0 +1,12 @@
1
+ require "bundler/setup"
2
+ Bundler.require(:default)
3
+ require "minitest/autorun"
4
+ require "minitest/pride"
5
+ require 'date'
6
+ require 'active_record'
7
+ require "sqlite3"
8
+
9
+ ActiveRecord::Base.establish_connection(
10
+ :adapter => 'sqlite3',
11
+ :database => ':memory:'
12
+ )
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rorschart
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.7.2
5
+ platform: ruby
6
+ authors:
7
+ - Eric Pantera
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activerecord
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: sqlite3
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Interprates Rails data structures for you to generate beautiful Google
84
+ Charts
85
+ email:
86
+ - eric.pantera@gmail.com
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - .gitignore
92
+ - Gemfile
93
+ - Gemfile.lock
94
+ - LICENSE
95
+ - README.md
96
+ - Rakefile
97
+ - app/assets/javascripts/rorschart.js
98
+ - app/assets/stylesheets/rorschart.css
99
+ - lib/rorschart.rb
100
+ - lib/rorschart/engine.rb
101
+ - lib/rorschart/helper.rb
102
+ - lib/rorschart/rails.rb
103
+ - lib/rorschart/version.rb
104
+ - rorschart.gemspec
105
+ - test/rorschart_test.rb
106
+ - test/test_helper.rb
107
+ homepage: https://github.com/epantera/rorschart
108
+ licenses:
109
+ - MIT
110
+ metadata: {}
111
+ post_install_message:
112
+ rdoc_options: []
113
+ require_paths:
114
+ - lib
115
+ required_ruby_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ required_rubygems_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ requirements: []
126
+ rubyforge_project:
127
+ rubygems_version: 2.0.14
128
+ signing_key:
129
+ specification_version: 4
130
+ summary: Beautiful Google Charts from Rails data structures
131
+ test_files:
132
+ - test/rorschart_test.rb
133
+ - test/test_helper.rb