Skip to content

Commit

Permalink
Initial Commit includes adding documenation from personal repo
Browse files Browse the repository at this point in the history
  • Loading branch information
Max Warnock committed Jun 26, 2008
0 parents commit ee8e835
Show file tree
Hide file tree
Showing 10 changed files with 309 additions and 0 deletions.
20 changes: 20 additions & 0 deletions MIT-LICENSE
@@ -0,0 +1,20 @@
Copyright (c) 2008 [name of plugin creator]

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.
35 changes: 35 additions & 0 deletions README
@@ -0,0 +1,35 @@
GoogleVisualization
===================

This plugin currently covers the motion chart (gap minder) google visualization. You can see an example of one here: http://googlesystem.blogspot.com/2008/03/google-spreadsheets-adds-gadgets.html


Example
=======

In order to use the plugin you simply need to install it into your rails app and then have the following code in a view:

#Model
class FakeModel < ActiveRecord::Base
#this is a fake model and can be replaced with any object
#I've defined some fake attribute accessors below
attr_accessors :group, :created_at, :x, :y, :z, :more_data_1, :more_data_2
end

#Controller
def index
@collection = FakeModel.find(:all)
end

#View (Here is the important stuff)
<% gap_minder_for(@collection, :width => 500, :height => 300) do |gm| %>
<% gm.label("Department Group") {|collection_item| collection_item.group } %>
<% gm.time("Created At") {|collection_item| collection_item.created_at } %>
<% gm.x("X") {|collection_item| collection_item.x } %>
<% gm.y("Y") {|collection_item| collection_item.y } %>
<% gm.bubble_size("Z") {|collection_item| collection_item.z } %>
<% gm.extra_column("More Data 1") {|collection_item| collection_item.more_data_1 } %>
<% gm.extra_column("More Data 2") {|collection_item| collection_item.more_data_2 } %>
<% end %>

Copyright (c) 2008 [name of plugin creator], released under the MIT license
22 changes: 22 additions & 0 deletions Rakefile
@@ -0,0 +1,22 @@
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'

desc 'Default: run unit tests.'
task :default => :test

desc 'Test the google_visualization plugin.'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.pattern = 'test/**/*_test.rb'
t.verbose = true
end

desc 'Generate documentation for the google_visualization plugin.'
Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'GoogleVisualization'
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.rdoc_files.include('README')
rdoc.rdoc_files.include('lib/**/*.rb')
end
2 changes: 2 additions & 0 deletions init.rb
@@ -0,0 +1,2 @@
# Include hook code here
ActionView::Base.send :include, GoogleVisualization::Helpers
1 change: 1 addition & 0 deletions install.rb
@@ -0,0 +1 @@
# Install hook code here
5 changes: 5 additions & 0 deletions lib/.autotest
@@ -0,0 +1,5 @@
Autotest.add_hook :initialize do |at|
at.add_mapping(%r%.*\.rb$%) {
at.files_matching %r%^spec_.*\.rb$%
}
end
142 changes: 142 additions & 0 deletions lib/google_visualization.rb
@@ -0,0 +1,142 @@
# GoogleVisualization
module GoogleVisualization
class GapMinder

attr_reader :collection, :collection_methods, :options, :size, :helpers, :procedure_hash, :name

def method_missing(method, *args, &block)
if Mappings.columns.include?(method)
procedure_hash[method] = [args[0], block]
else
helpers.send(method, *args, &block)
end
end

def initialize(view_instance, collection, options={}, *args)
@helpers = view_instance
@collection = collection
@collection_methods = collection_methods
@options = options.reverse_merge({:width => 600, :height => 300})
@columns = []
@rows = []
@procedure_hash = {:color => ["Department", lambda {|item| label_to_color(@procedure_hash[:label][1].call(item)) }] }
@size = collection.size
@name = "gap_minder_#{self.id.to_s.gsub("-","")}"
@labels = {}
@color_count = 0
end

def header
content_tag(:div, "", :id => name, :style => "width: #{options[:width]}px; height: #{options[:height]}px;")
end

def body
javascript_tag do
"var data = new google.visualization.DataTable();\n" +
"data.addRows(#{size});\n" +
render_columns +
render_rows +
"var #{name} = new google.visualization.MotionChart(document.getElementById('#{name}'));\n" +
"#{name}.draw(data, {width: #{options[:width]}, height: #{options[:height]}});"
end
end

def render
header + "\n" + body
end

def render_columns
if required_methods_supplied?
Mappings.columns.each { |c| @columns << gap_minder_add_column(procedure_hash[c]) }
procedure_hash.each { |key, value| @columns << gap_minder_add_column(value) if not Mappings.columns.include?(key) }
@columns.join("\n")
end
end

def render_rows
if required_methods_supplied?
collection.each_with_index do |item, index|
Mappings.columns.each_with_index {|name,column_index| @rows << gap_minder_set_value(index, column_index, procedure_hash[name][1].call(item)) }
procedure_hash.each {|key,value| @rows << gap_minder_set_value(index, key, procedure_hash[key][1].call(item)) unless Mappings.columns.include?(key) }
end
@rows.join("\n")
end
end

def required_methods_supplied?
Mappings.columns.each do |key|
unless procedure_hash.has_key? key
raise "GapMinder Must have the #{key} method called before it can be rendered"
end
end
end

def gap_minder_add_column(title_proc_tuple)
title = title_proc_tuple[0]
procedure = title_proc_tuple[1]
"data.addColumn('#{google_type(procedure)}','#{title}');\n"
end

def gap_minder_set_value(row, column, value)
"data.setValue(#{row}, #{column}, #{Mappings.ruby_to_javascript_object(value)});\n"
end

def google_type(procedure)
Mappings.ruby_to_google_type(procedure.call(collection[0]).class)
end

def google_formatted_value(value)
Mappings.ruby_to_javascript_object(value)
end

def label_to_color(label)
hashed_label = label.downcase.gsub(" |-","_").to_sym
if @labels.has_key? hashed_label
@labels[hashed_label]
else
@color_count += 1
@labels[hashed_label] = @color_count
end
end

def extra_column(title, &block)
procedure_hash[procedure_hash.size] = [title, block]
end

end

module Mappings
def self.ruby_to_google_type(type)
type_hash = {
:String => "string",
:Fixnum => "number",
:Float => "number",
:Date => "date",
:Time => "datetime"
}
type_hash[type.to_s.to_sym]
end

def self.ruby_to_javascript_object(value)
value_hash = {
:String => lambda {|v| "'#{v}'"},
:Date => lambda {|v| "new Date(#{v.to_s.gsub("-",",")})"},
:Fixnum => lambda {|v| v },
:Float => lambda {|v| v }
}
value_hash[value.class.to_s.to_sym].call(value)
end

def self.columns
[:label, :time, :x, :y, :color, :bubble_size]
end
end

module Helpers
def gap_minder_for(collection, options={}, *args, &block)
gap_minder = GapMinder.new(self, collection, options)
yield gap_minder
concat(gap_minder.render, block.binding)
end
end
end
77 changes: 77 additions & 0 deletions lib/spec_google_visualization.rb
@@ -0,0 +1,77 @@
require 'active_support'
require 'spec'
require 'google_visualization.rb'

class CollectionFixture
attr_accessor :label, :time, :x, :y, :bubble_size, :extra, :extra_2

def initialize(attributes)
attributes.each {|key,value| self.send((key.to_s + "=").to_sym, value)}
end
end

describe GoogleVisualization do
describe GoogleVisualization::GapMinder do
before do
@collection = [CollectionFixture.new(:label => "Monkey", :time => Date.today, :x => 5, :y => 10, :bubble_size => 50, :extra => 1, :extra_2 => 2)]

@gap_minder = GoogleVisualization::GapMinder.new(self, @collection)
@gap_minder.label("Department") {|cf| cf.label}
@gap_minder.time("Time of Year") {|cf| cf.time}
@gap_minder.x("X Axis") {|cf| cf.x}
@gap_minder.y("Y Axis") {|cf| cf.y}
@gap_minder.bubble_size("Bubble Size") {|cf| cf.bubble_size}
@gap_minder.extra_column("Extra") {|cf| cf.extra }
@gap_minder.extra_column("Extra 2") {|cf| cf.extra_2 }

@invalid_gap_minder = GoogleVisualization::GapMinder.new(self, @collection)
end

it "should build a valid procedure_hash" do
@gap_minder.procedure_hash.should be_instance_of(Hash)
@gap_minder.procedure_hash.should_not be_empty
@gap_minder.procedure_hash.each do |key,value|
@gap_minder.procedure_hash[key].should be_instance_of(Array)
#key.should be_instance_of(Symbol)
value[0].should be_instance_of(String)
value[1].should be_instance_of(Proc)
end
end

it "should render valid columns" do
puts "\n"
puts @gap_minder.render_columns
end

it "should render valid rows" do
puts "\n"
puts @gap_minder.render_rows
end

it "should raise and exception" do
lambda {@invalid_gap_minder.render_columns}.should raise_error
end

end

describe GoogleVisualization::Mappings do
it "#ruby_to_google_type should produce the correct types" do
GoogleVisualization::Mappings.ruby_to_google_type(String).should == "string"
GoogleVisualization::Mappings.ruby_to_google_type(Date).should == "date"
GoogleVisualization::Mappings.ruby_to_google_type(Fixnum).should == "number"
GoogleVisualization::Mappings.ruby_to_google_type(Float).should == "number"
GoogleVisualization::Mappings.ruby_to_google_type(Time).should == "datetime"
end

it "#ruby_to_javascript_object should produce the correct javascript" do
GoogleVisualization::Mappings.ruby_to_javascript_object(Date.parse("2008-01-02")).should == "new Date(2008,01,02)"
GoogleVisualization::Mappings.ruby_to_javascript_object("my string").should == "'my string'"
GoogleVisualization::Mappings.ruby_to_javascript_object(8).should == 8
GoogleVisualization::Mappings.ruby_to_javascript_object(8.6).should == 8.6
end

it "#columns should be a list of symbols" do
GoogleVisualization::Mappings.columns.should be_instance_of Array
end
end
end
4 changes: 4 additions & 0 deletions tasks/google_visualization_tasks.rake
@@ -0,0 +1,4 @@
# desc "Explaining what the task does"
# task :google_visualization do
# # Task goes here
# end
1 change: 1 addition & 0 deletions uninstall.rb
@@ -0,0 +1 @@
# Uninstall hook code here

0 comments on commit ee8e835

Please sign in to comment.