Full Code of mattetti/googlecharts for AI

master d316458ad177 cached
21 files
69.6 KB
22.3k tokens
76 symbols
1 requests
Download .txt
Repository: mattetti/googlecharts
Branch: master
Commit: d316458ad177
Files: 21
Total size: 69.6 KB

Directory structure:
gitextract_f4_dov6o/

├── .gitignore
├── .travis.yml
├── Gemfile
├── History.txt
├── License.txt
├── README
├── README.markdown
├── README.txt
├── Rakefile
├── googlecharts.gemspec
├── lib/
│   ├── gchart/
│   │   ├── aliases.rb
│   │   ├── theme.rb
│   │   └── version.rb
│   ├── gchart.rb
│   ├── googlecharts.rb
│   └── themes.yml
└── spec/
    ├── fixtures/
    │   ├── another_test_theme.yml
    │   └── test_theme.yml
    ├── gchart_spec.rb
    ├── spec_helper.rb
    └── theme_spec.rb

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.DS_Store
log/*
.manifest
pkg
.rspec
.rvmrc
Gemfile.lock

================================================
FILE: .travis.yml
================================================
language: ruby
rvm:
  - 1.8.7
  - ree
  - 1.9.2
  - 1.9.3
  - 2.0.0
  - jruby


================================================
FILE: Gemfile
================================================
source "http://rubygems.org"
gemspec

group :test do
  gem 'rspec'
  gem 'rake', '>= 0.8.7'
end





================================================
FILE: History.txt
================================================
== 1.6.12
* added license to gemspec
* added pie_c type for concentric pie charts

== 1.6.10
* added support for custom position on axis with label (parameter chxp)
* refactored bar chart
* fixed issue #44
* allows GChart to take a theme 

== 1.6.8
* added title alignment support

== 1.6.7
* changed url for ssl connection

== 1.6.6
* added ssl support
* refactored code
* аdded ability to set the legend position
* fixed legend position value
* separated labels and legends for pies

== 1.3.6
* support nil values. The Google Charts API specifies that a single underscore (_) can be used to omit a value from a line chart with 'simple' data encoding, and a double underscore (__) can do the same for a chart with 'extended' data encoding. (Matt Moyer)
* allow a label to appear on a google-o-meter via the :legend option. (hallettj)

== 1.3.5
* added code to properly escape image tag URLs (mokolabs)
* added themes support + 4 default themes (keynote, thirty7signals, pastel, greyscale) chart.line(:theme=>:keynote) (jakehow)

== 1.3.4
* updated documentation and cleaned it up (mokolabs)
* added support for custom class, id and alt tags when using the image_tag format (i.e Gchart.line(:data => [0, 26], :format => 'image_tag')) (mokolabs)

== 1.3.2 - 1.3.3
* changes required by github

== 1.3.1
* added width and spacing options

== 1.3.0
* added support for google-o-meter
* fixed a bug when the max value of a data set was 0

== 1.2.0
* added support for sparklines

== 1.1.0
* fixed another bug fix related to the uri escaping required to download the file properly.

== 1.0.0
* fixed the (URI::InvalidURIError) issue

== 0.2.0
* added export options (file and image tag)
* added support for all arguments to be passed as a string or an array

== 0.1.0 2007-12-11
* fixed the axis labels

== 0.0.3 2007-12-11
* added :chart_background alias and fixed a bug related to the background colors.

== 0.0.2 2007-12-11
* added support for more features and aliases

== 0.0.1 2007-12-08

* 1 major enhancement:
  * Initial release


================================================
FILE: License.txt
================================================
Copyright (c) 2007 Matt Aimonetti

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

================================================
FILE: README
================================================


================================================
FILE: README.markdown
================================================
## Googlecharts

[![Build Status](https://travis-ci.org/mattetti/googlecharts.png?branch=master)](https://travis-ci.org/mattetti/googlecharts)

The goal of this Gem is to make the creation of Google Charts a simple and easy task.
    
    require 'googlecharts'
    Gchart.line(  :size => '200x300', 
                  :title => "example title",
                  :bg => 'efefef',
                  :legend => ['first data set label', 'second data set label'],
                  :data => [10, 30, 120, 45, 72])
              

Check out the [full documentation over there](http://googlecharts.rubyforge.org/)

This gem is fully tested using Rspec, check the rspec folder for more examples.

See at the bottom of this file who reported using this gem.

Chart Type
-------------

This gem supports the following types of charts:
  
  * line, 
  * line_xy
  * sparkline
  * scatter
  * bar
  * venn
  * pie
  * pie_3d
  * google meter
  
Googlecharts also supports graphical themes and you can easily load your own.

To create a chart, simply require Gchart and call any of the existing type:

    require 'gchart'
    Gchart.pie
  
  
Chart Title
-------------

  To add a title to a chart pass the title to your chart:
  
    Gchart.line(:title => 'Sexy Charts!')
    
You can also specify the color and/or size
    
    Gchart.line(:title => 'Sexy Charts!', :title_color => 'FF0000', :title_size => '20')

Colors
-------------

Specify a color with at least a 6-letter string of hexadecimal values in the format RRGGBB. For example:

    * FF0000 = red
    * 00FF00 = green
    * 0000FF = blue
    * 000000 = black
    * FFFFFF = white

You can optionally specify transparency by appending a value between 00 and FF where 00 is completely transparent and FF completely opaque. For example:

    * 0000FFFF = solid blue
    * 0000FF00 = transparent blue

If you need to use multiple colors, check the doc. Usually you just need to pass :attribute => 'FF0000,00FF00'

Some charts have more options than other, make sure to refer to the documentation.

Background options:
-------------

If you don't set the background option, your graph will be transparent.

* You have 3 types of background  http://code.google.com/apis/chart/#chart_or_background_fill

- solid
- gradient
- stripes

By default, if you set a background color, the fill will be solid:

    Gchart.bar(:bg => 'efefef')

However you can specify another fill type such as:
            
    Gchart.line(:bg => {:color => 'efefef', :type => 'gradient'})
  
In the above code, we decided to have a gradient background, however since we only passed one color, the chart will start by the specified color and transition to white. By the default, the gradient angle is 0. Change it as follows:

    Gchart.line(:title =>'bg example', :bg => {:color => 'efefef', :type => 'gradient', :angle => 90})
    
For a more advance use of colors, refer to http://code.google.com/apis/chart/#linear_gradient

    Gchart.line(:bg => {:color => '76A4FB,1,ffffff,0', :type => 'gradient'})
    
    
The same way you set the background color, you can also set the graph background:

    Gchart.line(:graph_bg => 'cccccc')
    
or both

    Gchart.line(:bg => {:color => '76A4FB,1,ffffff,0', :type => 'gradient'}, :graph_bg => 'cccccc', :title => 'Sexy Chart')
    
    
Another type of fill is stripes http://code.google.com/apis/chart/#linear_stripes

    Gchart.line(:bg => {:color => 'efefef', :type => 'stripes'})
    
You can customize the amount of stripes, colors and width by changing the color value.


Themes
--------

  Googlecharts comes with 4 themes: keynote, thirty7signals, pastel and greyscale. (ganked from [Gruff](http://github.com/topfunky/gruff/tree/master)


    Gchart.line(
                :theme => :keynote, 
                :data => [[0,40,10,70,20],[41,10,80,50,40],[20,60,30,60,80],[5,23,35,10,56],[80,90,5,30,60]], 
                :title => 'keynote'
                )

  * keynote

    ![keynote](http://chart.apis.google.com/chart?chtt=keynote&chco=6886B4,FDD84E,72AE6E,D1695E,8A6EAF,EFAA43&chs=300x200&cht=lc&chd=s:AbGvN,bG2hb,NoUo2,DPXGl,29DUo&chf=c,s,FFFFFF|bg,s,000000)

  * thirty7signals

    ![37signals](http://chart.apis.google.com/chart?chtt=thirty7signals&chco=FFF804,336699,339933,ff0000,cc99cc,cf5910&chs=300x200&cht=lc&chd=s:AbGvN,bG2hb,NoUo2,DPXGl,29DUo&chf=bg,s,FFFFFF)

  * pastel

    ![pastel](http://chart.apis.google.com/chart?chtt=pastel&chco=a9dada,aedaa9,daaea9,dadaa9,a9a9da&chs=300x200&cht=lc&chd=s:AbGvN,bG2hb,NoUo2,DPXGl,29DUo)

  * greyscale

    ![greyscale](http://chart.apis.google.com/chart?chtt=greyscale&chco=282828,383838,686868,989898,c8c8c8,e8e8e8&chs=300x200&cht=lc&chd=s:AbGvN,bG2hb,NoUo2,DPXGl,29DUo)


You can also use your own theme. Create a yml file using the same format as the themes located in lib/themes.yml

Load your theme(s):

      Chart::Theme.add_theme_file("#{File.dirname(__FILE__)}/fixtures/another_test_theme.yml")

And use the standard method signature to use your own theme:

      Gchart.line(:theme => :custom_theme, :data => [[0, 40, 10, 70, 20],[41, 10, 80, 50]], :title => 'greyscale')

    
    
Legend & Labels
-------------

You probably will want to use a legend or labels for your graph.

    Gchart.line(:legend => 'legend label')
or
    Gchart.line(:legend => ['legend label 1', 'legend label 2'])
    
Will do the trick. You can also use the labels alias (makes more sense when using the pie charts)

    chart = Gchart.pie(:labels => ['label 1', 'label 2'])

Multiple axis labels 
-------------

Multiple axis labels are available for line charts, bar charts and scatter plots.

* x = bottom x-axis
* t = top x-axis
* y = left y-axis
* r = right y-axis

    Gchart.line(:axis_with_label => 'x,y,r,t')
  
To add labels on these axis:

    Gchart.line(:axis_with_label => 'x,y,r,t',
                :axis_labels => ['Jan|July|Jan|July|Jan', '0|100', 'A|B|C', '2005|2006|2007'])

Note that each array entry could also be an array but represent the
labels for the corresponding axis.

A question which comes back often is how do I only display the y axis
label? Solution:

    Gchart.line(
            :data => [0,20, 40, 60, 140, 230, 60],
            :axis_with_labels => 'y')

Custom axis ranges
---------------

If you want to display a custom range for an axis, you need to set the
range as described in the Google charts documentation: min, max, step:

     Gchart.line( :data => [17, 17, 11, 8, 2], 
                  :axis_with_labels => ['x', 'y'], 
                  :axis_labels => [['J', 'F', 'M', 'A', 'M']], 
                  :axis_range => [nil, [2,17,5]])


In this case, the custom axis range is only defined for y (second
entry) with a minimum value of 2, max 17 and a step of 5.

This is also valid if you want to set a x axis and automatically define
the y labels.
    

Data options
-------------

Data are passed using an array or a nested array.    

    Gchart.bar(:data => [1,2,4,67,100,41,234])  
  
    Gchart.bar(:data => [[1,2,4,67,100,41,234],[45,23,67,12,67,300, 250]])
  
By default, the graph is drawn with your max value representing 100% of the height or width of the graph. You can change that my passing the max value.

    Gchart.bar(:data => [1,2,4,67,100,41,234], :max_value => 300)
    Gchart.bar(:data => [1,2,4,67,100,41,234], :max_value => 'auto')
  
or if you want to use the real values from your dataset:

    Gchart.bar(:data => [1,2,4,67,100,41,234], :max_value => false)
  
  
You can also define a different encoding to add more granularity:

    Gchart.bar(:data => [1,2,4,67,100,41,234], :encoding => 'simple') 
    Gchart.bar(:data => [1,2,4,67,100,41,234], :encoding => 'extended') 
    Gchart.bar(:data => [1,2,4,67,100,41,234], :encoding => 'text') 
  

Pies:
-------------
  
you have 2 type of pies:
  - Gchart.pie() the standard 2D pie
  _ Gchart.pie_3d() the fancy 3D pie
  
To set labels, you can use one of these two options:

    @legend = ['Matt_fu', 'Rob_fu']
    Gchart.pie_3d(:title => @title, :labels => @legend, :data => @data, :size => '400x200')
    Gchart.pie_3d(:title => @title, :legend => @legend, :data => @data, :size => '400x200')
  
Bars:
-------------

A bar chart can accept options to set the width of the bars, spacing between bars and spacing between bar groups. To set these, you can either provide a string, array or hash.

The Google API sets these options in the order of width, spacing, and group spacing, with both spacing values being optional. So, if you provide a string or array, provide them in that order:

    Gchart.bar(:data => @data, :bar_width_and_spacing => '25,6') # width of 25, spacing of 6
    Gchart.bar(:data => @data, :bar_width_and_spacing => '25,6,12') # width of 25, spacing of 6, group spacing of 12
    Gchart.bar(:data => @data, :bar_width_and_spacing => [25,6]) # width of 25, spacing of 6
    Gchart.bar(:data => @data, :bar_width_and_spacing => 25) # width of 25
  
The hash lets you set these values directly, with the Google default values set for any options you don't include:

    Gchart.bar(:data => @data, :bar_width_and_spacing => {:width => 19})
    Gchart.bar(:data => @data, :bar_width_and_spacing => {:spacing => 10, :group_spacing => 12})

Radar:
-------------
    In a Radar graph, the x-axis is circular. The points can be connected by straight lines or curved lines.
    Gchart.radar(:data => @data, :curved => true)

Sparklines:
-------------

A sparkline chart has exactly the same parameters as a line chart. The only difference is that the axes lines are not drawn for sparklines by default.
  

Google-o-meter
-------------

A Google-o-meter has a few restrictions. It may only use a solid filled background and it may only have one label.

Record Chart PNG file in filesystem Sample :
--------------------------------------------

Multi Lines Chart Sample :

	chart = Gchart.new(	:type => 'line',
						:title => "example title",
						:theme => :keynote,
						:data => [[17, 17, 11, 8, 2],[10, 20, 15, 5, 7],[2, 3, 7, 9, 12]], 
						:line_colors => 'e0440e,e62ae5,287eec',
						:legend => ['courbe 1','courbe 2','courbe 3'],
						:axis_with_labels => ['x', 'y'], 
						:axis_range => [[0,100,20], [0,20,5]],
						:filename => "tmp/chart.png")
			
	# Record file in filesystem
	chart.file

try yourself
-------------

    Gchart.bar( :data => [[1,2,4,67,100,41,234],[45,23,67,12,67,300, 250]], 
                :title => 'SD Ruby Fu level', 
                :legend => ['matt','patrick'], 
                :bg => {:color => '76A4FB', :type => 'gradient'}, 
                :bar_colors => 'ff0000,00ff00')

 "http://chart.apis.google.com/chart?chs=300x200&chdl=matt|patrick&chd=s:AAANUIv,JENCN9y&chtt=SDRuby+Fu+level&chf=bg,lg,0,76A4FB,0,ffffff,1&cht=bvs&chco=ff0000,00ff00"  
 
    Gchart.pie(:data => [20,10,15,5,50], :title => 'SDRuby Fu level', :size => '400x200', :labels => ['matt', 'rob', 'patrick', 'ryan', 'jordan'])
http://chart.apis.google.com/chart?cht=p&chs=400x200&chd=s:YMSG9&chtt=SDRuby+Fu+level&chl=matt|rob|patrick|ryan|jordan


================================================
FILE: README.txt
================================================
CHECK README.markdown  (open as a text file)

http://github.com/mattetti/googlecharts

================================================
FILE: Rakefile
================================================
require 'rspec/core/rake_task'

desc 'Default: run specs.'
task :default => :spec

desc "Run specs"
RSpec::Core::RakeTask.new do |task|
    task.pattern = "**/spec/*_spec.rb"
    task.rspec_opts = []
    task.rspec_opts << '--color'
    task.rspec_opts << '-f documentation'
end

================================================
FILE: googlecharts.gemspec
================================================
# -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)
require "gchart/version"

Gem::Specification.new do |s|
  s.name = %q{googlecharts}
  s.version = GchartInfo::VERSION
  s.platform    = Gem::Platform::RUBY
  s.authors = ["Matt Aimonetti", "Andrey Deryabin", "Pedro Pimentel"]
  s.date = %q{2015-08-12}
  s.summary = %q{Generate charts using Google API & Ruby}
  s.description = %q{Generate charts using Google API & Ruby}
  s.email = %q{mattaimonetti@gmail.com deriabin@gmail.com zukunft@gmail.com}
  s.homepage = %q{http://googlecharts.rubyforge.org/}
  s.license = 'MIT'

  s.files         = `git ls-files`.split("\n")
  s.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n")
  s.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
  s.require_paths = ["lib"]
end


================================================
FILE: lib/gchart/aliases.rb
================================================
class Gchart
  
  alias_method :background=, :bg=
  alias_method :chart_bg=, :graph_bg=
  alias_method :chart_color=, :graph_bg=
  alias_method :chart_background=, :graph_bg=
  alias_method :bar_color=, :bar_colors=
  alias_method :line_colors=, :bar_colors=
  alias_method :line_color=, :bar_colors=
  alias_method :slice_colors=, :bar_colors=
  alias_method :horizontal?, :horizontal
  alias_method :curved?, :curved

end


================================================
FILE: lib/gchart/theme.rb
================================================
require 'yaml'

module Chart
  class Theme
    class ThemeNotFound < RuntimeError; end
    
    @@theme_files = ["#{File.dirname(__FILE__)}/../themes.yml"]

    attr_accessor :colors
    attr_accessor :bar_colors
    attr_accessor :background
    attr_accessor :chart_background
    
    def self.load(theme_name)
      theme = new(theme_name)
    end
    
    def self.theme_files
      @@theme_files
    end
    
    # Allows you to specify paths for custom theme files in YAML format
    def self.add_theme_file(file)
      @@theme_files << file
    end
    
    def initialize(theme_name)
      themes = {}
      @@theme_files.each {|f| themes.update YAML::load(File.open(f))}
      theme = themes[theme_name]
      if theme
        self.colors = theme[:colors]
        self.bar_colors = theme[:bar_colors]
        self.background = theme[:background]
        self.chart_background = theme[:chart_background]
        self
      else
        raise(ThemeNotFound, "Could not locate the #{theme_name} theme ...")
      end
    end
    
    def to_options
      {:background => background, :chart_background => chart_background, :bar_colors => bar_colors.join(',')}
    end
  end
end

================================================
FILE: lib/gchart/version.rb
================================================
module GchartInfo #:nodoc:
  VERSION = "1.6.12"
end


================================================
FILE: lib/gchart.rb
================================================
$:.unshift File.dirname(__FILE__)
require 'gchart/version'
require 'gchart/theme'
require "net/http"
require "net/https"
require "uri"
require "cgi"
require 'enumerator'

class Gchart
  include GchartInfo

  def self.url(use_ssl = false)
    if use_ssl
      'https://chart.googleapis.com/chart?'
    else
      'http://chart.apis.google.com/chart?'
    end
  end

  def self.types
    @types ||= ['line', 'line_xy', 'scatter', 'bar', 'venn', 'pie', 'pie_3d', 'pie_c', 'jstize', 'sparkline', 'meter', 'map', 'radar']
  end

  def self.simple_chars
    @simple_chars ||= ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a
  end 

  def self.chars
    @chars ||= simple_chars + ['-', '.']
  end

  def self.ext_pairs
    @ext_pairs ||= chars.map { |char_1| chars.map { |char_2| char_1 + char_2 } }.flatten
  end

  def self.default_filename
    'chart.png'
  end

  attr_accessor :title, :type, :width, :height, :curved, :horizontal, :grouped, :overlapped, :legend, :legend_position, :labels, :data, :encoding, :bar_colors,
  :title_color, :title_size, :title_alignment, :custom, :axis_with_labels, :custom_axis_with_labels, :axis_labels, :bar_width_and_spacing, :id, :alt, :klass,
  :range_markers, :geographical_area, :map_colors, :country_codes, :axis_range, :filename, :min, :max, :colors, :usemap

  attr_accessor :bg_type, :bg_color, :bg_angle, :chart_type, :chart_color, :chart_angle, :axis_range, :thickness, :new_markers, :grid_lines, :use_ssl

  attr_accessor :min_value, :max_value

  types.each do |type|
    instance_eval <<-DYNCLASSMETH
    def #{type}(options = {})
      # Start with theme defaults if a theme is set
      theme = options[:theme]
      options = theme ? Chart::Theme.load(theme).to_options.merge(options) : options 
      # # Extract the format and optional filename, then clean the hash
      format = options[:format] || 'url'
      options[:filename] ||= default_filename
      options.delete(:format)
      #update map_colors to become bar_colors
      options.update(:bar_colors => options[:map_colors]) if options.has_key?(:map_colors)
      chart = new(options.merge!({:type => "#{type}"}))
      chart.send(format)
    end
    DYNCLASSMETH
  end

  def self.version
    VERSION::STRING
  end

  def self.method_missing(m, options={})
    raise NoMethodError, "#{m} is not a supported chart format. Please use one of the following: #{supported_types}."
  end

  def initialize(options={})
    # Allow Gchart to take a theme too
    @theme = options[:theme] 
    options = @theme ? Chart::Theme.load(@theme).to_options.merge(options) : options
    options.delete(:theme)

    @type = options[:type] || 'line'
    @data = []
    @width = 300
    @height = 200
    @curved = false
    @horizontal = false

    @grouped = false
    @overlapped = false

    @use_ssl = false
    @encoding = 'simple'
    # @max_value = 'auto'
    # @min_value defaults to nil meaning zero
    @filename = options[:filename]
    # Sets the alt tag when chart is exported as image tag
    @alt = 'Google Chart'
    # Sets the CSS id selector when chart is exported as image tag
    @id = false
    # Sets the CSS class selector when chart is exported as image tag
    @klass = options[:class] || false
    # set the options value if definable
    options.each do |attribute, value| 
      send("#{attribute}=", value) if self.respond_to?("#{attribute}=")
    end
  end

  def self.supported_types
    self.types.join(' ')
  end

  # Defines the Graph size using the following format:
  # width X height
  def size=(size='300x200')
    @width, @height = size.split("x").map { |dimension| dimension.to_i }
  end

  def size
    "#{width}x#{height}"
  end

  def dimensions
    # TODO: maybe others?
    [:line_xy, :scatter].include?(type) ? 2 : 1
  end

  # Sets the orientation of a bar graph
  def orientation=(orientation='h')
    if orientation == 'h' || orientation == 'horizontal'
      self.horizontal = true
    elsif orientation == 'v' || orientation == 'vertical'
      self.horizontal = false
    end
  end

  def bar_presentation
    if @overlapped
      'o'
    elsif @grouped
      'g'
    else
      's'
    end
  end

  def bg=(options)
    if options.is_a?(String)
      @bg_color = options
    elsif options.is_a?(Hash)
      @bg_color = options[:color]
      @bg_type  = options[:type]
      @bg_angle = options[:angle]
    end
  end

  def graph_bg=(options)
    if options.is_a?(String)
      @chart_color = options
    elsif options.is_a?(Hash)
      @chart_color = options[:color]
      @chart_type  =  options[:type]
      @chart_angle = options[:angle]
    end
  end

  def max_value=(max_v)
    if max_v =~ /false/
      @max_value = false
    else
      @max_value = max_v
    end
  end

  def min_value=(min_v)
    if min_v =~ /false/
      @min_value = false
    else
      @min_value = min_v
    end
  end

  # returns the full data range as an array
  # it also sets the data range if not defined
  def full_data_range(ds)
    return if max_value == false

    ds.each_with_index do |mds, mds_index|
      mds[:min_value] ||= min_value
      mds[:max_value] ||= max_value

      if mds_index == 0 && type.to_s == 'bar'
        # TODO: unless you specify a zero line (using chp or chds),
        #       the min_value of a bar chart is always 0.
        #mds[:min_value] ||= mds[:data].first.to_a.compact.min
        mds[:min_value] ||= 0
      end
      if (mds_index == 0 && type.to_s == 'bar' && 
        !grouped && mds[:data].first.is_a?(Array))
        totals = []
        mds[:data].each do |l|
          l.each_with_index do |v, index|
            next if v.nil?
            totals[index] ||= 0
            totals[index] += v
          end
        end
        mds[:max_value] ||= totals.compact.max
      else
        all = mds[:data].flatten.compact
        # default min value should be 0 unless set to auto
        if mds[:min_value] == 'auto'
          mds[:min_value] = all.min
        else
          min = all.min
          mds[:min_value] ||=  (min && min < 0 ? min : 0)
        end
        mds[:max_value] ||= all.max
      end
    end

    unless axis_range
      @calculated_axis_range = true
      @axis_range = ds.map{|mds| [mds[:min_value], mds[:max_value]]}
      if dimensions == 1 && (type.to_s != 'bar' || horizontal)
        tmp = axis_range.fetch(0, [])
        @axis_range[0] = axis_range.fetch(1, [])
        @axis_range[1] = tmp
      end
    end
    # return [min, max] unless (min.nil? || max.nil?)
    # @max = (max_value.nil? || max_value == 'auto') ? ds.compact.map{|mds| mds.compact.max}.max : max_value
    # 
    # if min_value.nil? 
    #   min_ds_value = ds.compact.map{|mds| mds.compact.min}.min || 0
    #   @min = (min_ds_value < 0) ? min_ds_value : 0
    # else
    #   @min = min_value == 'auto' ? ds.compact.map{|mds| mds.compact.min}.min || 0 : min_value      
    # end
    # @axis_range = [[min,max]]
  end

  def dataset
    if @dataset
      @dataset 
    else
      @dataset = convert_dataset(data || [])
      full_data_range(@dataset)   # unless axis_range
      @dataset
    end
  end

  # Sets of data to handle multiple sets
  def datasets
    datasets = []
    dataset.each do |d|
      if d[:data].first.is_a?(Array)
        datasets += d[:data]
      else
        datasets << d[:data]
      end
    end
    datasets
  end

  def self.jstize(string)
    # See http://github.com/mattetti/googlecharts/issues#issue/27
    #URI.escape( string ).gsub("%7C", "|")
    # See discussion: http://github.com/mattetti/googlecharts/commit/9b5cfb93aa51aae06611057668e631cd515ec4f3#comment_51347
    string.gsub(' ', '+').gsub(/\[|\{|\}|\\|\^|\[|\]|\`|\]/) {|c| "%#{c[0].to_s.upcase}"}
    #string.gsub(' ', '+').gsub(/\[|\{|\}|\||\\|\^|\[|\]|\`|\]/) {|c| "%#{c[0].to_s.upcase}"}
  end    
  # load all the custom aliases
  require 'gchart/aliases'

  # Returns the chart's generated PNG as a blob. (borrowed from John's gchart.rubyforge.org)
  def fetch
    url = URI.parse(self.class.url(use_ssl))
    req = Net::HTTP::Post.new(url.path)
    req.body = query_builder
    req.content_type = 'application/x-www-form-urlencoded'
    http = Net::HTTP.new(url.host, url.port)
    http.verify_mode = OpenSSL::SSL::VERIFY_PEER if use_ssl
    http.use_ssl = use_ssl
    http.start {|resp| resp.request(req) }.body
  end

  # Writes the chart's generated PNG to a file. (borrowed from John's gchart.rubyforge.org)
  def write
    io_or_file = filename || self.class.default_filename
    return io_or_file.write(fetch) if io_or_file.respond_to?(:write)
    open(io_or_file, "wb+") { |io| io.write(fetch) }
  end

  # Format

  def image_tag
    image = "<img"
    image += " id=\"#{id}\"" if id  
    image += " class=\"#{klass}\"" if klass      
    image += " src=\"#{url_builder(:html)}\""
    image += " width=\"#{width}\""
    image += " height=\"#{height}\""
    image += " alt=\"#{alt}\""
    image += " title=\"#{title}\"" if title
    image += " usemap=\"#{usemap}\"" if usemap
    image += " />"
  end

  alias_method :img_tag, :image_tag

  def url
    url_builder
  end

  def file
    write
  end

  #
  def jstize(string)
    self.class.jstize(string)
  end

  private

  # The title size cannot be set without specifying a color.
  # A dark key will be used for the title color if no color is specified 
  def set_title
    title_params = "chtt=#{title}".gsub(/\|/,"\n")
    unless (title_color.nil? && title_size.nil? && title_alignment.nil?)
      title_params << "&chts=" + (color, size, alignment = (title_color || '454545'), title_size, (title_alignment.to_s[0,1] || 'c')).compact.join(',')
    end
    title_params
  end

  def set_size
    "chs=#{size}"
  end

  def set_data
    data = send("#{@encoding}_encoding")
    "chd=#{data}"
  end

  def set_colors
    @bg_type = fill_type(bg_type) || 's' if bg_color
    @chart_type = fill_type(chart_type) || 's' if chart_color

    "chf=" + {'bg' => fill_for(bg_type, bg_color, bg_angle), 'c' => fill_for(chart_type, chart_color, chart_angle)}.map{|k,v| "#{k},#{v}" unless v.nil?}.compact.join('|')      
  end

  # set bar, line colors
  def set_bar_colors
    @bar_colors = bar_colors.join(',') if bar_colors.is_a?(Array)
    "chco=#{bar_colors}"
  end

  def set_country_codes
    @country_codes = country_codes.join() if country_codes.is_a?(Array)
    "chld=#{country_codes}"
  end

  # set bar spacing
  # chbh=
  # <bar width in pixels>,
  # <optional space between bars in a group>,
  # <optional space between groups>
  def set_bar_width_and_spacing
    width_and_spacing_values = case bar_width_and_spacing
    when String
      bar_width_and_spacing
    when Array
      bar_width_and_spacing.join(',')
    when Hash
      width         = bar_width_and_spacing[:width] || 23
      spacing       = bar_width_and_spacing[:spacing] || 4
      group_spacing = bar_width_and_spacing[:group_spacing] || 8
      [width,spacing,group_spacing].join(',')
    else
      bar_width_and_spacing.to_s
    end
    "chbh=#{width_and_spacing_values}"
  end

  def set_range_markers
    markers = case range_markers
    when Hash
      set_range_marker(range_markers)
    when Array
      range_markers.collect{|marker| set_range_marker(marker)}.join('|')
    end
    "chm=#{markers}"
  end

  def set_range_marker(options)
    orientation = ['vertical', 'Vertical', 'V', 'v', 'R'].include?(options[:orientation]) ? 'R' : 'r'
    "#{orientation},#{options[:color]},0,#{options[:start_position]},#{options[:stop_position]}#{',1' if options[:overlaid?]}"  
  end

  def fill_for(type=nil, color='', angle=nil)
    unless type.nil? 
      case type
      when 'lg'
        angle ||= 0
        color = "#{color},0,ffffff,1" if color.split(',').size == 1
        "#{type},#{angle},#{color}"
      when 'ls'
        angle ||= 90
        color = "#{color},0.2,ffffff,0.2" if color.split(',').size == 1
        "#{type},#{angle},#{color}"
      else
        "#{type},#{color}"
      end
    end
  end

  # A chart can have one or many legends. 
  # Gchart.line(:legend => 'label')
  # or
  # Gchart.line(:legend => ['first label', 'last label'])
  def set_legend
    if type.to_s =~ /meter/
      @labels = legend
      return set_labels
    end
    if legend.is_a?(Array)
      "chdl=#{@legend.map{|label| "#{CGI::escape(label.to_s)}"}.join('|')}"
    else
      "chdl=#{legend}"
    end

  end

  def set_legend_position
    case @legend_position.to_s
    when /(bottom|b)$/
      "chdlp=b"
    when /(bottom_vertical|bv)$/
      "chdlp=bv"
    when /(top|t)$/
      "chdlp=t"
    when /(top_vertical|tv)$/
      "chdlp=tv"
    when /(right|r)$/
      "chdlp=r"
    when /(left|l)$/
      "chdlp=l"
    end
  end

  def set_line_thickness
    "chls=#{thickness}"
  end

  def set_line_markers
    "chm=#{new_markers}"
  end

  def set_grid_lines
    "chg=#{grid_lines}"
  end

  def set_labels
    if labels.is_a?(Array)
      "chl=#{@labels.map{|label| "#{CGI::escape(label.to_s)}"}.join('|')}"
    else
      "chl=#{@labels}"
    end
  end

  def set_axis_with_labels
    @axis_with_labels = axis_with_labels.join(',') if @axis_with_labels.is_a?(Array)
    "chxt=#{axis_with_labels}"
  end

  def set_custom_axis_with_labels
    @custom_axis_with_labels = custom_axis_with_labels.join(',') if @custom_axis_with_labels.is_a?(Array)
    "chxp=#{custom_axis_with_labels}"
  end

  def set_axis_labels
    if axis_labels.is_a?(Array)
      if RUBY_VERSION.to_f < 1.9
        labels_arr = axis_labels.enum_with_index.map{|labels,index| [index,labels]}
      else
        labels_arr = axis_labels.map.with_index.map{|labels,index| [index,labels]}
      end
    elsif axis_labels.is_a?(Hash)
      labels_arr = axis_labels.to_a
    end
    labels_arr.map! do |index,labels|
      if labels.is_a?(Array)
        "#{index}:|#{labels.map{|label| "#{CGI::escape(label.to_s)}"}.join('|')}"
      else
        "#{index}:|#{labels}"
      end
    end
    "chxl=#{labels_arr.join('|')}"
  end

  # http://code.google.com/apis/chart/labels.html#axis_range
  # Specify a range for axis labels
  def set_axis_range
    # a passed axis_range should look like:
    # [[10,100]] or [[10,100,4]] or [[10,100], [20,300]]
    # in the second example, 4 is the interval 
    set = @calculated_axis_range ? datasets : axis_range || datasets

    return unless set && set.respond_to?(:each) && set.find {|o| o}.respond_to?(:each)

    'chxr=' + set.enum_for(:each_with_index).map do |axis_range, index|
      next nil if axis_range.nil? # ignore this axis
      min, max, step = axis_range
      if axis_range.size > 3 || step && max && step > max # this is a full series
        max = axis_range.compact.max
        step = nil
      end
      [index, (min_value || min || 0), (max_value || max), step].compact.join(',')
    end.compact.join("|")
  end

  def set_geographical_area
    "chtm=#{geographical_area}"
  end

  def set_type
    'cht=' + case type.to_s
    when 'line'      then "lc"
    when 'line_xy'   then "lxy"
    when 'pie_3d'    then "p3"
    when 'pie_c'     then "pc"
    when 'pie'       then "p"
    when 'venn'      then "v"
    when 'scatter'   then "s"
    when 'sparkline' then "ls"
    when 'meter'     then "gom"
    when 'map'       then "t"
    when 'radar'
      "r" + (curved? ? 's' : '')
    when 'bar'
      "b" + (horizontal? ? "h" : "v") + bar_presentation
    end
  end

  def fill_type(type)
    case type
    when 'solid'    then 's'
    when 'gradient' then 'lg'
    when 'stripes'  then 'ls'
    end
  end

  def number_visible
    n = 0
    dataset.each do |mds|
      return n.to_s if mds[:invisible] == true
      if mds[:data].first.is_a?(Array)
        n += mds[:data].length
      else
        n += 1
      end
    end
    ""
  end

  # Turns input into an array of axis hashes, dependent on the chart type
  def convert_dataset(ds)
    if dimensions == 2
      # valid inputs include:
      # an array of >=2 arrays, or an array of >=2 hashes
      ds = ds.map do |d|
        d.is_a?(Hash) ? d : {:data => d}
      end
    elsif dimensions == 1
      # valid inputs include:
      # a hash, an array of data, an array of >=1 array, or an array of >=1 hash
      if ds.is_a?(Hash)
        ds = [ds]
      elsif not ds.first.is_a?(Hash)
        ds = [{:data => ds}]
      end
    end
    ds
  end

  # just an alias
  def axis_set
    dataset
  end

  def convert_to_simple_value(number)
    if number.nil?
      "_"
    else
      value = self.class.simple_chars[number.to_i]
      value.nil? ? "_" : value
    end
  end

  def convert_to_extended_value(number)
    if number.nil?
      '__'
    else
      value = self.class.ext_pairs[number.to_i]
      value.nil? ? "__" : value
    end
  end

  def encode_scaled_dataset(chars, nil_char)
    dsets = []
    dataset.each do |ds|
      if max_value != false
        range = ds[:max_value] - ds[:min_value]
        range = 1 if range == 0
      end
      unless ds[:data].first.is_a?(Array)
        ldatasets = [ds[:data]]
      else
        ldatasets = ds[:data]
      end
      ldatasets.each do |l|
        dsets << l.map do |number|
          if number.nil?
            nil_char
          else
            unless range.nil? || range.zero?
              number = chars.size * (number - ds[:min_value]) / range.to_f
              number = [number, chars.size - 1].min
            end
            chars[number.to_i]
          end
        end.join
      end
    end
    dsets.join(',')
  end

  # http://code.google.com/apis/chart/#simple
  # Simple encoding has a resolution of 62 different values. 
  # Allowing five pixels per data point, this is sufficient for line and bar charts up
  # to about 300 pixels. Simple encoding is suitable for all other types of chart regardless of size.
  def simple_encoding
    "s" + number_visible + ":" + encode_scaled_dataset(self.class.simple_chars, '_')
  end

  # http://code.google.com/apis/chart/#text
  # Text encoding with data scaling lets you specify arbitrary positive or
  # negative floating point numbers, in combination with a scaling parameter
  # that lets you specify a custom range for your chart. This chart is useful
  # when you don't want to worry about limiting your data to a specific range,
  # or do the calculations to scale your data down or up to fit nicely inside
  # a chart.
  #
  # Valid values range from (+/-)9.999e(+/-)100, and only four non-zero digits are supported (that is, 123400, 1234, 12.34, and 0.1234 are valid, but 12345, 123.45 and 123400.5 are not).
  #
  # This encoding is not available for maps.
  #
  def text_encoding
    chds = dataset.map{|ds| "#{ds[:min_value]},#{ds[:max_value]}" }.join(",")
    "t" + number_visible + ":" + datasets.map{ |ds| ds.map{|e|e||'_'}.join(',') }.join('|') + "&chds=" + chds
  end

  # http://code.google.com/apis/chart/#extended
  # Extended encoding has a resolution of 4,096 different values 
  # and is best used for large charts where a large data range is required.
  def extended_encoding
    "e" + number_visible + ":" + encode_scaled_dataset(self.class.ext_pairs, '__')
  end

  def url_builder(options="")
    self.class.url(use_ssl) + query_builder(options)
  end

  def query_builder(options="")
    query_params = instance_variables.sort.map do |var|
      case var.to_s

      when '@data'
        set_data unless data == []  
        # Set the graph size  
      when '@width'
        set_size unless width.nil? || height.nil?
      when '@type'
        set_type
      when '@title'
        set_title unless title.nil?
      when '@legend'
        set_legend unless legend.nil?
      when '@labels'
        set_labels unless labels.nil?
      when '@legend_position'
        set_legend_position unless legend_position.nil?
      when '@thickness'
        set_line_thickness
      when '@new_markers'
        set_line_markers
      when '@bg_color'
        set_colors
      when '@chart_color'
        set_colors if bg_color.nil?
      when '@bar_colors'
        set_bar_colors
      when '@bar_width_and_spacing'
        set_bar_width_and_spacing
      when '@axis_with_labels'
        set_axis_with_labels
      when '@axis_labels'
        set_axis_labels
      when '@range_markers'
        set_range_markers
      when '@grid_lines'
        set_grid_lines
      when '@custom_axis_with_labels'
        set_custom_axis_with_labels
      when '@geographical_area'
        set_geographical_area
      when '@country_codes'
        set_country_codes
      when '@custom'
        custom
      end
    end.compact

    query_params << set_axis_range

    # Use ampersand as default delimiter
    unless options == :html
      delimiter = '&'
      # Escape ampersand for html image tags
    else
      delimiter = '&amp;'
    end

    jstize(query_params.join(delimiter))
  end

end


================================================
FILE: lib/googlecharts.rb
================================================
require 'gchart'
Googlecharts = Gchart unless Object.const_defined? 'Googlechart'

================================================
FILE: lib/themes.yml
================================================
#Default themes ganked from Gruff: http://github.com/topfunky/gruff/tree/master
:keynote:
  :colors:
    - &blue 6886B4
    - &yellow FDD84E
    - &green 72AE6E
    - &red D1695E
    - &purple 8A6EAF
    - &orange EFAA43
    - &white FFFFFF
    - &black !str 000000
  :bar_colors: [ *blue, *yellow, *green, *red, *purple, *orange ]
  :background: *black
  :chart_background: *white
:thirty7signals:
  :colors:
    - &green 339933
    - &purple cc99cc
    - &blue 336699
    - &yellow FFF804
    - &red ff0000
    - &orange cf5910
  :bar_colors: [ *yellow, *blue, *green, *red, *purple, *orange ]
  :background: *white
:pastel:
  :colors:
    - &blue a9dada
    - &green aedaa9
    - &peach daaea9
    - &yellow dadaa9
    - &dk_purple a9a9da
    - &purple daaeda
    - &grey dadada
  :bar_colors: [ *blue, *green, *peach, *yellow, *dk_purple ]
  :background_color: *white
:greyscale:
  :bar_colors: [
            282828,  
            383838,  
            686868,  
            989898,  
            c8c8c8,  
            e8e8e8
            ]
  :background_color: *white

================================================
FILE: spec/fixtures/another_test_theme.yml
================================================
:test_two:
  :colors:
    - &blue 6886B4
    - &yellow FDD84E
    - &grey 333333
  :bar_colors: [ *blue, *yellow ]
  :background: *grey
  :chart_background: *grey


================================================
FILE: spec/fixtures/test_theme.yml
================================================
:test:
  :colors:
    - &blue 6886B4
    - &yellow FDD84E
    - &white FFFFFF
  :bar_colors: [ *blue, *yellow ]
  :background: *white
  :chart_background: *white

================================================
FILE: spec/gchart_spec.rb
================================================
require File.dirname(__FILE__) + '/spec_helper.rb'
require File.dirname(__FILE__) + '/../lib/gchart'

Chart::Theme.add_theme_file("#{File.dirname(__FILE__)}/fixtures/test_theme.yml")

# Time to add your specs!
# http://rspec.rubyforge.org/
describe "The Gchart class" do
  it "should show supported_types on error" do
    expect(Gchart.supported_types).to match(/line/)
  end

  it "should return supported types" do
    expect(Gchart.types).to include('line')
  end

  it "should support theme option" do
    chart = Gchart.new(:type => 'line',:theme => :test)
    expect(chart.send('url')).to include('chco=6886B4,FDD84E')
  end
end

describe "generating a default Gchart" do

  before(:each) do
    @chart = Gchart.line
  end

  it "should create a line break when a pipe character is encountered" do
    @chart = Gchart.line(:title => "title|subtitle")	
    expect(@chart).to include("chtt=title\nsubtitle")
  end

  it "should include the Google URL" do
    expect(@chart).to include("http://chart.apis.google.com/chart?")
  end

  it "should have a default size" do
    expect(@chart).to include('chs=300x200')
  end

  it "should be able to have a custom size" do
    expect(Gchart.line(:size => '400x600')).to include('chs=400x600')
    expect(Gchart.line(:width => 400, :height => 600)).to include('chs=400x600')
  end

  it "should have query parameters in predictable order" do
    expect(Gchart.line(:axis_with_labels => 'x,y,r', :size => '400x600')).to match(/chxt=.+cht=.+chs=/)
  end

  it "should have a type" do
    expect(@chart).to include('cht=lc')
  end

  it 'should use theme defaults if theme is set' do
    expect(Gchart.line(:theme=>:test)).to include('chco=6886B4,FDD84E')
    expect(Gchart.line(:theme=>:test)).to match(/chf=(c,s,FFFFFF\|bg,s,FFFFFF|bg,s,FFFFFF\|c,s,FFFFFF)/)
  end

  it "should use the simple encoding by default with auto max value" do
    # 9 is the max value in simple encoding, 26 being our max value the 2nd encoded value should be 9
    expect(Gchart.line(:data => [0, 26])).to include('chd=s:A9')
    expect(Gchart.line(:data => [0, 26], :max_value => 26, :axis_with_labels => 'y')).to include('chxr=0,0,26')
  end

  it "should support simple encoding with and without max_value" do
    expect(Gchart.line(:data => [0, 26], :max_value => 26)).to include('chd=s:A9')
    expect(Gchart.line(:data => [0, 26], :max_value => false)).to include('chd=s:Aa')
  end

  it "should support the extended encoding and encode properly" do
    expect(Gchart.line(:data => [0, 10], :encoding => 'extended', :max_value => false)).to include('chd=e:AA')
    expect(Gchart.line(:encoding => 'extended',
                :max_value => false,
                :data => [[0,25,26,51,52,61,62,63], [64,89,90,115,4084]]
                )).to include('chd=e:AAAZAaAzA0A9A-A.,BABZBaBz.0')
  end

  it "should auto set the max value for extended encoding" do
    expect(Gchart.line(:data => [0, 25], :encoding => 'extended', :max_value => false)).to include('chd=e:AAAZ')
    # Extended encoding max value is '..'
    expect(Gchart.line(:data => [0, 25], :encoding => 'extended')).to include('chd=e:AA..')
  end

  it "should be able to have data with text encoding" do
    expect(Gchart.line(:data => [10, 5.2, 4, 45, 78], :encoding => 'text')).to include('chd=t:10,5.2,4,45,78')
  end

  it "should be able to have missing data points with text encoding" do
    expect(Gchart.line(:data => [10, 5.2, nil, 45, 78], :encoding => 'text')).to include('chd=t:10,5.2,_,45,78')
  end

  it "should handle max and min values with text encoding" do
    expect(Gchart.line(:data => [10, 5.2, 4, 45, 78], :encoding => 'text')).to include('chds=0,78')
  end

  it "should automatically handle negative values with proper max/min limits when using text encoding" do
    expect(Gchart.line(:data => [-10, 5.2, 4, 45, 78], :encoding => 'text')).to include('chds=-10,78')
  end

  it "should handle negative values with manual max/min limits when using text encoding" do
   expect(Gchart.line(:data => [-10, 5.2, 4, 45, 78], :encoding => 'text', :min_value => -20, :max_value => 100)).to include('chds=-20,100')
  end

  it "should set the proper axis values when using text encoding and negative values" do
    expect(Gchart.bar( :data       => [[-10], [100]],
                :encoding   => 'text',
                :horizontal => true,
                :min_value  => -20,
                :max_value  => 100,
                :axis_with_labels => 'x',
                :bar_colors => ['FD9A3B', '4BC7DC'])).to include("chxr=0,-20,100")
  end

  it "should be able to have multiple set of data with text encoding" do
    expect(Gchart.line(:data => [[10, 5.2, 4, 45, 78], [20, 40, 70, 15, 99]], :encoding => 'text')).to include(Gchart.jstize('chd=t:10,5.2,4,45,78|20,40,70,15,99'))
  end

  it "should be able to receive a custom param" do
    expect(Gchart.line(:custom => 'ceci_est_une_pipe')).to include('ceci_est_une_pipe')
  end

  it "should be able to set label axis" do
    expect(Gchart.line(:axis_with_labels => 'x,y,r')).to include('chxt=x,y,r')
    expect(Gchart.line(:axis_with_labels => ['x','y','r'])).to include('chxt=x,y,r')
  end

  it "should be able to have axis labels" do
   expect(Gchart.line(:axis_labels => ['Jan|July|Jan|July|Jan', '0|100', 'A|B|C', '2005|2006|2007'])).to include(Gchart.jstize('chxl=0:|Jan|July|Jan|July|Jan|1:|0|100|2:|A|B|C|3:|2005|2006|2007'))
   expect(Gchart.line(:axis_labels => ['Jan|July|Jan|July|Jan'])).to include(Gchart.jstize('chxl=0:|Jan|July|Jan|July|Jan'))
   expect(Gchart.line(:axis_labels => [['Jan','July','Jan','July','Jan']])).to include(Gchart.jstize('chxl=0:|Jan|July|Jan|July|Jan'))
   expect(Gchart.line(:axis_labels => [['Jan','July','Jan','July','Jan'], ['0','100'], ['A','B','C'], ['2005','2006','2007']])).to include(Gchart.jstize('chxl=0:|Jan|July|Jan|July|Jan|1:|0|100|2:|A|B|C|3:|2005|2006|2007'))
  end

  def labeled_line(options = {})
    Gchart.line({:data => @data, :axis_with_labels => 'x,y'}.merge(options))
  end

  it "should display ranges properly" do
    @data = [85,107,123,131,155,172,173,189,203,222,217,233,250,239,256,267,247,261,275,295,288,305,322,307,325,347,331,346,363,382,343,359,383,352,374,393,358,379,396,416,377,398,419,380,409,426,453,432,452,465,436,460,480,440,457,474,501,457,489,507,347,373,413,402,424,448,475,488,513,475,507,530,440,476,500,518,481,512,531,367,396,423,387,415,446,478,442,469,492,463,489,508,463,491,518,549,503,526,547,493,530,549,493,520,541,564,510,535,564,492,512,537,502,530,548,491,514,538,568,524,548,568,512,533,552,577,520,545,570,516,536,555,514,536,566,521,553,579,604,541,569,595,551,581,602,549,576,606,631,589,615,650,597,624,646,672,605,626,654,584,608,631,574,597,622,559,591,614,644,580,603,629,584,615,631,558,591,618,641,314,356,395,397,429,450,421,454,477,507,458,490,560,593]
    expect(labeled_line(:axis_labels => [((1..24).to_a << 1)])).
      to include('chxr=0,85,672')
  end

  def labeled_bar(options = {})
    Gchart.bar({:data => @data,
            :axis_with_labels => 'x,y',
            :axis_labels => [(1..12).to_a],
            :encoding => "text"
    }.merge(options))
  end

  it "should force the y range properly" do
    @data = [1,1,1,1,1,1,1,1,6,2,1,1]
    expect(labeled_bar(
      :axis_range => [[0,0],[0,16]]
    )).to include('chxr=0,0,0|1,0,16')
    expect(labeled_bar(
      :max_value => 16,
      :axis_range => [[0,0],[0,16]]
    )).to include('chxr=0,0,16|1,0,16')

    # nil means ignore axis
    expect(labeled_bar(
      :axis_range => [nil,[0,16]]
    )).to include('chxr=1,0,16')

    # empty array means take defaults
    expect(labeled_bar(
      :max_value => 16,
      :axis_range => [[],[0,16]]
    )).to include('chxr=0,0,16|1,0,16')
    expect(labeled_bar(
      :axis_range => [[],[0,16]]
    )).to include('chxr=0,0|1,0,16')

    expect(Gchart.line(
            :data => [0,20, 40, 60, 140, 230, 60],
            :axis_with_labels => 'y')).to include("chxr=0,0,230")
  end

  it "should take in consideration the max value when creating a range" do
    data = [85,107,123,131,155,172,173,189,203,222,217,233,250,239,256,267,247,261,275,295,288,305,322,307,325,347,331,346,363,382,343,359,383,352,374,393,358,379,396,416,377,398,419,380,409,426,453,432,452,465,436,460,480,440,457,474,501,457,489,507,347,373,413,402,424,448,475,488,513,475,507,530,440,476,500,518,481,512,531,367,396,423,387,415,446,478,442,469,492,463,489,508,463,491,518,549,503,526,547,493,530,549,493,520,541,564,510,535,564,492,512,537,502,530,548,491,514,538,568,524,548,568,512,533,552,577,520,545,570,516,536,555,514,536,566,521,553,579,604,541,569,595,551,581,602,549,576,606,631,589,615,650,597,624,646,672,605,626,654,584,608,631,574,597,622,559,591,614,644,580,603,629,584,615,631,558,591,618,641,314,356,395,397,429,450,421,454,477,507,458,490,560,593]
    url = Gchart.line(:data => data, :axis_with_labels => 'x,y', :axis_labels => [((1..24).to_a << 1)], :max_value => 700)
    expect(url).to include('chxr=0,85,700')
  end

  it 'should generate different labels and legend' do
    expect(Gchart.pie(:legend => %w(1 2 3), :labels=>%w(one two three))).to(include('chdl=1|2|3') && include('chl=one|two|three'))
  end
end

describe "generating different type of charts" do

  it "should be able to generate a line chart" do
    expect(Gchart.line).to be_an_instance_of(String)
    expect(Gchart.line).to include('cht=lc')
  end

  it "should be able to generate a sparkline chart" do
    expect(Gchart.sparkline).to be_an_instance_of(String)
    expect(Gchart.sparkline).to include('cht=ls')
  end

  it "should be able to generate a line xy chart" do
    expect(Gchart.line_xy).to be_an_instance_of(String)
    expect(Gchart.line_xy).to include('cht=lxy')
  end

  it "should be able to generate a scatter chart" do
    expect(Gchart.scatter).to be_an_instance_of(String)
    expect(Gchart.scatter).to include('cht=s')
  end

  it "should be able to generate a bar chart" do
    expect(Gchart.bar).to be_an_instance_of(String)
    expect(Gchart.bar).to include('cht=bvs')
  end

  it "should be able to generate a Venn diagram" do
    expect(Gchart.venn).to be_an_instance_of(String)
    expect(Gchart.venn).to include('cht=v')
  end

  it "should be able to generate a Pie Chart" do
    expect(Gchart.pie).to be_an_instance_of(String)
    expect(Gchart.pie).to include('cht=p')
  end

  it "should be able to generate a Concentric Pie Chart" do
    expect(Gchart.pie_c).to be_an_instance_of(String)
    expect(Gchart.pie_c).to include('cht=pc')
    expect(Gchart.pie_c(size: '240x240', data: [[-1], [2,3]])).to include('-1|1,2,3')
  end

  it "should be able to generate a Google-O-Meter" do
    expect(Gchart.meter).to be_an_instance_of(String)
    expect(Gchart.meter).to include('cht=gom')
  end

  it "should be able to generate a map chart" do
    expect(Gchart.map).to be_an_instance_of(String)
    expect(Gchart.map).to include('cht=t')
  end

  it "should not support other types" do
    msg = "sexy is not a supported chart format. Please use one of the following: #{Gchart.supported_types}."
    expect{Gchart.sexy}.to raise_error(NoMethodError)
  end
end


describe "range markers" do

  it "should be able to generate given a hash of range-marker options" do
    expect(Gchart.line(:range_markers => {:start_position => 0.59, :stop_position => 0.61, :color => 'ff0000'})).to include('chm=r,ff0000,0,0.59,0.61')
  end

  it "should be able to generate given an array of range-marker hash options" do
    expect(Gchart.line(:range_markers => [
          {:start_position => 0.59, :stop_position => 0.61, :color => 'ff0000'},
          {:start_position => 0, :stop_position => 0.6, :color => '666666'},
          {:color => 'cccccc', :start_position => 0.6, :stop_position => 1}
        ])).to include(Gchart.jstize('r,ff0000,0,0.59,0.61|r,666666,0,0,0.6|r,cccccc,0,0.6,1'))
  end

  it "should allow a :overlaid? to be set" do
    expect(Gchart.line(:range_markers => {:start_position => 0.59, :stop_position => 0.61, :color => 'ffffff', :overlaid? => true})).to include('chm=r,ffffff,0,0.59,0.61,1')
    expect(Gchart.line(:range_markers => {:start_position => 0.59, :stop_position => 0.61, :color => 'ffffff', :overlaid? => false})).to include('chm=r,ffffff,0,0.59,0.61')
  end

  describe "when setting the orientation option" do
    before(:each) do
      @options = {:start_position => 0.59, :stop_position => 0.61, :color => 'ff0000'}
    end

    it "to vertical (R) if given a valid option" do
      expect(Gchart.line(:range_markers => @options.merge(:orientation => 'v'))).to include('chm=R')
      expect(Gchart.line(:range_markers => @options.merge(:orientation => 'V'))).to include('chm=R')
      expect(Gchart.line(:range_markers => @options.merge(:orientation => 'R'))).to include('chm=R')
      expect(Gchart.line(:range_markers => @options.merge(:orientation => 'vertical'))).to include('chm=R')
      expect(Gchart.line(:range_markers => @options.merge(:orientation => 'Vertical'))).to include('chm=R')
    end

    it "to horizontal (r) if given a valid option (actually anything other than the vertical options)" do
      expect(Gchart.line(:range_markers => @options.merge(:orientation => 'horizontal'))).to include('chm=r')
      expect(Gchart.line(:range_markers => @options.merge(:orientation => 'h'))).to include('chm=r')
      expect(Gchart.line(:range_markers => @options.merge(:orientation => 'etc'))).to include('chm=r')
    end

    it "if left blank defaults to horizontal (r)" do
      expect(Gchart.line(:range_markers => @options)).to include('chm=r')
    end
  end
end


describe "a bar graph" do

  it "should have a default vertical orientation" do
    expect(Gchart.bar).to include('cht=bvs')
  end

  it "should be able to have a different orientation" do
    expect(Gchart.bar(:orientation => 'vertical')).to include('cht=bvs')
    expect(Gchart.bar(:orientation => 'v')).to include('cht=bvs')
    expect(Gchart.bar(:orientation => 'h')).to include('cht=bhs')
    expect(Gchart.bar(:orientation => 'horizontal')).to include('cht=bhs')
    expect(Gchart.bar(:horizontal => false)).to include('cht=bvs')
  end

  it "should be set to be stacked by default" do
    expect(Gchart.bar).to include('cht=bvs')
  end

  it "should be able to stacked, grouped or overlapped" do
    expect(Gchart.bar(:stacked => true)).to include('cht=bvs')
    expect(Gchart.bar(:stacked => false)).to include('cht=bvs')
    expect(Gchart.bar(:grouped => true)).to include('cht=bvg')
    expect(Gchart.bar(:grouped => false)).to include('cht=bvs')
    expect(Gchart.bar(:overlapped => true)).to include('cht=bvo')
    expect(Gchart.bar(:overlapped => false)).to include('cht=bvs')
  end

  it "should be able to have different bar colors" do
    expect(Gchart.bar(:bar_colors => 'efefef,00ffff')).to include('chco=')
    expect(Gchart.bar(:bar_colors => 'efefef,00ffff')).to include('chco=efefef,00ffff')
    # alias
    expect(Gchart.bar(:bar_color => 'efefef')).to include('chco=efefef')
  end

  it "should be able to have different bar colors when using an array of colors" do
    expect(Gchart.bar(:bar_colors => ['efefef','00ffff'])).to include('chco=efefef,00ffff')
  end

  it 'should be able to accept a string of width and spacing options' do
    expect(Gchart.bar(:bar_width_and_spacing => '25,6')).to include('chbh=25,6')
  end

  it 'should be able to accept a single fixnum width and spacing option to set the bar width' do
    expect(Gchart.bar(:bar_width_and_spacing => 25)).to include('chbh=25')
  end

  it 'should be able to accept an array of width and spacing options' do
    expect(Gchart.bar(:bar_width_and_spacing => [25,6,12])).to include('chbh=25,6,12')
    expect(Gchart.bar(:bar_width_and_spacing => [25,6])).to include('chbh=25,6')
    expect(Gchart.bar(:bar_width_and_spacing => [25])).to include('chbh=25')
  end

  describe "with a hash of width and spacing options" do

    before(:each) do
      @default_width         = 23
      @default_spacing       = 4
      @default_group_spacing = 8
    end

    it 'should be able to have a custom bar width' do
      expect(Gchart.bar(:bar_width_and_spacing => {:width => 19})).to include("chbh=19,#{@default_spacing},#{@default_group_spacing}")
    end

    it 'should be able to have custom spacing' do
      expect(Gchart.bar(:bar_width_and_spacing => {:spacing => 19})).to include("chbh=#{@default_width},19,#{@default_group_spacing}")
    end

    it 'should be able to have custom group spacing' do
      expect(Gchart.bar(:bar_width_and_spacing => {:group_spacing => 19})).to include("chbh=#{@default_width},#{@default_spacing},19")
    end
  end
end

describe "a radar chart" do

  before(:each) do
    @chart = Gchart.radar(:title => 'Chart Title')
  end

  it "should be able have a chart title" do
    expect(@chart).to include("chtt=Chart+Title")
  end

  it "should allow axis labels positions to be used" do
    expect(Gchart.radar(:custom_axis_with_labels => '0,0,50,100')).to include('chxp=0,0,50,100')
  end
  
  it "should allow array of axis labels positions to be used " do
    expect(Gchart.radar(:custom_axis_with_labels => ['0', '0', '50', '100'])).to include('chxp=0,0,50,100')
  end
end

describe "a line chart" do

  before(:each) do
    @title = 'Chart Title'
    @legend = ['first data set label', 'n data set label']
    @chart = Gchart.line(:title => @title, :legend => @legend)
  end

  it 'should be able have a chart title' do
    expect(@chart).to include("chtt=Chart+Title")
  end

  it "should be able to a custom color, size and alignment for title" do
     expect(Gchart.line(:title => @title, :title_color => 'FF0000')).to include('chts=FF0000')
     expect(Gchart.line(:title => @title, :title_size => '20')).to include('chts=454545,20')
     expect(Gchart.line(:title => @title, :title_size => '20', :title_alignment => :left)).to include('chts=454545,20,l')
  end

  it "should be able to have multiple legends" do
    expect(@chart).to include(Gchart.jstize("chdl=first+data+set+label|n+data+set+label"))
  end

  it "should escape text values in url" do
    title = 'Chart & Title'
    legend = ['first data & set label', 'n data set label']
    chart = Gchart.line(:title => title, :legend => legend)
    expect(chart).to include(Gchart.jstize("chdl=first+data+%26+set+label|n+data+set+label"))
  end

  it "should be able to have one legend" do
    chart = Gchart.line(:legend => 'legend label')
    expect(chart).to include("chdl=legend+label")
  end

  it "should be able to set the position of the legend" do
    title = 'Chart & Title'
    legend = ['first data & set label', 'n data set label']

    chart = Gchart.line(:title => title, :legend => legend, :legend_position => :bottom_vertical)
    expect(chart).to include("chdlp=bv")

    chart = Gchart.line(:title => title, :legend => legend, :legend_position => 'r')
    expect(chart).to include("chdlp=r")
  end

  it "should be able to set the background fill" do
    expect(Gchart.line(:bg => 'efefef')).to include("chf=bg,s,efefef")
    expect(Gchart.line(:bg => {:color => 'efefef', :type => 'solid'})).to include("chf=bg,s,efefef")

    expect(Gchart.line(:bg => {:color => 'efefef', :type => 'gradient'})).to include("chf=bg,lg,0,efefef,0,ffffff,1")
    expect(Gchart.line(:bg => {:color => 'efefef,0,ffffff,1', :type => 'gradient'})).to include("chf=bg,lg,0,efefef,0,ffffff,1")
    expect(Gchart.line(:bg => {:color => 'efefef', :type => 'gradient', :angle => 90})).to include("chf=bg,lg,90,efefef,0,ffffff,1")

    expect(Gchart.line(:bg => {:color => 'efefef', :type => 'stripes'})).to include("chf=bg,ls,90,efefef,0.2,ffffff,0.2")
  end

  it "should be able to set a graph fill" do
    expect(Gchart.line(:graph_bg => 'efefef')).to include("chf=c,s,efefef")
    expect(Gchart.line(:graph_bg => {:color => 'efefef', :type => 'solid'})).to include("chf=c,s,efefef")
    expect(Gchart.line(:graph_bg => {:color => 'efefef', :type => 'gradient'})).to include("chf=c,lg,0,efefef,0,ffffff,1")
    expect(Gchart.line(:graph_bg => {:color => 'efefef,0,ffffff,1', :type => 'gradient'})).to include("chf=c,lg,0,efefef,0,ffffff,1")
    expect(Gchart.line(:graph_bg => {:color => 'efefef', :type => 'gradient', :angle => 90})).to include("chf=c,lg,90,efefef,0,ffffff,1")
  end

  it "should be able to set both a graph and a background fill" do
    expect(Gchart.line(:bg => 'efefef', :graph_bg => '76A4FB')).to match /chf=(bg,s,efefef\|c,s,76A4FB|c,s,76A4FB\|bg,s,efefef)/
  end

  it "should be able to have different line colors" do
    expect(Gchart.line(:line_colors => 'efefef|00ffff')).to include(Gchart.jstize('chco=efefef|00ffff'))
    expect(Gchart.line(:line_color => 'efefef|00ffff')).to include(Gchart.jstize('chco=efefef|00ffff'))
  end

  it "should be able to render a graph where all the data values are 0" do
    expect(Gchart.line(:data => [0, 0, 0])).to include("chd=s:AAA")
  end
end

describe "a sparkline chart" do

  before(:each) do
    @title = 'Chart Title'
    @legend = ['first data set label', 'n data set label']
    @jstized_legend = Gchart.jstize(@legend.join('|'))
    @data = [27,25,25,25,25,27,100,31,25,36,25,25,39,25,31,25,25,25,26,26,25,25,28,25,25,100,28,27,31,25,27,27,29,25,27,26,26,25,26,26,35,33,34,25,26,25,36,25,26,37,33,33,37,37,39,25,25,25,25]
    @chart = Gchart.sparkline(:title => @title, :data => @data, :legend => @legend)
  end

  it "should create a sparkline" do
    expect(@chart).to include('cht=ls')
  end

  it 'should be able have a chart title' do
    expect(@chart).to include("chtt=Chart+Title")
  end

  it "should be able to a custom color and size title" do
     expect(Gchart.sparkline(:title => @title, :title_color => 'FF0000')).to include('chts=FF0000')
     expect(Gchart.sparkline(:title => @title, :title_size => '20')).to include('chts=454545,20')
  end

  it "should be able to have multiple legends" do
    expect(@chart).to include(Gchart.jstize("chdl=first+data+set+label|n+data+set+label"))
  end

  it "should be able to have one legend" do
    chart = Gchart.sparkline(:legend => 'legend label')
    expect(chart).to include("chdl=legend+label")
  end

  it "should be able to set the background fill" do
    expect(Gchart.sparkline(:bg => 'efefef')).to include("chf=bg,s,efefef")
    expect(Gchart.sparkline(:bg => {:color => 'efefef', :type => 'solid'})).to include("chf=bg,s,efefef")

    expect(Gchart.sparkline(:bg => {:color => 'efefef', :type => 'gradient'})).to include("chf=bg,lg,0,efefef,0,ffffff,1")
    expect(Gchart.sparkline(:bg => {:color => 'efefef,0,ffffff,1', :type => 'gradient'})).to include("chf=bg,lg,0,efefef,0,ffffff,1")
    expect(Gchart.sparkline(:bg => {:color => 'efefef', :type => 'gradient', :angle => 90})).to include("chf=bg,lg,90,efefef,0,ffffff,1")

    expect(Gchart.sparkline(:bg => {:color => 'efefef', :type => 'stripes'})).to include("chf=bg,ls,90,efefef,0.2,ffffff,0.2")
  end

  it "should be able to set a graph fill" do
    expect(Gchart.sparkline(:graph_bg => 'efefef')).to include("chf=c,s,efefef")
    expect(Gchart.sparkline(:graph_bg => {:color => 'efefef', :type => 'solid'})).to include("chf=c,s,efefef")
    expect(Gchart.sparkline(:graph_bg => {:color => 'efefef', :type => 'gradient'})).to include("chf=c,lg,0,efefef,0,ffffff,1")
    expect(Gchart.sparkline(:graph_bg => {:color => 'efefef,0,ffffff,1', :type => 'gradient'})).to include("chf=c,lg,0,efefef,0,ffffff,1")
    expect(Gchart.sparkline(:graph_bg => {:color => 'efefef', :type => 'gradient', :angle => 90})).to include("chf=c,lg,90,efefef,0,ffffff,1")
  end

  it "should be able to set both a graph and a background fill" do
    expect(Gchart.sparkline(:bg => 'efefef', :graph_bg => '76A4FB')).to match(/chf=(bg,s,efefef\|c,s,76A4FB|c,s,76A4FB\|bg,s,efefef)/)
  end

  it "should be able to have different line colors" do
    expect(Gchart.sparkline(:line_colors => 'efefef|00ffff')).to include(Gchart.jstize('chco=efefef|00ffff'))
    expect(Gchart.sparkline(:line_color => 'efefef|00ffff')).to include(Gchart.jstize('chco=efefef|00ffff'))
  end
end

describe "a 3d pie chart" do

  before(:each) do
    @title = 'Chart Title'
    @legend = ['first data set label', 'n data set label']
    @jstized_legend = Gchart.jstize(@legend.join('|'))
    @data = [12,8,40,15,5]
    @chart = Gchart.pie(:title => @title, :legend => @legend, :data => @data)
  end

  it "should create a pie" do
    expect(@chart).to include('cht=p')
  end

  it "should be able to be in 3d" do
    expect(Gchart.pie_3d(:title => @title, :legend => @legend, :data => @data)).to include('cht=p3')
  end
end

describe "a google-o-meter" do

  before(:each) do
    @data = [70]
    @legend = ['arrow points here']
    @jstized_legend = Gchart.jstize(@legend.join('|'))
    @chart = Gchart.meter(:data => @data)
  end

  it "should create a meter" do
    expect(@chart).to include('cht=gom')
  end

  it "should be able to set a solid background fill" do
    expect(Gchart.meter(:bg => 'efefef')).to include("chf=bg,s,efefef")
    expect(Gchart.meter(:bg => {:color => 'efefef', :type => 'solid'})).to include("chf=bg,s,efefef")
  end

  it "should be able to set labels by using the legend or labesl accessor" do
    expect(Gchart.meter(:title => @title, :labels => @legend, :data => @data)).to include("chl=#{@jstized_legend}")
    expect(Gchart.meter(:title => @title, :labels => @legend, :data => @data)).to eq(Gchart.meter(:title => @title, :legend => @legend, :data => @data))
  end
end

describe "a map chart" do

  before(:each) do
    @data = [0,100,50,32]
    @geographical_area = 'usa'
    @map_colors = ['FFFFFF', 'FF0000', 'FFFF00', '00FF00']
    @country_codes = ['MT', 'WY', "ID", 'SD']
    @chart = Gchart.map(:data => @data, :encoding => 'text', :size => '400x300',
      :geographical_area => @geographical_area, :map_colors => @map_colors,
      :country_codes => @country_codes)
  end

  it "should create a map" do
    expect(@chart).to include('cht=t')
  end

  it "should set the geographical area" do
    expect(@chart).to include('chtm=usa')
  end

  it "should set the map colors" do
    expect(@chart).to include('chco=FFFFFF,FF0000,FFFF00,00FF00')
  end

  it "should set the country/state codes" do
    expect(@chart).to include('chld=MTWYIDSD')
  end

  it "should set the chart data" do
    expect(@chart).to include('chd=t:0,100,50,32')
  end
end

describe 'exporting a chart' do

  it "should be available in the url format by default" do
    expect(Gchart.line(:data => [0, 26], :format => 'url')).to eq(Gchart.line(:data => [0, 26]))
  end

  it "should be available as an image tag" do
    expect(Gchart.line(:data => [0, 26], :format => 'image_tag')).to match(/<img src=(.*) width="300" height="200" alt="Google Chart" \/>/)
  end

  it "should be available as an image tag using img_tag alias" do
    expect(Gchart.line(:data => [0, 26], :format => 'img_tag')).to match(/<img src=(.*) width="300" height="200" alt="Google Chart" \/>/)
  end

  it "should be available as an image tag using custom dimensions" do
    expect(Gchart.line(:data => [0, 26], :format => 'image_tag', :size => '400x400')).to match(/<img src=(.*) width="400" height="400" alt="Google Chart" \/>/)
  end

  it "should be available as an image tag using custom alt text" do
    expect(Gchart.line(:data => [0, 26], :format => 'image_tag', :alt => 'Sexy chart')).to match(/<img src=(.*) width="300" height="200" alt="Sexy chart" \/>/)
  end

  it "should be available as an image tag using custom title text" do
    expect(Gchart.line(:data => [0, 26], :format => 'image_tag', :title => 'Sexy chart')).to match(/<img src=(.*) width="300" height="200" alt="Google Chart" title="Sexy chart" \/>/)
  end

  it "should be available as an image tag using custom css id selector" do
    expect(Gchart.line(:data => [0, 26], :format => 'image_tag', :id => 'chart')).to match(/<img id="chart" src=(.*) width="300" height="200" alt="Google Chart" \/>/)
  end

  it "should be available as an image tag using custom css class selector" do
    expect(Gchart.line(:data => [0, 26], :format => 'image_tag', :class => 'chart')).to match(/<img class="chart" src=(.*) width="300" height="200" alt="Google Chart" \/>/)
  end

  it "should use ampersands to separate key/value pairs in URLs by default" do
    expect(Gchart.line(:data => [0, 26])).to include "&"
    expect(Gchart.line(:data => [0, 26])).not_to include "&amp;"
  end

  it "should escape ampersands in URLs when used as an image tag" do
    expect(Gchart.line(:data => [0, 26], :format => 'image_tag', :class => 'chart')).to satisfy {|chart| expect(chart).to include "&amp;" }
  end

  it "should be available as a file" do
    File.delete('chart.png') if File.exist?('chart.png')
    Gchart.line(:data => [0, 26], :format => 'file')
    expect(File.exist?('chart.png')).to be
    File.delete('chart.png') if File.exist?('chart.png')
  end

  it "should be available as a file using a custom file name" do
    File.delete('custom_file_name.png') if File.exist?('custom_file_name.png')
    Gchart.line(:data => [0, 26], :format => 'file', :filename => 'custom_file_name.png')
    expect(File.exist?('custom_file_name.png')).to be
    File.delete('custom_file_name.png') if File.exist?('custom_file_name.png')
  end

  it "should work even with multiple attrs" do
    File.delete('foo.png') if File.exist?('foo.png')
    Gchart.line(:size => '400x200',
                :data => [1,2,3,4,5],
                # :axis_labels => [[1,2,3,4, 5], %w[foo bar]],
                :axis_with_labels => 'x,r',
                :format => "file",
                :filename => "foo.png"
                )
    expect(File.exist?('foo.png')).to be
    File.delete('foo.png') if File.exist?('foo.png')
  end
end

describe 'SSL support' do
  it 'should change url if is presented' do
    expect(Gchart.line(:use_ssl => true)).to include('https://chart.googleapis.com/chart?')
  end

  it "should be available as a file" do
    pending "unexpected error under Travis CI (should be fixed using http://martinottenwaelter.fr/2010/12/ruby19-and-the-ssl-error/)"
    File.delete('chart.png') if File.exist?('chart.png')
    Gchart.line(:data => [0, 26], :format => 'file', :use_ssl => true)
    expect(File.exist?('chart.png')).to be_true
    File.delete('chart.png') if File.exist?('chart.png')
  end
end



================================================
FILE: spec/spec_helper.rb
================================================
begin
  require 'rspec'
rescue LoadError
  require 'rubygems'
  gem 'rspec'
  require 'rspec'
end


================================================
FILE: spec/theme_spec.rb
================================================
require File.dirname(__FILE__) + '/spec_helper.rb'
require File.dirname(__FILE__) + '/../lib/gchart'

describe "generating a default Gchart" do
  it 'should be able to add additional theme files' do
    expect(Chart::Theme.theme_files).not_to include("#{File.dirname(__FILE__)}/fixtures/another_test_theme.yml")
    Chart::Theme.add_theme_file("#{File.dirname(__FILE__)}/fixtures/another_test_theme.yml")
    expect(Chart::Theme.theme_files).to include("#{File.dirname(__FILE__)}/fixtures/another_test_theme.yml")
  end
  
  it 'should be able to load themes from the additional theme files' do
    expect { Chart::Theme.load(:test_two) }.not_to raise_error
  end
  
  it 'should raise ThemeNotFound if theme does not exist' do
    expect { Chart::Theme.load(:nonexistent) }.to raise_error(Chart::Theme::ThemeNotFound, "Could not locate the nonexistent theme ...")
  end
  
  it 'should set colors array' do
    expect(Chart::Theme.load(:keynote).colors).to eql(["6886B4", "FDD84E", "72AE6E", "D1695E", "8A6EAF", "EFAA43", "FFFFFF", "000000"])
  end
  
  it 'should set bar colors array' do
    expect(Chart::Theme.load(:keynote).bar_colors).to eql(["6886B4", "FDD84E", "72AE6E", "D1695E", "8A6EAF", "EFAA43"])
  end
  
  it 'should set background' do
    expect(Chart::Theme.load(:keynote).background).to eql("000000")
  end
  
  it 'should set chart background' do
    expect(Chart::Theme.load(:keynote).chart_background).to eql("FFFFFF")
  end
end
Download .txt
gitextract_f4_dov6o/

├── .gitignore
├── .travis.yml
├── Gemfile
├── History.txt
├── License.txt
├── README
├── README.markdown
├── README.txt
├── Rakefile
├── googlecharts.gemspec
├── lib/
│   ├── gchart/
│   │   ├── aliases.rb
│   │   ├── theme.rb
│   │   └── version.rb
│   ├── gchart.rb
│   ├── googlecharts.rb
│   └── themes.yml
└── spec/
    ├── fixtures/
    │   ├── another_test_theme.yml
    │   └── test_theme.yml
    ├── gchart_spec.rb
    ├── spec_helper.rb
    └── theme_spec.rb
Download .txt
SYMBOL INDEX (76 symbols across 5 files)

FILE: lib/gchart.rb
  class Gchart (line 10) | class Gchart
    method url (line 13) | def self.url(use_ssl = false)
    method types (line 21) | def self.types
    method simple_chars (line 25) | def self.simple_chars
    method chars (line 29) | def self.chars
    method ext_pairs (line 33) | def self.ext_pairs
    method default_filename (line 37) | def self.default_filename
    method version (line 67) | def self.version
    method method_missing (line 71) | def self.method_missing(m, options={})
    method initialize (line 75) | def initialize(options={})
    method supported_types (line 108) | def self.supported_types
    method size= (line 114) | def size=(size='300x200')
    method size (line 118) | def size
    method dimensions (line 122) | def dimensions
    method orientation= (line 128) | def orientation=(orientation='h')
    method bar_presentation (line 136) | def bar_presentation
    method bg= (line 146) | def bg=(options)
    method graph_bg= (line 156) | def graph_bg=(options)
    method max_value= (line 166) | def max_value=(max_v)
    method min_value= (line 174) | def min_value=(min_v)
    method full_data_range (line 184) | def full_data_range(ds)
    method dataset (line 242) | def dataset
    method datasets (line 253) | def datasets
    method jstize (line 265) | def self.jstize(string)
    method fetch (line 276) | def fetch
    method write (line 288) | def write
    method image_tag (line 296) | def image_tag
    method url (line 311) | def url
    method file (line 315) | def file
    method jstize (line 320) | def jstize(string)
    method set_title (line 328) | def set_title
    method set_size (line 336) | def set_size
    method set_data (line 340) | def set_data
    method set_colors (line 345) | def set_colors
    method set_bar_colors (line 353) | def set_bar_colors
    method set_country_codes (line 358) | def set_country_codes
    method set_bar_width_and_spacing (line 368) | def set_bar_width_and_spacing
    method set_range_markers (line 385) | def set_range_markers
    method set_range_marker (line 395) | def set_range_marker(options)
    method fill_for (line 400) | def fill_for(type=nil, color='', angle=nil)
    method set_legend (line 421) | def set_legend
    method set_legend_position (line 434) | def set_legend_position
    method set_line_thickness (line 451) | def set_line_thickness
    method set_line_markers (line 455) | def set_line_markers
    method set_grid_lines (line 459) | def set_grid_lines
    method set_labels (line 463) | def set_labels
    method set_axis_with_labels (line 471) | def set_axis_with_labels
    method set_custom_axis_with_labels (line 476) | def set_custom_axis_with_labels
    method set_axis_labels (line 481) | def set_axis_labels
    method set_axis_range (line 503) | def set_axis_range
    method set_geographical_area (line 522) | def set_geographical_area
    method set_type (line 526) | def set_type
    method fill_type (line 545) | def fill_type(type)
    method number_visible (line 553) | def number_visible
    method convert_dataset (line 567) | def convert_dataset(ds)
    method axis_set (line 587) | def axis_set
    method convert_to_simple_value (line 591) | def convert_to_simple_value(number)
    method convert_to_extended_value (line 600) | def convert_to_extended_value(number)
    method encode_scaled_dataset (line 609) | def encode_scaled_dataset(chars, nil_char)
    method simple_encoding (line 642) | def simple_encoding
    method text_encoding (line 658) | def text_encoding
    method extended_encoding (line 666) | def extended_encoding
    method url_builder (line 670) | def url_builder(options="")
    method query_builder (line 674) | def query_builder(options="")

FILE: lib/gchart/aliases.rb
  class Gchart (line 1) | class Gchart

FILE: lib/gchart/theme.rb
  type Chart (line 3) | module Chart
    class Theme (line 4) | class Theme
      class ThemeNotFound (line 5) | class ThemeNotFound < RuntimeError; end
      method load (line 14) | def self.load(theme_name)
      method theme_files (line 18) | def self.theme_files
      method add_theme_file (line 23) | def self.add_theme_file(file)
      method initialize (line 27) | def initialize(theme_name)
      method to_options (line 42) | def to_options

FILE: lib/gchart/version.rb
  type GchartInfo (line 1) | module GchartInfo #:nodoc:

FILE: spec/gchart_spec.rb
  function labeled_line (line 135) | def labeled_line(options = {})
  function labeled_bar (line 145) | def labeled_bar(options = {})
Condensed preview — 21 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (75K chars).
[
  {
    "path": ".gitignore",
    "chars": 56,
    "preview": ".DS_Store\nlog/*\n.manifest\npkg\n.rspec\n.rvmrc\nGemfile.lock"
  },
  {
    "path": ".travis.yml",
    "chars": 78,
    "preview": "language: ruby\nrvm:\n  - 1.8.7\n  - ree\n  - 1.9.2\n  - 1.9.3\n  - 2.0.0\n  - jruby\n"
  },
  {
    "path": "Gemfile",
    "chars": 99,
    "preview": "source \"http://rubygems.org\"\ngemspec\n\ngroup :test do\n  gem 'rspec'\n  gem 'rake', '>= 0.8.7'\nend\n\n\n\n"
  },
  {
    "path": "History.txt",
    "chars": 2033,
    "preview": "== 1.6.12\n* added license to gemspec\n* added pie_c type for concentric pie charts\n\n== 1.6.10\n* added support for custom "
  },
  {
    "path": "License.txt",
    "chars": 1057,
    "preview": "Copyright (c) 2007 Matt Aimonetti\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this "
  },
  {
    "path": "README",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "README.markdown",
    "chars": 11037,
    "preview": "## Googlecharts\n\n[![Build Status](https://travis-ci.org/mattetti/googlecharts.png?branch=master)](https://travis-ci.org/"
  },
  {
    "path": "README.txt",
    "chars": 85,
    "preview": "CHECK README.markdown  (open as a text file)\n\nhttp://github.com/mattetti/googlecharts"
  },
  {
    "path": "Rakefile",
    "chars": 278,
    "preview": "require 'rspec/core/rake_task'\n\ndesc 'Default: run specs.'\ntask :default => :spec\n\ndesc \"Run specs\"\nRSpec::Core::RakeTas"
  },
  {
    "path": "googlecharts.gemspec",
    "chars": 831,
    "preview": "# -*- encoding: utf-8 -*-\n$:.push File.expand_path(\"../lib\", __FILE__)\nrequire \"gchart/version\"\n\nGem::Specification.new "
  },
  {
    "path": "lib/gchart/aliases.rb",
    "chars": 424,
    "preview": "class Gchart\n  \n  alias_method :background=, :bg=\n  alias_method :chart_bg=, :graph_bg=\n  alias_method :chart_color=, :g"
  },
  {
    "path": "lib/gchart/theme.rb",
    "chars": 1183,
    "preview": "require 'yaml'\n\nmodule Chart\n  class Theme\n    class ThemeNotFound < RuntimeError; end\n    \n    @@theme_files = [\"#{File"
  },
  {
    "path": "lib/gchart/version.rb",
    "chars": 52,
    "preview": "module GchartInfo #:nodoc:\n  VERSION = \"1.6.12\"\nend\n"
  },
  {
    "path": "lib/gchart.rb",
    "chars": 20729,
    "preview": "$:.unshift File.dirname(__FILE__)\nrequire 'gchart/version'\nrequire 'gchart/theme'\nrequire \"net/http\"\nrequire \"net/https\""
  },
  {
    "path": "lib/googlecharts.rb",
    "chars": 81,
    "preview": "require 'gchart'\nGooglecharts = Gchart unless Object.const_defined? 'Googlechart'"
  },
  {
    "path": "lib/themes.yml",
    "chars": 1071,
    "preview": "#Default themes ganked from Gruff: http://github.com/topfunky/gruff/tree/master\n:keynote:\n  :colors:\n    - &blue 6886B4\n"
  },
  {
    "path": "spec/fixtures/another_test_theme.yml",
    "chars": 163,
    "preview": ":test_two:\n  :colors:\n    - &blue 6886B4\n    - &yellow FDD84E\n    - &grey 333333\n  :bar_colors: [ *blue, *yellow ]\n  :ba"
  },
  {
    "path": "spec/fixtures/test_theme.yml",
    "chars": 161,
    "preview": ":test:\n  :colors:\n    - &blue 6886B4\n    - &yellow FDD84E\n    - &white FFFFFF\n  :bar_colors: [ *blue, *yellow ]\n  :backg"
  },
  {
    "path": "spec/gchart_spec.rb",
    "chars": 30295,
    "preview": "require File.dirname(__FILE__) + '/spec_helper.rb'\nrequire File.dirname(__FILE__) + '/../lib/gchart'\n\nChart::Theme.add_t"
  },
  {
    "path": "spec/spec_helper.rb",
    "chars": 98,
    "preview": "begin\n  require 'rspec'\nrescue LoadError\n  require 'rubygems'\n  gem 'rspec'\n  require 'rspec'\nend\n"
  },
  {
    "path": "spec/theme_spec.rb",
    "chars": 1450,
    "preview": "require File.dirname(__FILE__) + '/spec_helper.rb'\nrequire File.dirname(__FILE__) + '/../lib/gchart'\n\ndescribe \"generati"
  }
]

About this extraction

This page contains the full source code of the mattetti/googlecharts GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 21 files (69.6 KB), approximately 22.3k tokens, and a symbol index with 76 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!