rgviz-rails 0.67 → 0.68
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +135 -0
- data/lib/rgviz_rails/executor.rb +28 -1
- data/lib/rgviz_rails/init.rb +2 -2
- data/lib/rgviz_rails/parser.rb +2 -2
- data/lib/rgviz_rails/view_helper.rb +11 -7
- metadata +9 -9
- data/README.rdoc +0 -131
data/README.markdown
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
rgviz-rails
|
2
|
+
===========
|
3
|
+
|
4
|
+
this library makes it easy to implement a visualization data source so that you can easily chart or visualize your data from [activerecord](http://ar.rubyonrails.org/) models or from in-memory arrays. the library implements the [google visualization api wire protocol](http://code.google.com/apis/visualization/documentation/dev/implementing_data_source.html).
|
5
|
+
|
6
|
+
it also allows you to [render the visualizations in a view template](https://github.com/asterite/rgviz-rails/wiki/showing-a-visualization-in-a-view) in a very simple but powerful way.
|
7
|
+
|
8
|
+
this library is built on top of [rgviz](https://github.com/asterite/rgviz).
|
9
|
+
|
10
|
+
installation
|
11
|
+
------------
|
12
|
+
|
13
|
+
gem install rgviz-rails
|
14
|
+
|
15
|
+
rails 3
|
16
|
+
-------
|
17
|
+
|
18
|
+
in your gemfile
|
19
|
+
|
20
|
+
gem 'rgviz'
|
21
|
+
gem 'rgviz-rails', :require => 'rgviz_rails'
|
22
|
+
|
23
|
+
rails 2.x
|
24
|
+
---------
|
25
|
+
|
26
|
+
in your environment.rb
|
27
|
+
|
28
|
+
config.gem "rgviz"
|
29
|
+
config.gem "rgviz-rails", :lib => 'rgviz_rails'
|
30
|
+
|
31
|
+
usage
|
32
|
+
-----
|
33
|
+
|
34
|
+
to make a method in your controller be a visualization api endpoint:
|
35
|
+
|
36
|
+
class vizcontroller < applicationcontroller
|
37
|
+
def person
|
38
|
+
# person is an activerecord::base class
|
39
|
+
render :rgviz => person
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
so for example if <tt>person</tt> has <tt>name</tt> and <tt>age</tt>, pointing your browser to:
|
44
|
+
|
45
|
+
http://localhost:3000/viz/person?select name where age > 20 limit 5
|
46
|
+
|
47
|
+
would render the necessary javascript code that implements the google visualization api wire protocol.
|
48
|
+
|
49
|
+
associations
|
50
|
+
------------
|
51
|
+
|
52
|
+
if you want to filter, order by or group by columns that are in a model's association you can use underscores. this is better understood with an example:
|
53
|
+
|
54
|
+
class person < activerecord::base
|
55
|
+
belongs_to :city
|
56
|
+
end
|
57
|
+
|
58
|
+
class city < activerecord::base
|
59
|
+
belongs_to :country
|
60
|
+
end
|
61
|
+
|
62
|
+
class country < activerecord::base
|
63
|
+
end
|
64
|
+
|
65
|
+
to select the name of the city each person belongs to:
|
66
|
+
|
67
|
+
select city_name
|
68
|
+
|
69
|
+
to select the name of the country of the city each person belongs to:
|
70
|
+
|
71
|
+
select city_country_name
|
72
|
+
|
73
|
+
a slightly more complex example:
|
74
|
+
|
75
|
+
select avg(age) where city_country_name = 'argentina' group by city_name
|
76
|
+
|
77
|
+
the library will make it in just one query, writing all the sql joins for you.
|
78
|
+
|
79
|
+
extra conditions
|
80
|
+
----------------
|
81
|
+
|
82
|
+
sometimes you want to limit your results the query will work with. you can do it like this:
|
83
|
+
|
84
|
+
render :rgviz => person, :conditions => ['age > ?', 20]
|
85
|
+
|
86
|
+
or also:
|
87
|
+
|
88
|
+
render :rgviz => person, :conditions => 'age > 20'
|
89
|
+
|
90
|
+
preprocessing
|
91
|
+
-------------
|
92
|
+
|
93
|
+
if you need to tweak a result before returning it, just include a block:
|
94
|
+
|
95
|
+
render :rgviz => person do |table|
|
96
|
+
# modify the rgviz::table object
|
97
|
+
end
|
98
|
+
|
99
|
+
showing a visualization in a view
|
100
|
+
---------------------------------
|
101
|
+
|
102
|
+
you can invoke the rgviz method in your views. [read more about this](https://github.com/asterite/rgviz-rails/wiki/showing-a-visualization-in-a-view).
|
103
|
+
|
104
|
+
you can always do it the [old way](http://code.google.com/apis/visualization/documentation/using_overview.html).
|
105
|
+
|
106
|
+
executing queries over in-memory arrays
|
107
|
+
---------------------------------------
|
108
|
+
|
109
|
+
you can also apply a query over an array of arrays that contains your "records" to be queried.
|
110
|
+
|
111
|
+
types = [[:id, :number], [:name, :string], [:age, :number]]
|
112
|
+
records = [
|
113
|
+
[1, 'john', 23],
|
114
|
+
[2, 'pete', 36]
|
115
|
+
]
|
116
|
+
executor = rgviz::memoryexecutor.new records, types
|
117
|
+
|
118
|
+
render :rgviz => executor
|
119
|
+
|
120
|
+
this is very useful if you need to present visualizations against data coming from a csv file.
|
121
|
+
|
122
|
+
current limitations
|
123
|
+
-------------------
|
124
|
+
|
125
|
+
* the *format* clause works, but formatting is as in ruby (like "%.2f" for numbers, "foo %s bar" for strings, and "%y-%m-%d" for dates, as specified by time#strftime)
|
126
|
+
* only supports mysql, postgresql and sqlite adapters
|
127
|
+
* these scalar functions are not supported for sqlite: *millisecond*, *quarter*
|
128
|
+
* these scalar functions are not supported for mysql: *millisecond*
|
129
|
+
* the function *toDate* doesn't accept a number as its argument
|
130
|
+
* the *tsv* output format is not supported
|
131
|
+
|
132
|
+
contributors
|
133
|
+
------------
|
134
|
+
|
135
|
+
* [brad seefeld](https://github.com/bradseefeld)
|
data/lib/rgviz_rails/executor.rb
CHANGED
@@ -2,6 +2,7 @@ module Rgviz
|
|
2
2
|
class Executor
|
3
3
|
attr_reader :model_class
|
4
4
|
attr_reader :adapter
|
5
|
+
attr_reader :virtual_columns
|
5
6
|
|
6
7
|
def initialize(model_class)
|
7
8
|
@model_class = model_class
|
@@ -27,11 +28,13 @@ module Rgviz
|
|
27
28
|
|
28
29
|
def execute(query, options = {})
|
29
30
|
@query = query
|
30
|
-
@query = RgvizRails::Parser.parse(@query
|
31
|
+
@query = RgvizRails::Parser.parse(@query) unless @query.kind_of?(Query)
|
31
32
|
|
32
33
|
@table = Table.new
|
33
34
|
@extra_conditions = options[:conditions]
|
35
|
+
@virtual_columns = options[:virtual_columns]
|
34
36
|
|
37
|
+
process_virtual_columns
|
35
38
|
process_pivot
|
36
39
|
process_labels
|
37
40
|
process_formats
|
@@ -46,6 +49,17 @@ module Rgviz
|
|
46
49
|
@table
|
47
50
|
end
|
48
51
|
|
52
|
+
def process_virtual_columns
|
53
|
+
return unless @virtual_columns
|
54
|
+
|
55
|
+
@virtual_columns.each do |key, value|
|
56
|
+
if value.is_a?(String) || value[:gql]
|
57
|
+
parser = RgvizRails::Parser.new(value.is_a?(String) ? value : value[:gql])
|
58
|
+
@virtual_columns[key] = {:gql => parser.parse_column}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
49
63
|
def process_labels
|
50
64
|
return unless @query.labels.present?
|
51
65
|
|
@@ -319,6 +333,10 @@ module Rgviz
|
|
319
333
|
def column_type(col)
|
320
334
|
case col
|
321
335
|
when IdColumn
|
336
|
+
if @virtual_columns && (vc = @virtual_columns[col.name])
|
337
|
+
return vc[:gql] ? column_type(vc[:gql]) : vc[:type]
|
338
|
+
end
|
339
|
+
|
322
340
|
klass, rails_col, joins = Rgviz::find_rails_col @model_class, col.name
|
323
341
|
raise "Unknown column #{col}" unless rails_col
|
324
342
|
rails_column_type rails_col
|
@@ -440,6 +458,15 @@ module Rgviz
|
|
440
458
|
end
|
441
459
|
|
442
460
|
def visit_id_column(node)
|
461
|
+
if @executor.virtual_columns && (vc = @executor.virtual_columns[node.name])
|
462
|
+
if vc[:gql]
|
463
|
+
vc[:gql].accept self
|
464
|
+
else
|
465
|
+
@string += vc[:sql]
|
466
|
+
end
|
467
|
+
return
|
468
|
+
end
|
469
|
+
|
443
470
|
klass, rails_col, joins = Rgviz::find_rails_col @executor.model_class, node.name
|
444
471
|
raise "Unknown column '#{node.name}'" unless rails_col
|
445
472
|
@string += ActiveRecord::Base.connection.quote_column_name(klass.table_name)
|
data/lib/rgviz_rails/init.rb
CHANGED
@@ -13,7 +13,7 @@ module Rgviz
|
|
13
13
|
else
|
14
14
|
model = hash[:rgviz]
|
15
15
|
conditions = hash[:conditions]
|
16
|
-
|
16
|
+
virtual_columns = hash[:virtual_columns]
|
17
17
|
query = params[:tq] || 'select *'
|
18
18
|
tqx = params[:tqx] || ''
|
19
19
|
|
@@ -22,7 +22,7 @@ module Rgviz
|
|
22
22
|
begin
|
23
23
|
options = {}
|
24
24
|
options[:conditions] = conditions if conditions
|
25
|
-
options[:
|
25
|
+
options[:virtual_columns] = virtual_columns if virtual_columns
|
26
26
|
|
27
27
|
table = if model.is_a?(Class) && model < ActiveRecord::Base
|
28
28
|
Rgviz::Executor.new(model).execute query, options
|
data/lib/rgviz_rails/parser.rb
CHANGED
@@ -20,14 +20,18 @@ module Rgviz
|
|
20
20
|
events = options[:events] || {}
|
21
21
|
html = options[:html] || {}
|
22
22
|
hidden = options[:hidden]
|
23
|
-
extensions = options[:extensions]
|
24
23
|
conditions = options[:conditions]
|
24
|
+
virtual_columns = options[:virtual_columns]
|
25
25
|
package = options[:package]
|
26
26
|
|
27
27
|
rgviz_events, google_events = events.partition{|x| x[0].to_s.start_with? 'rgviz'}
|
28
28
|
rgviz_events = rgviz_events.inject(Hash.new){|h, y| h[y[0]] = y[1]; h}
|
29
29
|
rgviz_events = rgviz_events.with_indifferent_access
|
30
30
|
|
31
|
+
ajax = options.has_key?(:ajax) && options[:ajax]
|
32
|
+
load_package = !ajax && (!options.has_key?(:load_package) || options[:load_package])
|
33
|
+
load_google = !ajax && (!options.has_key?(:load_google) || options[:load_google])
|
34
|
+
|
31
35
|
html_prefix = (options[:html_prefix] || 'html').to_s
|
32
36
|
js_prefix = (options[:js_prefix] || 'js').to_s
|
33
37
|
param_prefix = (options[:param_prefix] || 'param').to_s
|
@@ -87,7 +91,7 @@ module Rgviz
|
|
87
91
|
url = url_for url unless custom_executor
|
88
92
|
|
89
93
|
# Parse the query
|
90
|
-
query = RgvizRails::Parser.parse query
|
94
|
+
query = RgvizRails::Parser.parse query
|
91
95
|
|
92
96
|
# And replace the html_ and javascript_ magic names
|
93
97
|
query.accept visitor
|
@@ -104,7 +108,7 @@ module Rgviz
|
|
104
108
|
|
105
109
|
# Output the google jsapi tag the first time
|
106
110
|
@first_time ||= 1
|
107
|
-
if @first_time == 1
|
111
|
+
if load_google && @first_time == 1
|
108
112
|
out << "<script type=\"text/javascript\" src=\"http://www.google.com/jsapi\"></script>\n"
|
109
113
|
end
|
110
114
|
# Now the real script
|
@@ -150,7 +154,7 @@ module Rgviz
|
|
150
154
|
@defined_rgviz_append = true
|
151
155
|
end
|
152
156
|
|
153
|
-
if
|
157
|
+
if load_package
|
154
158
|
# Load visualizations and the package, if not already loaded
|
155
159
|
package ||= get_package(kind)
|
156
160
|
|
@@ -165,7 +169,7 @@ module Rgviz
|
|
165
169
|
|
166
170
|
# Set the callback if the function doesn't have params and if the
|
167
171
|
# user didn't request to hide the visualization
|
168
|
-
if !hidden && params.empty?
|
172
|
+
if !ajax && !hidden && params.empty?
|
169
173
|
out << "google.setOnLoadCallback(#{callback});\n"
|
170
174
|
end
|
171
175
|
|
@@ -194,7 +198,7 @@ module Rgviz
|
|
194
198
|
else
|
195
199
|
executor_options = {}
|
196
200
|
executor_options[:conditions] = conditions if conditions
|
197
|
-
executor_options[:
|
201
|
+
executor_options[:virtual_columns] = virtual_columns if virtual_columns
|
198
202
|
|
199
203
|
table = if url.is_a?(Class) and url < ActiveRecord::Base
|
200
204
|
Rgviz::Executor.new(url).execute(query, executor_options)
|
@@ -216,7 +220,7 @@ module Rgviz
|
|
216
220
|
out << "});\n"
|
217
221
|
end
|
218
222
|
out << "}\n"
|
219
|
-
|
223
|
+
out << "#{callback}()" if ajax
|
220
224
|
out << "</script>\n"
|
221
225
|
|
222
226
|
# Write the div
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rgviz-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.68'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,22 +9,22 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-07-23 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rgviz
|
16
|
-
requirement: &
|
16
|
+
requirement: &70314626649780 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: '0.
|
21
|
+
version: '0.46'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70314626649780
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rails
|
27
|
-
requirement: &
|
27
|
+
requirement: &70314626649300 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,13 +32,13 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70314626649300
|
36
36
|
description:
|
37
37
|
email: aborenszweig@manas.com.ar
|
38
38
|
executables: []
|
39
39
|
extensions: []
|
40
40
|
extra_rdoc_files:
|
41
|
-
- README.
|
41
|
+
- README.markdown
|
42
42
|
files:
|
43
43
|
- lib/rgviz_rails.rb
|
44
44
|
- lib/rgviz_rails/executor.rb
|
@@ -51,7 +51,7 @@ files:
|
|
51
51
|
- lib/rgviz_rails/adapters/sqlite_adapter.rb
|
52
52
|
- lib/rgviz_rails/init.rb
|
53
53
|
- rails/init.rb
|
54
|
-
- README.
|
54
|
+
- README.markdown
|
55
55
|
homepage: http://github.com/asterite/rgviz-rails
|
56
56
|
licenses: []
|
57
57
|
post_install_message:
|
data/README.rdoc
DELETED
@@ -1,131 +0,0 @@
|
|
1
|
-
== Rgviz-rails
|
2
|
-
|
3
|
-
This library makes it easy to implement a Visualization data source so that you can easily chart or visualize your data from ActiveRecord[http://ar.rubyonrails.org/] models or from in-memory arrays. The library implements the {Google Visualization API wire protocol}[http://code.google.com/apis/visualization/documentation/dev/implementing_data_source.html].
|
4
|
-
|
5
|
-
It also allows you to {render the visualizations in a view template}[https://github.com/asterite/rgviz-rails/wiki/Showing-a-visualization-in-a-view] in a very simple but powerful way.
|
6
|
-
|
7
|
-
This library is built on top of rgviz[https://github.com/asterite/rgviz].
|
8
|
-
|
9
|
-
=== Installation
|
10
|
-
|
11
|
-
gem install rgviz-rails
|
12
|
-
|
13
|
-
=== Rails 3
|
14
|
-
|
15
|
-
In your Gemfile
|
16
|
-
|
17
|
-
gem 'rgviz'
|
18
|
-
gem 'rgviz-rails', :require => 'rgviz_rails'
|
19
|
-
|
20
|
-
=== Rails 2.x
|
21
|
-
|
22
|
-
In your environment.rb
|
23
|
-
|
24
|
-
config.gem "rgviz"
|
25
|
-
config.gem "rgviz-rails", :lib => 'rgviz_rails'
|
26
|
-
|
27
|
-
=== Usage
|
28
|
-
|
29
|
-
To make a method in your controller be a visualization API endpoint:
|
30
|
-
|
31
|
-
class VizController < ApplicationController
|
32
|
-
|
33
|
-
def person
|
34
|
-
# Person is an ActiveRecord::Base class
|
35
|
-
render :rgviz => Person
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
|
-
So for example if +Person+ has +name+ and +age+, pointing your browser to:
|
41
|
-
|
42
|
-
http://localhost:3000/viz/person?select name where age > 20 limit 5
|
43
|
-
|
44
|
-
would render the necessary javascript code that implements the Google Visualization API wire protocol.
|
45
|
-
|
46
|
-
=== Extensions
|
47
|
-
|
48
|
-
To enable the extensions defined by rgviz you need to specify it in the render method:
|
49
|
-
|
50
|
-
render :rgviz => Person, :extensions => true
|
51
|
-
|
52
|
-
=== Associations
|
53
|
-
|
54
|
-
If you want to filter, order by or group by columns that are in a model's association you can use underscores. This is better understood with an example:
|
55
|
-
|
56
|
-
class Person < ActiveRecord::Base
|
57
|
-
belongs_to :city
|
58
|
-
end
|
59
|
-
|
60
|
-
class City < ActiveRecord::Base
|
61
|
-
belongs_to :country
|
62
|
-
end
|
63
|
-
|
64
|
-
class Country < ActiveRecord::Base
|
65
|
-
end
|
66
|
-
|
67
|
-
To select the name of the city each person belongs to:
|
68
|
-
|
69
|
-
select city_name
|
70
|
-
|
71
|
-
To select the name of the country of the city each person belongs to:
|
72
|
-
|
73
|
-
select city_country_name
|
74
|
-
|
75
|
-
A slightly more complex example:
|
76
|
-
|
77
|
-
select avg(age) where city_country_name = 'Argentina' group by city_name
|
78
|
-
|
79
|
-
The library will make it in just one query, writing all the SQL joins for you.
|
80
|
-
|
81
|
-
=== Extra conditions
|
82
|
-
|
83
|
-
Sometimes you want to limit your results the query will work with. You can do it like this:
|
84
|
-
|
85
|
-
render :rgviz => Person, :conditions => ['age > ?', 20]
|
86
|
-
|
87
|
-
Or also:
|
88
|
-
|
89
|
-
render :rgviz => Person, :conditions => 'age > 20'
|
90
|
-
|
91
|
-
=== Preprocessing
|
92
|
-
|
93
|
-
If you need to tweak a result before returning it, just include a block:
|
94
|
-
|
95
|
-
render :rgviz => Person do |table|
|
96
|
-
# Modify the Rgviz::Table object
|
97
|
-
end
|
98
|
-
|
99
|
-
=== Showing a visualization in a view
|
100
|
-
|
101
|
-
You can invoke the rgviz method in your views. {Read more about this}[https://github.com/asterite/rgviz-rails/wiki/Showing-a-visualization-in-a-view].
|
102
|
-
|
103
|
-
You can always do it the {old way}[http://code.google.com/apis/visualization/documentation/using_overview.html].
|
104
|
-
|
105
|
-
=== Executing queries over in-memory arrays
|
106
|
-
|
107
|
-
You can also apply a query over an array of arrays that contains your "records" to be queried.
|
108
|
-
|
109
|
-
types = [[:id, :number], [:name, :string], [:age, :number]]
|
110
|
-
records = [
|
111
|
-
[1, 'John', 23],
|
112
|
-
[2, 'Pete', 36]
|
113
|
-
]
|
114
|
-
executor = Rgviz::MemoryExecutor.new records, types
|
115
|
-
|
116
|
-
render :rgviz => executor
|
117
|
-
|
118
|
-
This is very useful if you need to present visualizations against data coming from a CSV file.
|
119
|
-
|
120
|
-
=== Current Limitations
|
121
|
-
|
122
|
-
* The *format* clause works, but formatting is as in ruby (like "%.2f" for numbers, "foo %s bar" for strings, and "%Y-%m-%d" for dates, as specified by Time#strftime)
|
123
|
-
* Only supports MySQL, PostgreSQL and SQLite adapters
|
124
|
-
* These scalar functions are not supported for SQLite: *millisecond*, *quarter*
|
125
|
-
* These scalar functions are not supported for MySQL: *millisecond*
|
126
|
-
* The function *toDate* doesn't accept a number as its argument
|
127
|
-
* The *tsv* output format is not supported
|
128
|
-
|
129
|
-
=== Contributors
|
130
|
-
|
131
|
-
* {Brad Seefeld}[https://github.com/bradseefeld]
|