gvis 2.0.1 → 2.0.2

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