gvis 2.0.4 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.coveralls.yml +1 -0
- data/.gitignore +1 -0
- data/.travis.yml +12 -5
- data/Appraisals +19 -0
- data/CHANGELOG.md +8 -1
- data/README.md +5 -1
- data/Rakefile +7 -0
- data/gemfiles/rails3.0.gemfile +8 -0
- data/gemfiles/rails3.1.gemfile +8 -0
- data/gemfiles/rails3.2.gemfile +8 -0
- data/gemfiles/rails4.0.gemfile +8 -0
- data/gvis.gemspec +6 -5
- data/lib/google_visualization.rb +25 -10
- data/lib/gvis.rb +1 -0
- data/lib/gvis/data_cell.rb +38 -0
- data/lib/gvis/data_table.rb +2 -13
- data/lib/gvis/version.rb +1 -1
- data/test/helper.rb +2 -2
- data/test/test_data_table.rb +6 -5
- data/test/test_google_visualization.rb +11 -0
- data/test/views/_annotatedtimeline.html.erb +15 -0
- metadata +29 -3
data/.coveralls.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
service_name: travis-ci
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -1,13 +1,20 @@
|
|
1
1
|
language: ruby
|
2
|
+
script: "bundle exec rake test_with_coveralls"
|
2
3
|
rvm:
|
3
|
-
- 1.8.7
|
4
4
|
- 1.9.2
|
5
5
|
- 1.9.3
|
6
|
-
-
|
7
|
-
- jruby-19mode
|
8
|
-
- rbx-18mode
|
6
|
+
- 2.0.0
|
7
|
+
- jruby-19mode
|
9
8
|
- rbx-19mode
|
10
|
-
|
9
|
+
gemfile:
|
10
|
+
- gemfiles/3.0.gemfile
|
11
|
+
- gemfiles/3.1.gemfile
|
12
|
+
- gemfiles/3.2.gemfile
|
13
|
+
# - gemfiles/4.0.gemfile
|
14
|
+
branches:
|
15
|
+
only:
|
16
|
+
- master
|
17
|
+
- develop
|
11
18
|
notifications:
|
12
19
|
recipients:
|
13
20
|
- jeremy.olliver@gmail.com
|
data/Appraisals
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
appraise "rails3.0" do
|
2
|
+
gem 'activesupport', '~> 3.0'
|
3
|
+
gem 'actionpack', '~> 3.0'
|
4
|
+
end
|
5
|
+
|
6
|
+
appraise "rails3.1" do
|
7
|
+
gem 'activesupport', '~> 3.1'
|
8
|
+
gem 'actionpack', '~> 3.1'
|
9
|
+
end
|
10
|
+
|
11
|
+
appraise "rails3.2" do
|
12
|
+
gem 'activesupport', '~> 3.2'
|
13
|
+
gem 'actionpack', '~> 3.2'
|
14
|
+
end
|
15
|
+
|
16
|
+
appraise "rails4.0" do
|
17
|
+
gem 'activesupport', '~> 4.0'
|
18
|
+
gem 'actionpack', '~> 4.0'
|
19
|
+
end
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
Changelog
|
2
2
|
=========
|
3
3
|
|
4
|
+
2.1.0
|
5
|
+
-----
|
6
|
+
|
7
|
+
* Support loading javascript via https (if the page is https)
|
8
|
+
* escapes single quotes within values/id's
|
9
|
+
* Official Support for 1.8.7 dropped (may, or may not work)
|
10
|
+
|
4
11
|
2.0.4
|
5
12
|
-----
|
6
13
|
|
@@ -41,4 +48,4 @@ Changelog
|
|
41
48
|
1.0.0
|
42
49
|
-----
|
43
50
|
|
44
|
-
* Initial release (As rails plugin)
|
51
|
+
* Initial release (As rails plugin)
|
data/README.md
CHANGED
@@ -1,6 +1,10 @@
|
|
1
|
-
Gvis
|
1
|
+
Gvis
|
2
2
|
====
|
3
3
|
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/gvis.png)](http://badge.fury.io/rb/gvis) : Latest published version on [rubygems.org](https://rubygems.org/gems/gvis/)
|
5
|
+
|
6
|
+
[![Build Status](https://secure.travis-ci.org/jeremyolliver/gvis.png)](http://travis-ci.org/jeremyolliver/gvis) [![Coverage Status](https://coveralls.io/repos/jeremyolliver/gvis/badge.png?branch=master)](https://coveralls.io/r/jeremyolliver/gvis) [![Code Climate](https://codeclimate.com/github/jeremyolliver/gvis.png)](https://codeclimate.com/github/jeremyolliver/gvis) Current master branch status
|
7
|
+
|
4
8
|
Rails plugin that provides a Ruby wrapper for easily loading the Google Visualization API, and simple generation of the javascript required to plot the graphs
|
5
9
|
For a full list of the graphs provided by google's visualization api see the [gallery](http://code.google.com/apis/visualization/documentation/gallery.html)
|
6
10
|
For documentation on how to use each graph type see google's [API documentation](http://code.google.com/apis/visualization/documentation/)
|
data/Rakefile
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'bundler'
|
2
2
|
Bundler::GemHelper.install_tasks
|
3
3
|
|
4
|
+
require 'appraisal'
|
5
|
+
|
4
6
|
require 'rake/testtask'
|
5
7
|
Rake::TestTask.new(:test) do |test|
|
6
8
|
test.libs << 'lib' << 'test'
|
@@ -9,3 +11,8 @@ Rake::TestTask.new(:test) do |test|
|
|
9
11
|
end
|
10
12
|
|
11
13
|
task :default => :test
|
14
|
+
|
15
|
+
# Pushes test coverage results to coveralls.io, we will only do this during CI builds
|
16
|
+
require 'coveralls/rake/task'
|
17
|
+
Coveralls::RakeTask.new
|
18
|
+
task :test_with_coveralls => [:test, 'coveralls:push']
|
data/gvis.gemspec
CHANGED
@@ -16,13 +16,14 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
17
|
s.require_paths = ["lib"]
|
18
18
|
|
19
|
-
|
19
|
+
# Gem dependencies
|
20
|
+
s.add_runtime_dependency 'json'
|
20
21
|
|
22
|
+
# Gem development/test dependencies
|
21
23
|
s.add_development_dependency 'rake'
|
22
24
|
s.add_development_dependency 'bundler'
|
23
25
|
s.add_development_dependency 'minitest'
|
24
|
-
s.add_development_dependency '
|
25
|
-
|
26
|
-
|
27
|
-
s.add_development_dependency 'actionpack', '> 3.0.0'
|
26
|
+
s.add_development_dependency 'coveralls'
|
27
|
+
s.add_development_dependency 'appraisal'
|
28
|
+
s.add_development_dependency 'actionpack', '> 3.0.0' # For rendering test views
|
28
29
|
end
|
data/lib/google_visualization.rb
CHANGED
@@ -14,7 +14,8 @@ module GoogleVisualization
|
|
14
14
|
# Include the Visualization API code from google.
|
15
15
|
# (Omit this call if you prefer to include the API in your own js package)
|
16
16
|
def include_visualization_api
|
17
|
-
|
17
|
+
# Ensure we use https when the page is loaded on https so we don't make the page look insecure
|
18
|
+
javascript_include_tag("//www.google.com/jsapi")
|
18
19
|
end
|
19
20
|
|
20
21
|
# Call this method from the within the head tag (or alternately just before the closing body tag)
|
@@ -70,7 +71,7 @@ module GoogleVisualization
|
|
70
71
|
|
71
72
|
# Output a div with given id on the page right now, that our graph will be embedded into
|
72
73
|
html = html_options.collect {|key,value| "#{key}=\"#{value}\"" }.join(" ")
|
73
|
-
concat raw(%Q(<div id="#{id}" #{html}><!-- /--></div>))
|
74
|
+
concat raw(%Q(<div id="#{escape_id(id)}" #{html}><!-- /--></div>))
|
74
75
|
nil # Return nil just incase this is called with an output erb tag, as we don't to output the html twice
|
75
76
|
end
|
76
77
|
|
@@ -90,16 +91,16 @@ module GoogleVisualization
|
|
90
91
|
# @return [String] javascript that creates the chart, and adds it to the window variable
|
91
92
|
def generate_visualization(id, chart_type, table, options={})
|
92
93
|
# Generate the js chart data
|
93
|
-
output = "chartData['#{id}'] = new google.visualization.DataTable();"
|
94
|
+
output = "chartData['#{escape_id(id)}'] = new google.visualization.DataTable();"
|
94
95
|
table.columns.each do |col|
|
95
|
-
output += "chartData['#{id}'].addColumn('#{table.column_types[col]}', '#{col}');"
|
96
|
+
output += "chartData['#{escape_id(id)}'].addColumn('#{escape(table.column_types[col])}', '#{escape(col)}');"
|
96
97
|
end
|
97
98
|
option_str = parse_options(options)
|
98
99
|
|
99
100
|
output += %Q(
|
100
|
-
chartData['#{id}'].addRows(#{table.format_data});
|
101
|
-
visualizationCharts['#{id}'] = new google.visualization.#{chart_type.to_s.camelize}(document.getElementById('#{id}'));
|
102
|
-
visualizationCharts['#{id}'].draw(chartData['#{id}'], {#{option_str}});
|
101
|
+
chartData['#{escape_id(id)}'].addRows(#{table.format_data});
|
102
|
+
visualizationCharts['#{escape_id(id)}'] = new google.visualization.#{chart_type.to_s.camelize}(document.getElementById('#{escape_id(id)}'));
|
103
|
+
visualizationCharts['#{escape_id(id)}'].draw(chartData['#{escape_id(id)}'], {#{option_str}});
|
103
104
|
)
|
104
105
|
end
|
105
106
|
|
@@ -112,9 +113,9 @@ module GoogleVisualization
|
|
112
113
|
if val.kind_of? Hash
|
113
114
|
str += "{" + parse_options(val) + "}"
|
114
115
|
elsif val.kind_of? Array
|
115
|
-
str += "[ " + val.collect { |v| "'#{v}'" }.join(", ") + " ]"
|
116
|
+
str += "[ " + val.collect { |v| "'#{escape(v)}'" }.join(", ") + " ]"
|
116
117
|
else
|
117
|
-
str += (val
|
118
|
+
str += Gvis::DataCell.new(val).to_js
|
118
119
|
end
|
119
120
|
str
|
120
121
|
end.join(',')
|
@@ -136,4 +137,18 @@ module GoogleVisualization
|
|
136
137
|
debugging
|
137
138
|
end
|
138
139
|
|
139
|
-
|
140
|
+
def escape(s)
|
141
|
+
if s
|
142
|
+
ERB::Util.json_escape(s)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def escape_id(id)
|
147
|
+
if id
|
148
|
+
# Let's be extra strict and validate for characters allowed in HTML id attribute.
|
149
|
+
# Allow word characters (letters and underscores), digits, dashes, colons and periods.
|
150
|
+
id.gsub(/[^\w\d\-\:\.]/, "_")
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
data/lib/gvis.rb
CHANGED
@@ -0,0 +1,38 @@
|
|
1
|
+
# This is an internal class intended for use by the helper methods present in the {GoogleVisualization} class.
|
2
|
+
#
|
3
|
+
# Converts a Ruby object into a string containing valid javascript for 'string' 'number' 'boolean' 'date' 'datetime' 'timeofday' types
|
4
|
+
# http://code.google.com/apis/chart/interactive/docs/reference.html#DataTable_getValue
|
5
|
+
#
|
6
|
+
# @author Jeremy Olliver
|
7
|
+
module Gvis
|
8
|
+
class DataCell
|
9
|
+
attr_accessor :value
|
10
|
+
attr_accessor :type
|
11
|
+
|
12
|
+
def initialize(value, type = '')
|
13
|
+
@value = value
|
14
|
+
@type = type
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_js
|
18
|
+
# Format/escape individual values for javascript, checking column types, and the ruby value as a failsafe
|
19
|
+
if @type == "datetime" || @value.is_a?(DateTime)
|
20
|
+
# Format a DateTime as a javascript date object down to seconds
|
21
|
+
@value.is_a?(DateTime) ? "new Date (#{@value.year},#{@value.month - 1},#{@value.day},#{@value.hour},#{@value.min},#{@value.sec})" : @value.to_json
|
22
|
+
elsif @type == "date" || @value.is_a?(Date)
|
23
|
+
# Format a Date object as a javascript date
|
24
|
+
@value.is_a?(Date) ? "new Date (#{@value.year},#{@value.month - 1},#{@value.day})" : @value.to_json
|
25
|
+
elsif @type == "timeofday" || @value.is_a?(Time)
|
26
|
+
# Format a Time as a javascript date object down to milliseconds
|
27
|
+
@value.is_a?(Time) ? "[#{@value.hour},#{@value.min},#{@value.sec},#{@value.usec}]" : @value.to_json
|
28
|
+
else
|
29
|
+
# Non date/time values can be JS escaped/formatted safely with # to_json
|
30
|
+
@value.to_json
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
@value.to_s
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/gvis/data_table.rb
CHANGED
@@ -8,7 +8,7 @@ module Gvis
|
|
8
8
|
|
9
9
|
require 'json'
|
10
10
|
|
11
|
-
COLUMN_TYPES = ["string", "number", "date", "datetime"]
|
11
|
+
COLUMN_TYPES = ["string", "number", "date", "datetime", "timeofday"]
|
12
12
|
|
13
13
|
attr_accessor :data, :table_columns, :column_types
|
14
14
|
|
@@ -74,18 +74,7 @@ module Gvis
|
|
74
74
|
@data.each do |row|
|
75
75
|
values = []
|
76
76
|
row.each_with_index do |entry,index|
|
77
|
-
|
78
|
-
safe_val = if @column_types[index] == "date" || entry.is_a?(Date)
|
79
|
-
# Format a date object as a javascript date
|
80
|
-
entry.is_a?(String) ? entry : "new Date (#{entry.year},#{entry.month - 1},#{entry.day})"
|
81
|
-
elsif @column_types[index] == "datetime" || entry.is_a?(Time)
|
82
|
-
# Format a Time (datetime) as a javascript date object down to seconds
|
83
|
-
entry.is_a?(String) ? entry : "new Date (#{entry.year},#{entry.month - 1},#{entry.day},#{entry.hour},#{entry.min},#{entry.sec})"
|
84
|
-
else
|
85
|
-
# Non date/time values can be JS escaped/formatted safely with # to_json
|
86
|
-
entry.to_json
|
87
|
-
end
|
88
|
-
values << safe_val
|
77
|
+
values << Gvis::DataCell.new(entry, @column_types.to_a[index][1]).to_js
|
89
78
|
end
|
90
79
|
rowstring = "[#{values.join(", ")}]"
|
91
80
|
formatted_rows << rowstring
|
data/lib/gvis/version.rb
CHANGED
data/test/helper.rb
CHANGED
data/test/test_data_table.rb
CHANGED
@@ -8,7 +8,7 @@ class TestDataTable < MiniTest::Unit::TestCase
|
|
8
8
|
|
9
9
|
def test_attributes_methods_and_constants
|
10
10
|
assert defined?(Gvis::DataTable::COLUMN_TYPES)
|
11
|
-
assert_equal ["string", "number", "date", "datetime"], Gvis::DataTable::COLUMN_TYPES
|
11
|
+
assert_equal ["string", "number", "date", "datetime", "timeofday"], Gvis::DataTable::COLUMN_TYPES
|
12
12
|
defined_attributes = [:data, :table_columns, :column_types]
|
13
13
|
defined_attributes.each do |a|
|
14
14
|
assert @table.respond_to?(a), "DataTable should have attribute #{a} defined"
|
@@ -52,11 +52,12 @@ class TestDataTable < MiniTest::Unit::TestCase
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def test_formatting_data
|
55
|
-
@table.columns = [["Name", "String"], ["age", "number"], ["dob", "date"], ["now", "datetime"]]
|
56
|
-
|
57
|
-
|
55
|
+
@table.columns = [["Name", "String"], ["age", "number"], ["dob", "date"], ["now", "datetime"], ["time", "timeofday"]]
|
56
|
+
now_datetime = DateTime.new(2011,1,23,11,30,4)
|
57
|
+
now_time = Time.utc(2011,01,23,02,45,43,21)
|
58
|
+
@table.add_rows([["Jeremy Olliver", 23, Date.new(2011,1,1), now_datetime, now_time], ["Optimus Prime", 1000, Date.new(1980,2,23), now_datetime, now_time], ["'The MegaTron'", 999, Date.new(1981,1,1), now_datetime, now_time]])
|
58
59
|
|
59
|
-
assert_equal %q([["Jeremy Olliver", 23, new Date (2011,0,1), new Date (2011,0,23,11,30,4)], ["Optimus Prime", 1000, new Date (1980,1,23), new Date (2011,0,23,11,30,4)], ["'The MegaTron'", 999, new Date (1981,0,1), new Date (2011,0,23,11,30,4)]]), @table.format_data
|
60
|
+
assert_equal %q([["Jeremy Olliver", 23, new Date (2011,0,1), new Date (2011,0,23,11,30,4), [2,45,43,21]], ["Optimus Prime", 1000, new Date (1980,1,23), new Date (2011,0,23,11,30,4), [2,45,43,21]], ["'The MegaTron'", 999, new Date (1981,0,1), new Date (2011,0,23,11,30,4), [2,45,43,21]]]), @table.format_data
|
60
61
|
end
|
61
62
|
|
62
63
|
end
|
@@ -58,4 +58,15 @@ class TestGoogleVisualization < MiniTest::Unit::TestCase
|
|
58
58
|
assert_match("<div id=\"my_chart\"", output, "The graph div should exist on the page")
|
59
59
|
end
|
60
60
|
|
61
|
+
def test_annotated_timeline
|
62
|
+
output = @view.render("test/views/_annotatedtimeline.html.erb")
|
63
|
+
assert_match("'packages':['annotatedtimeline']", output, "the annotated timeline package should have been loaded")
|
64
|
+
assert_match("<div id=\"my_chart\"", output, "The graph div should exist on the page")
|
65
|
+
assert_match("zoomStartTime: new Date (2011,0,1)", output, "The a zoomStartTime date option should exist on the page")
|
66
|
+
assert_match("thickness: 11", output, "The a thickness number option should exist on the page")
|
67
|
+
assert_match("displayZoomButtons: true", output, "The a displayZoomButtons boolean option should exist on the page")
|
68
|
+
assert_match("timeofdayTest: [1,2,3,4]", output, "The a timeofDayTest timeofday option should exist on the page")
|
69
|
+
assert_match("nullTest: null", output, "The a nullTest null option should exist on the page")
|
70
|
+
end
|
71
|
+
|
61
72
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<% visualization "my_chart", "AnnotatedTimeline", :width => 600, :height => 400, :thickness => 11, :displayZoomButtons => true, :timeofdayTest => Time.utc(2000,"jan",1,1,2,3,4), :nullTest => nil, :zoomStartTime => Date.new(2011,01,01), :html => {:style => 'width:600px; height:300px', :class => "graph_chart"} do |chart| %>
|
2
|
+
<%# Add the columns that the graph will have %>
|
3
|
+
<% chart.date "Date" %>
|
4
|
+
<% chart.number "Sales" %>
|
5
|
+
|
6
|
+
<%# Add the data %>
|
7
|
+
<% chart.add_rows([
|
8
|
+
[Date.new(1998,1,1), 1000],
|
9
|
+
[Date.new(1998,1,1), 950],
|
10
|
+
[Date.new(1998,1,1), 300],
|
11
|
+
[Date.new(1998,2,1), 1200],
|
12
|
+
[Date.new(1998,2,1), 950],
|
13
|
+
[Date.new(1998,2,1), 788]
|
14
|
+
]) %>
|
15
|
+
<% end %>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gvis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-09-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
@@ -76,7 +76,23 @@ dependencies:
|
|
76
76
|
- !ruby/object:Gem::Version
|
77
77
|
version: '0'
|
78
78
|
- !ruby/object:Gem::Dependency
|
79
|
-
name:
|
79
|
+
name: coveralls
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: appraisal
|
80
96
|
requirement: !ruby/object:Gem::Requirement
|
81
97
|
none: false
|
82
98
|
requirements:
|
@@ -114,21 +130,29 @@ executables: []
|
|
114
130
|
extensions: []
|
115
131
|
extra_rdoc_files: []
|
116
132
|
files:
|
133
|
+
- .coveralls.yml
|
117
134
|
- .gitignore
|
118
135
|
- .travis.yml
|
136
|
+
- Appraisals
|
119
137
|
- CHANGELOG.md
|
120
138
|
- Gemfile
|
121
139
|
- MIT-LICENSE
|
122
140
|
- README.md
|
123
141
|
- Rakefile
|
142
|
+
- gemfiles/rails3.0.gemfile
|
143
|
+
- gemfiles/rails3.1.gemfile
|
144
|
+
- gemfiles/rails3.2.gemfile
|
145
|
+
- gemfiles/rails4.0.gemfile
|
124
146
|
- gvis.gemspec
|
125
147
|
- lib/google_visualization.rb
|
126
148
|
- lib/gvis.rb
|
149
|
+
- lib/gvis/data_cell.rb
|
127
150
|
- lib/gvis/data_table.rb
|
128
151
|
- lib/gvis/version.rb
|
129
152
|
- test/helper.rb
|
130
153
|
- test/test_data_table.rb
|
131
154
|
- test/test_google_visualization.rb
|
155
|
+
- test/views/_annotatedtimeline.html.erb
|
132
156
|
- test/views/_corechart.html.erb
|
133
157
|
- test/views/_motionchart.html.erb
|
134
158
|
- test/views/layout.html.erb
|
@@ -160,6 +184,8 @@ test_files:
|
|
160
184
|
- test/helper.rb
|
161
185
|
- test/test_data_table.rb
|
162
186
|
- test/test_google_visualization.rb
|
187
|
+
- test/views/_annotatedtimeline.html.erb
|
163
188
|
- test/views/_corechart.html.erb
|
164
189
|
- test/views/_motionchart.html.erb
|
165
190
|
- test/views/layout.html.erb
|
191
|
+
has_rdoc:
|