gvis 2.0.1 → 2.0.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.
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .yardoc/*
6
+ doc/*
7
+ coverage/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in resque-batched-logger.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ Gvis
2
+ ====
3
+
4
+ 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
+ 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
+ For documentation on how to use each graph type see google's [API documentation](http://code.google.com/apis/visualization/documentation/)
7
+
8
+ Compatiblity
9
+ ------------
10
+
11
+ gvis version 2.x - Rails 3.x compatible (And rails 2.x using rails_xss)
12
+
13
+ gvis version 1.x - Rails 2.x compatible
14
+
15
+
16
+ Installation
17
+ ============
18
+
19
+ Rails 3:
20
+
21
+ # Gemfile
22
+ gem 'gvis', '>= 2.0.0'
23
+
24
+ Rails 2.X:
25
+
26
+ # config/environment.rb
27
+ config.gem 'gvis', :version => '< 2.0.0'
28
+
29
+ Then include the GoogleVisualization module in app/helpers/application_helper.rb
30
+
31
+ module ApplicationHelper
32
+ include GoogleVisualization
33
+ end
34
+
35
+ Load the API, and render any graphs by placing these methods inside your layout
36
+
37
+ # app/views/layouts/application.html.erb
38
+ <head>
39
+ <%= include_visualization_api %>
40
+ <%= render_visualizations %>
41
+ ...
42
+ </head>
43
+
44
+
45
+ Example
46
+ =======
47
+
48
+ Render desired graphs in the view like this:
49
+
50
+ # index.html.erb
51
+ <% visualization "my_chart", "MotionChart", :width => 600, :height => 400, :html => {:class => "graph_chart"} do |chart| %>
52
+ <%# Add the columns that the graph will have %>
53
+ <% chart.string "Fruit" %>
54
+ <% chart.date "Date" %>
55
+ <% chart.number "Sales" %>
56
+ <% chart.number "Expenses" %>
57
+ <% chart.string "Location" %>
58
+
59
+ <%# Add the data %>
60
+ <% chart.add_rows([
61
+ ["Apples", Date.new(1998,1,1), 1000,300,'East'],
62
+ ["Oranges", Date.new(1998,1,1), 950,200,'West'],
63
+ ["Bananas", Date.new(1998,1,1), 300,250,'West'],
64
+ ["Apples", Date.new(1998,2,1), 1200,400,'East'],
65
+ ["Oranges", Date.new(1998,2,1), 950,150,'West'],
66
+ ["Bananas", Date.new(1998,2,1), 788,617,'West']
67
+ ]) %>
68
+ <% end %>
69
+
70
+
71
+ Copyright (c) 2009 [Jeremy Olliver], released under the MIT license
data/Rakefile CHANGED
@@ -1,23 +1,19 @@
1
- require 'rake'
2
- require 'rake/testtask'
3
- require 'rake/rdoctask'
4
-
5
- desc 'Default: run unit tests.'
6
- task :default => :test
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
7
3
 
8
- desc 'Test the gvis plugin.'
9
- Rake::TestTask.new(:test) do |t|
10
- t.libs << 'lib'
11
- t.libs << 'test'
12
- t.pattern = 'test/**/*_test.rb'
13
- t.verbose = true
4
+ require 'rake/testtask'
5
+ Rake::TestTask.new(:test) do |test|
6
+ test.libs << 'lib' << 'test'
7
+ test.pattern = 'test/**/test_*.rb'
8
+ test.verbose = true
14
9
  end
15
10
 
16
- desc 'Generate documentation for the gvis plugin.'
17
- Rake::RDocTask.new(:rdoc) do |rdoc|
18
- rdoc.rdoc_dir = 'rdoc'
19
- rdoc.title = 'Gvis'
20
- rdoc.options << '--line-numbers' << '--inline-source'
21
- rdoc.rdoc_files.include('README')
22
- rdoc.rdoc_files.include('lib/**/*.rb')
11
+ require 'rcov/rcovtask'
12
+ Rcov::RcovTask.new do |test|
13
+ test.rcov_opts << '--exclude /gems/,/Library/,/usr/,spec,lib/tasks' # exclude external gems/libraries
14
+ test.libs << 'test'
15
+ test.pattern = 'test/**/test_*.rb'
16
+ test.verbose = true
23
17
  end
18
+
19
+ task :default => :test
data/gvis.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "gvis/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "gvis"
7
+ s.version = Gvis::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.author = "Jeremy Olliver"
10
+ s.email = "jeremy.olliver@gmail.com"
11
+ s.homepage = "http://github.com/jeremyolliver/gvis"
12
+ s.summary = "Easily embed charts with Google Visualization API"
13
+ s.description = "Easily embed charts with Google Visualization API, using ruby formatted options in your view files"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_dependency 'json'
20
+
21
+ s.add_development_dependency 'bundler'
22
+ s.add_development_dependency 'minitest'
23
+ s.add_development_dependency 'rcov'
24
+ # Although this runs on rails 3, I'm only specifying this as development dependency for now,
25
+ # (instead of runtime dependency) since rails can be vendored and need not be installed/required as gems
26
+ s.add_development_dependency 'actionpack', '> 3.0.0'
27
+ end
@@ -1,29 +1,31 @@
1
- # Provides calls for simplifying the loading and use of the Google Visualization API
1
+ # view helper, and view methods for using the Google Visualization API
2
2
  #
3
- # For use with rails, include this Module in ApplicationHelper
4
- # See the Readme for usage details
3
+ # For use with rails, include this Module in ApplicationHelper, and call {#include_visualization_api} and {#render_visualizations} within the head tag of your html layout
4
+ # See the Readme[http://github.com/jeremyolliver/gvis#readme] for examples and usage details. For more detailed info on each visualization see the API[http://code.google.com/apis/visualization/documentation/]
5
5
  #
6
- # written by Jeremy Olliver
6
+ # @author Jeremy Olliver
7
7
  module GoogleVisualization
8
-
8
+
9
9
  attr_accessor :google_visualizations, :visualization_packages
10
-
11
- #######################################################################
12
- # Place these method calls inside the <head> tag in your layout file. #
13
- #######################################################################
14
-
10
+
11
+ # @group Layout helper methods
12
+ # Place these method calls inside the head tag in your layout file.
13
+
15
14
  # Include the Visualization API code from google.
16
15
  # (Omit this call if you prefer to include the API in your own js package)
17
16
  def include_visualization_api
18
17
  javascript_include_tag("http://www.google.com/jsapi")
19
18
  end
20
-
21
- # This code actually inserts the visualization data
19
+
20
+ # Call this method from the within the head tag (or alternately just before the closing body tag)
21
+ # This will render the graph's generated by the rendering of your view files
22
+ # @return [String] a javascript tag that contains the generated javascript to render the graphs
22
23
  def render_visualizations
23
24
  if @google_visualizations
24
- package_list = []
25
- @visualization_packages.uniq.each do |p|
26
- package_list << "\'#{p.to_s.camelize.downcase}\'"
25
+ package_list = @visualization_packages.uniq.collect do |p|
26
+ package = p.to_s.camelize.downcase
27
+ package = "corechart" if ["areachart", "barchart", "columnchart", "linechart", "piechart"].include?(package)
28
+ "\'#{package}\'"
27
29
  end
28
30
  output = %Q(
29
31
  <script type="text/javascript">
@@ -32,91 +34,106 @@ module GoogleVisualization
32
34
  var chartData = {};
33
35
  var visualizationCharts = {};
34
36
  function drawCharts() { )
35
- @google_visualizations.each do |id, vis|
36
- output += generate_visualization(id, vis[0], vis[1], vis[2])
37
- end
37
+ @google_visualizations.each do |id, vis|
38
+ output += generate_visualization(id, vis[0], vis[1], vis[2])
39
+ end
38
40
  output += "} </script>"
39
41
  raw(output + "<!-- Rendered Google Visualizations /-->")
40
42
  else
41
- raw("<!-- No graphs on this page /-->")
43
+ raw("<!-- No graphs on this page /-->") if debugging?
42
44
  end
43
45
  end
44
46
 
45
- ########################################################################
46
- # Call this method from the view to insert the visualization data here #
47
- # Will output a div with given id, and add the chart data to be #
48
- # rendered from the head of the page #
49
- ########################################################################
47
+ # @endgroup Layout helper methods
48
+
49
+ # @group View methods
50
+
51
+ # Call this method from the view to insert the visualization graph/chart here.
52
+ # This method will output a div with the specified id, and store the chart data to be rendered later via {#render_visualizations}
53
+ # @param [String] id the id of the chart. corresponds to the id of the div
54
+ # @param [String] chart_type the kind of chart to render
55
+ # @param [Hash] options the configuration options for the graph
50
56
  def visualization(id, chart_type, options = {}, &block)
51
57
  init
52
58
  chart_type = chart_type.camelize # Camelize the chart type, as the Google API follows Camel Case conventions (e.g. ColumnChart, MotionChart)
53
59
  options.stringify_keys! # Ensure consistent hash access
54
60
  @visualization_packages << chart_type # Add the chart type to the packages needed to be loaded
55
-
61
+
56
62
  # Initialize the data table (with hashed options), and pass it the block for cleaner adding of attributes within the block
57
- table = DataTable.new(options.delete("data"), options.delete("columns"), options)
63
+ table = Gvis::DataTable.new(options.delete("data"), options.delete("columns"), options)
58
64
  if block_given?
59
65
  yield table
60
66
  end
61
-
62
- # Extract the html options
63
- html_options = options.delete("html") || {}
64
- # Add our chart to the list to be rendered in the head tag
65
- @google_visualizations.merge!(id => [chart_type, table, options])
66
-
67
- # Output a div with given id, that our graph will be embedded into
68
- html = ""
69
- html_options.each do |key, value|
70
- html += %Q(#{key}="#{value}" )
71
- end
67
+
68
+ html_options = options.delete("html") || {} # Extract the html options
69
+ @google_visualizations.merge!(id => [chart_type, table, options]) # Store our chart in an instance variable to be rendered in the head tag
70
+
71
+ # Output a div with given id on the page right now, that our graph will be embedded into
72
+ html = html_options.collect {|key,value| "#{key}=\"#{value}\"" }.join(" ")
72
73
  concat raw(%Q(<div id="#{id}" #{html}><!-- /--></div>))
73
- nil
74
+ nil # Return nil just incase this is called with an output erb tag, as we don't to output the html twice
74
75
  end
75
-
76
+
77
+ # @endgroup View methods
78
+
76
79
  protected
77
-
78
- # Initialize instance variables
79
- def init
80
- @google_visualizations ||= {}
81
- @visualization_packages ||=[]
82
- end
83
-
80
+
84
81
  ###################################################
85
82
  # Internal methods for building the script data #
86
83
  ###################################################
87
- def generate_visualization(id, chart, table, options={})
84
+
85
+ # Generates the javascript for initializing each graph/chart
86
+ # @param [String] id the id for the given chart, this should be unique per html page
87
+ # @param [String] chart_type the name of the chart type that we're rendering.
88
+ # @param [DataTable] table the DataTable containing the column definitions and data rows
89
+ # @param [Hash] options the view formatting options
90
+ # @return [String] javascript that creates the chart, and adds it to the window variable
91
+ def generate_visualization(id, chart_type, table, options={})
88
92
  # Generate the js chart data
89
93
  output = "chartData['#{id}'] = new google.visualization.DataTable();"
90
94
  table.columns.each do |col|
91
95
  output += "chartData['#{id}'].addColumn('#{table.column_types[col]}', '#{col}');"
92
96
  end
93
- option_str = make_opts_string(options)
94
-
97
+ option_str = parse_options(options)
98
+
95
99
  output += %Q(
96
- chartData['#{id}'].addRows(#{table.js_format_data});
97
- visualizationCharts['#{id}'] = new google.visualization.#{chart.to_s.camelize}(document.getElementById('#{id}'));
100
+ chartData['#{id}'].addRows(#{table.format_data});
101
+ visualizationCharts['#{id}'] = new google.visualization.#{chart_type.to_s.camelize}(document.getElementById('#{id}'));
98
102
  visualizationCharts['#{id}'].draw(chartData['#{id}'], {#{option_str}});
99
103
  )
100
104
  end
101
105
 
102
- # parse options into an array of key-value pairs
103
- #
104
- def make_opts_string(opts)
105
- option_str = []
106
- opts.each do |key, val|
106
+ # Parse options hash into a string containing a javascript hash key-value pairs
107
+ # @param [Hash] options the hash to parse
108
+ # @return [String] a javascript representation of the input
109
+ def parse_options(options)
110
+ options.collect do |key, val|
107
111
  str = "#{key}: "
108
112
  if val.kind_of? Hash
109
- str += "{" + make_opts_string(val) + "}"
113
+ str += "{" + parse_options(val) + "}"
110
114
  elsif val.kind_of? Array
111
115
  str += "[ " + val.collect { |v| "'#{v}'" }.join(", ") + " ]"
112
116
  else
113
117
  str += (val.kind_of?(String) ? "'#{val}'" : val.to_s)
114
118
  end
119
+ str
120
+ end.join(',')
121
+ end
115
122
 
116
- option_str << str
117
- end
123
+ # Convenience method for initializing instance variables
124
+ def init
125
+ @google_visualizations ||= {}
126
+ @visualization_packages ||= []
127
+ end
118
128
 
119
- return option_str.join(',')
129
+ # Determines if we're in a debugging environment
130
+ # @return [boolean]
131
+ def debugging?
132
+ debugging = ENV["DEBUG"]
133
+ if defined?(Rails) && Rails.responsd_to?(:env)
134
+ debugging = true if ["development", "test"].include? Rails.env
135
+ end
136
+ debugging
120
137
  end
121
-
138
+
122
139
  end
data/lib/gvis.rb CHANGED
@@ -1,2 +1,2 @@
1
- require 'data_table'
1
+ require 'gvis/data_table'
2
2
  require 'google_visualization'
@@ -0,0 +1,111 @@
1
+ # This is an internal class intended for use by the helper methods present in the {GoogleVisualization} class.
2
+ #
3
+ # Converts Ruby data structures into a string containing a javascript array for use with a google.visualization.DataTable[http://code.google.com/apis/visualization/documentation/reference.html#DataTable] javascript object
4
+ #
5
+ # @author Jeremy Olliver
6
+ module Gvis
7
+ class DataTable
8
+
9
+ require 'json'
10
+
11
+ COLUMN_TYPES = ["string", "number", "date", "datetime"]
12
+
13
+ attr_accessor :data, :table_columns, :column_types
14
+
15
+ # @param [Array] data optional param that may contain a 2D Array for specifying the data upon initialization
16
+ # @param [Array] columns optional param for specifying the column structure upon initialization
17
+ # @param [Hash] options optional param of configuration options for the google.visualization.DataTable javascript object
18
+ def initialize(data = nil, columns = [], options = {})
19
+ @table_columns, @column_types = [], {}
20
+ if columns && columns.any?
21
+ columns.each do |name, type|
22
+ register_column(type, name)
23
+ end
24
+ end
25
+ @data = data || []
26
+ end
27
+
28
+ # A one liner to set all the columns at once
29
+ # eg: chart.columns = { :signups => "number", :day => "date" }
30
+ # @param [Hash] cols a hash where keys are column names, and values are a string of the column type
31
+ def columns=(cols)
32
+ cols.each do |name, coltype|
33
+ register_column(coltype, name)
34
+ end
35
+ end
36
+
37
+ # @return [Array] The columns stored in this table
38
+ def columns
39
+ @table_columns
40
+ end
41
+
42
+ # Adds a single row to the table
43
+ # @param [Array] row An array with a single row of data for the table. Should have the same number of entries as there are columns
44
+ def add_row(row)
45
+ size = row.size
46
+ raise ArgumentError.new("Given a row of data with #{size} entries, but there are only #{@table_columns.size} columns in the table") unless size == @table_columns.size
47
+ @data << row
48
+ end
49
+
50
+ # Adds multiple rows to the table
51
+ # @param [Array] rows A 2d Array containing multiple rows of data. Each Array should have the same number of entries as the table has columns
52
+ def add_rows(rows)
53
+ sizes = rows.collect {|r| r.size }.uniq
54
+ expected_size = @table_columns.size
55
+ errors = sizes.select {|s| s != expected_size }
56
+ raise ArgumentError.new("Given a row of data with #{errors.to_sentence} entries, but there are only #{expected_size} columns in the table") if errors.any?
57
+ @data += rows
58
+ end
59
+
60
+ # Handle the Column definition methods (#string, #number, #date, #datetime)
61
+ # This allows columns to be defined one at a time, with a dsl similar to AR migrations
62
+ # e.g. table.string "name"
63
+ COLUMN_TYPES.each do |col_type|
64
+ define_method(col_type) do |args|
65
+ register_column(col_type, *args)
66
+ end
67
+ end
68
+
69
+ # Outputs the data within this table as a javascript array ready for use by google.visualization.DataTable
70
+ # This is where conversions of ruby date objects to javascript Date objects and escaping strings, and formatting options is done
71
+ # @return [String] a javascript array with the first row defining the table, and subsequent rows holding the table's data
72
+ def format_data
73
+ formatted_rows = []
74
+ @data.each do |row|
75
+ values = []
76
+ row.each_with_index do |entry,index|
77
+ # Format/escape individual values for javascript, checking column types, and the ruby value as a failsafe
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
89
+ end
90
+ rowstring = "[#{values.join(", ")}]"
91
+ formatted_rows << rowstring
92
+ end
93
+ "[#{formatted_rows.join(', ')}]"
94
+ end
95
+ alias :js_format_data :format_data # For backwards compatibility, just in case
96
+ alias :to_s :format_data
97
+
98
+ private
99
+
100
+ # Registers each column explicitly, with data type, and a name associated
101
+ # @param [String] type the type of data column being registered, valid input here are entries from DataTable::COLUMN_TYPES
102
+ # @param [String] name the column name that will be used as a label on the graph
103
+ def register_column(type, name)
104
+ type = type.to_s.downcase
105
+ raise ArgumentError.new("invalid column type #{type}, permitted types are #{COLUMN_TYPES.join(', ')}") unless COLUMN_TYPES.include?(type)
106
+ @table_columns << name.to_s
107
+ @column_types.merge!(name.to_s => type)
108
+ end
109
+
110
+ end
111
+ end
@@ -0,0 +1,3 @@
1
+ module Gvis
2
+ VERSION = "2.0.2"
3
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'minitest/unit'
11
+
12
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ require 'gvis'
15
+
16
+ class MiniTest::Unit::TestCase
17
+ end
18
+
19
+ MiniTest::Unit.autorun
@@ -0,0 +1,62 @@
1
+ require 'helper'
2
+
3
+ class TestDataTable < MiniTest::Unit::TestCase
4
+
5
+ def setup
6
+ @table = Gvis::DataTable.new
7
+ end
8
+
9
+ def test_attributes_methods_and_constants
10
+ assert defined?(Gvis::DataTable::COLUMN_TYPES)
11
+ assert_equal ["string", "number", "date", "datetime"], Gvis::DataTable::COLUMN_TYPES
12
+ defined_attributes = [:data, :table_columns, :column_types]
13
+ defined_attributes.each do |a|
14
+ assert @table.respond_to?(a), "DataTable should have attribute #{a} defined"
15
+ end
16
+ methods = [:columns, :columns=, :add_row, :add_rows, :format_data] + Gvis::DataTable::COLUMN_TYPES
17
+ methods.each do |meth|
18
+ assert @table.respond_to?(meth), "DataTable should respond to instance method ##{meth}"
19
+ end
20
+ end
21
+
22
+ def test_defining_columns
23
+ @table.string "Name"
24
+ @table.number "age"
25
+ @table.date "dob"
26
+ @table.datetime "deceased_at"
27
+ assert_equal 4, @table.columns.size
28
+ assert_equal({"Name" => "string", "age" => "number", "dob" => "date", "deceased_at" => "datetime"}, @table.column_types)
29
+ end
30
+
31
+ def test_single_assign_columns
32
+ # should be case insensitive on column types
33
+ @table.columns = [["Name", "String"], ["Surname", "string"], ["age", "number"]]
34
+ assert_equal 3, @table.columns.size
35
+ assert_equal({"Name" => "string", "Surname" => "string", "age" => "number"}, @table.column_types)
36
+ end
37
+
38
+ def test_initializing_with_columns
39
+ table = Gvis::DataTable.new(nil, [["Name", "String"], ["Surname", "string"], ["age", "number"]])
40
+ assert_equal 3, table.columns.size
41
+ assert_equal({"Name" => "string", "Surname" => "string", "age" => "number"}, table.column_types)
42
+ end
43
+
44
+ def test_adding_rows
45
+ @table.columns = [["Name", "String"], ["Surname", "string"], ["age", "number"]]
46
+ @table.add_row(["Jeremy", "Olliver", 23])
47
+ @table.add_rows([
48
+ ["Optimus", "Prime", 1000],
49
+ ["Mega", "Tron", 999]
50
+ ])
51
+ assert_equal [["Jeremy", "Olliver", 23], ["Optimus", "Prime", 1000], ["Mega", "Tron", 999]], @table.data
52
+ end
53
+
54
+ def test_formatting_data
55
+ @table.columns = [["Name", "String"], ["age", "number"], ["dob", "date"], ["now", "datetime"]]
56
+ now = Time.utc(2011,1,23,11,30,4)
57
+ @table.add_rows([["Jeremy Olliver", 23, Date.new(2011,1,1), now], ["Optimus Prime", 1000, Date.new(1980,2,23), now], ["'The MegaTron'", 999, Date.new(1981,1,1), now]])
58
+
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
+ end
61
+
62
+ end
@@ -0,0 +1,61 @@
1
+ require 'helper'
2
+
3
+ class TestGoogleVisualization < MiniTest::Unit::TestCase
4
+
5
+ require 'action_view'
6
+
7
+ module ApplicationHelper
8
+ include GoogleVisualization
9
+ end
10
+
11
+ # Mocking out ActionView
12
+ class MockView
13
+ attr_accessor :buffer
14
+ include ApplicationHelper
15
+
16
+ def concat(s)
17
+ @buffer ||= ""
18
+ @buffer << s
19
+ end
20
+
21
+ def raw(s)
22
+ s
23
+ end
24
+
25
+ def render(template)
26
+ ERB.new(File.read(template)).result(binding)
27
+ # Render the view file first, then the overall layout
28
+ ERB.new(File.read("test/views/layout.html.erb")).result(binding)
29
+ end
30
+ end
31
+
32
+ def setup
33
+ @view = MockView.new
34
+ end
35
+
36
+ def test_attributes_and_methods
37
+ defined_attributes = [:google_visualizations, :visualization_packages]
38
+ defined_attributes.each do |a|
39
+ assert @view.respond_to?(a), "GoogleVisualization should have defined attribute: #{a}"
40
+ end
41
+ methods = [:include_visualization_api, :render_visualizations, :visualization]
42
+ methods.each do |meth|
43
+ assert @view.respond_to?(meth), "GoogleVisualization should have defined method: ##{meth}"
44
+ end
45
+ end
46
+
47
+ def test_support_for_corechart
48
+ output = @view.render("test/views/_corechart.html.erb")
49
+ assert_match("'packages':['corechart']", output, "only the corechart package should have been loaded")
50
+ %w(AreaChart BarChart ColumnChart LineChart PieChart).each do |chart_type|
51
+ assert_match("<div id=\"#{chart_type}_id\"", output, "The #{chart_type} graph div should exist on the page")
52
+ end
53
+ end
54
+
55
+ def test_motion_chart
56
+ output = @view.render("test/views/_motionchart.html.erb")
57
+ assert_match("'packages':['motionchart']", output, "the motionchart package should have been loaded")
58
+ assert_match("<div id=\"my_chart\"", output, "The graph div should exist on the page")
59
+ end
60
+
61
+ end
@@ -0,0 +1,11 @@
1
+ <%
2
+ %w(AreaChart BarChart ColumnChart LineChart PieChart).each do |chart_type|
3
+ visualization("#{chart_type}_id", "LineChart") do |chart|
4
+ chart.columns = [["Name", "String"], ["age", "number"]]
5
+ chart.add_rows([
6
+ ["Jeremy", 23],
7
+ ["Ben", 24]
8
+ ])
9
+ end
10
+ end
11
+ %>
@@ -0,0 +1,18 @@
1
+ <% visualization "my_chart", "MotionChart", :width => 600, :height => 400, :html => {:class => "graph_chart"} do |chart| %>
2
+ <%# Add the columns that the graph will have %>
3
+ <% chart.string "Fruit" %>
4
+ <% chart.date "Date" %>
5
+ <% chart.number "Sales" %>
6
+ <% chart.number "Expenses" %>
7
+ <% chart.string "Location" %>
8
+
9
+ <%# Add the data %>
10
+ <% chart.add_rows([
11
+ ["Apples", Date.new(1998,1,1), 1000,300,'East'],
12
+ ["Oranges", Date.new(1998,1,1), 950,200,'West'],
13
+ ["Bananas", Date.new(1998,1,1), 300,250,'West'],
14
+ ["Apples", Date.new(1998,2,1), 1200,400,'East'],
15
+ ["Oranges", Date.new(1998,2,1), 950,150,'West'],
16
+ ["Bananas", Date.new(1998,2,1), 788,617,'West']
17
+ ]) %>
18
+ <% end %>
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Test Application</title>
5
+
6
+ <%= render_visualizations %>
7
+ </head>
8
+ <body>
9
+
10
+ <%= @buffer %>
11
+
12
+ </body>
13
+ </html>
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gvis
3
3
  version: !ruby/object:Gem::Version
4
- hash: 13
4
+ hash: 11
5
5
  prerelease:
6
6
  segments:
7
7
  - 2
8
8
  - 0
9
- - 1
10
- version: 2.0.1
9
+ - 2
10
+ version: 2.0.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Jeremy Olliver
@@ -15,10 +15,81 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-03-12 00:00:00 +13:00
18
+ date: 2011-04-17 00:00:00 +12:00
19
19
  default_executable:
20
- dependencies: []
21
-
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: json
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: bundler
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :development
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: minitest
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :development
62
+ version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: rcov
65
+ prerelease: false
66
+ requirement: &id004 !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 3
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ type: :development
76
+ version_requirements: *id004
77
+ - !ruby/object:Gem::Dependency
78
+ name: actionpack
79
+ prerelease: false
80
+ requirement: &id005 !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">"
84
+ - !ruby/object:Gem::Version
85
+ hash: 7
86
+ segments:
87
+ - 3
88
+ - 0
89
+ - 0
90
+ version: 3.0.0
91
+ type: :development
92
+ version_requirements: *id005
22
93
  description: Easily embed charts with Google Visualization API, using ruby formatted options in your view files
23
94
  email: jeremy.olliver@gmail.com
24
95
  executables: []
@@ -28,12 +99,22 @@ extensions: []
28
99
  extra_rdoc_files: []
29
100
 
30
101
  files:
31
- - README
32
- - Rakefile
102
+ - .gitignore
103
+ - Gemfile
33
104
  - MIT-LICENSE
34
- - lib/gvis.rb
35
- - lib/data_table.rb
105
+ - README.md
106
+ - Rakefile
107
+ - gvis.gemspec
36
108
  - lib/google_visualization.rb
109
+ - lib/gvis.rb
110
+ - lib/gvis/data_table.rb
111
+ - lib/gvis/version.rb
112
+ - test/helper.rb
113
+ - test/test_data_table.rb
114
+ - test/test_google_visualization.rb
115
+ - test/views/_corechart.html.erb
116
+ - test/views/_motionchart.html.erb
117
+ - test/views/layout.html.erb
37
118
  has_rdoc: true
38
119
  homepage: http://github.com/jeremyolliver/gvis
39
120
  licenses: []
@@ -68,5 +149,10 @@ rubygems_version: 1.6.1
68
149
  signing_key:
69
150
  specification_version: 3
70
151
  summary: Easily embed charts with Google Visualization API
71
- test_files: []
72
-
152
+ test_files:
153
+ - test/helper.rb
154
+ - test/test_data_table.rb
155
+ - test/test_google_visualization.rb
156
+ - test/views/_corechart.html.erb
157
+ - test/views/_motionchart.html.erb
158
+ - test/views/layout.html.erb
data/README DELETED
@@ -1,64 +0,0 @@
1
- Gvis
2
- ====
3
-
4
- 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
- For a full list of the graphs provided by google's visualization api see: http://code.google.com/apis/visualization/documentation/gallery.html
6
- For documentation on how to use each graph type see: http://code.google.com/apis/visualization/documentation/
7
-
8
- version 2.X - Rails 3.X
9
- version 1.X - Rails 2.X
10
-
11
-
12
- Installation
13
- ============
14
-
15
- Rails 3:
16
- # Gemfile
17
- gem 'gvis', '>= 2.0.0'
18
-
19
- Rails 2.X:
20
- # config/environment.rb
21
- config.gem 'gvis', :version => '< 2.0.0'
22
-
23
- # Include the GoogleVisualization module in app/helpers/application_helper.rb
24
- module ApplicationHelper
25
-
26
- include GoogleVisualization
27
-
28
- end
29
-
30
- # Load the API, and render any graphs by placing these methods inside your layout
31
- # app/views/layouts/application.html.erb
32
- <head>
33
- <%= include_visualization_api %>
34
- <%= render_visualizations %>
35
- ...
36
- </head>
37
-
38
-
39
- Example
40
- =======
41
-
42
- # Render desired graphs in the view
43
- # index.html.erb
44
- <% visualization "my_chart", "MotionChart", :width => 600, :height => 400, :html => {:class => "graph_chart"} do |chart| %>
45
- <%# Add the columns that the graph will have %>
46
- <% chart.string "Fruit" %>
47
- <% chart.date "Date" %>
48
- <% chart.number "Sales" %>
49
- <% chart.number "Expenses" %>
50
- <% chart.string "Location" %>
51
-
52
- <%# Add the data %>
53
- <% chart.add_rows([
54
- ["Apples", Date.new(1998,1,1), 1000,300,'East'],
55
- ["Oranges", Date.new(1998,1,1), 950,200,'West'],
56
- ["Bananas", Date.new(1998,1,1), 300,250,'West'],
57
- ["Apples", Date.new(1998,2,1), 1200,400,'East'],
58
- ["Oranges", Date.new(1998,2,1), 950,150,'West'],
59
- ["Bananas", Date.new(1998,2,1), 788,617,'West']
60
- ]) %>
61
- <% end %>
62
-
63
-
64
- Copyright (c) 2009 [Jeremy Olliver], released under the MIT license
data/lib/data_table.rb DELETED
@@ -1,76 +0,0 @@
1
- # Converts Ruby data structures into javascript strings for constructing the data for Google Visualization API clients.
2
- #
3
- # This library can be used to create a google.visualization.DataTable usable by
4
- # visualizations built on the Google Visualization API. Output formats are raw
5
- # JSON, JSON response, and JavaScript.
6
- #
7
- # written by Jeremy Olliver
8
- class DataTable
9
-
10
- attr_accessor :data, :columns, :column_types
11
-
12
- def initialize(data = nil, columns = [], options = {})
13
- @columns, @column_types = [], {}
14
- unless columns.nil? || columns.empty?
15
- columns.each do |type, name|
16
- register_column(type, name, options)
17
- end
18
- end
19
- @data = data || []
20
- end
21
-
22
- # Registers each column explicitly, with data type, and a name associated
23
- def register_column(type, name, options = {})
24
- @columns << name.to_s
25
- @column_types.merge!(name.to_s => type.to_s)
26
- end
27
-
28
- # Adds a single row to the table
29
- def add_row(row)
30
- @data << row
31
- end
32
-
33
- # Adds multiple rows (2D array) to the table
34
- def add_rows(rows)
35
- @data += rows
36
- end
37
-
38
- # Handle the Column definition methods (#string, #number, #date, #datetime)
39
- def method_missing(method, *arguments)
40
- if ["string", "number", "date", "datetime"].include?(method.to_s)
41
- options = arguments.extract_options!
42
- register_column(method, arguments, options)
43
- else
44
- raise NoMethodError.new(method)
45
- end
46
- end
47
-
48
- ###################################################################################
49
- # Format the ruby arrays into JS #
50
- # Builds up a string representing a JS Array with JS escaped and formatted values #
51
- ###################################################################################
52
- def js_format_data
53
- formatted_rows = []
54
- @data.each do |row|
55
- values = []
56
- row.each_with_index do |entry,index|
57
- # Format/escape individual values for javascript, checking column types, and the ruby value as a failsafe
58
- safe_val = if @column_types[index] == "date" || entry.is_a?(Date)
59
- # Format a date object as a javascript date
60
- entry.is_a?(String) ? entry : "new Date (#{entry.year},#{entry.month - 1},#{entry.day})"
61
- elsif @column_types[index] == "datetime" || entry.is_a?(Time)
62
- # Format a Time (datetime) as a javascript date object down to seconds
63
- entry.is_a?(String) ? entry : "new Date (#{entry.year},#{entry.month - 1},#{entry.day},#{entry.hour},#{entry.min},#{entry.sec})"
64
- else
65
- # Non date/time values can be JS escaped/formatted safely with # to_json
66
- entry.to_json
67
- end
68
- values << safe_val
69
- end
70
- rowstring = "[#{values.join(",")}]"
71
- formatted_rows << rowstring
72
- end
73
- "[#{formatted_rows.join(',')}]"
74
- end
75
-
76
- end