rorschart 0.7.2

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