fusion_tables 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -0
- data/CHANGELOG +16 -0
- data/README.md +122 -0
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/examples/boris_bikes.rb +159 -0
- data/examples/compare_tweets.rb +1 -1
- data/fusion_tables.gemspec +8 -12
- data/lib/fusion_tables/data/table.rb +27 -21
- data/test/test_client.rb +3 -3
- data/test/test_ext.rb +12 -12
- data/test/test_table.rb +27 -12
- metadata +15 -13
- data/README.textile +0 -144
- data/pkg/fusion_tables-0.1.0.gem +0 -0
- data/pkg/fusion_tables-0.1.1.gem +0 -0
- data/pkg/fusion_tables-0.1.2.gem +0 -0
- data/pkg/fusion_tables-0.2.0.gem +0 -0
- data/pkg/fusion_tables-0.2.1.gem +0 -0
- data/pkg/fusion_tables-0.2.2.gem +0 -0
data/.gitignore
CHANGED
data/CHANGELOG
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
== 0.2.3 (03/06/11)
|
2
|
+
|
3
|
+
* all tests pass
|
4
|
+
* readme simplified
|
5
|
+
* count now returns 0 for empty tables
|
6
|
+
* truncate table, or delete all rows (sikachu)
|
7
|
+
* fix up the single update row method (sikachu)
|
8
|
+
* if value is nil, insert empty string (wynst)
|
9
|
+
* fixes to exception handling and tests (troy)
|
10
|
+
|
11
|
+
== 0.2.2
|
12
|
+
|
13
|
+
* 1.9.2 compatibility through gdata_19 gem
|
14
|
+
* examples updated for 1.9.2
|
15
|
+
* datetime columns now include time
|
16
|
+
|
data/README.md
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
fusion-tables
|
2
|
+
==============
|
3
|
+
|
4
|
+
This gem lets you easily interact with [Google Fusion Tables](http://www.google.com/fusiontables/Home) from your Ruby application. Read more in this [Blog post](http://www.tokumine.com/2010/08/10/fusion-tables-gem/).
|
5
|
+
|
6
|
+
Demo and examples
|
7
|
+
------------------
|
8
|
+
|
9
|
+
* Twitter [demo](http://tables.googlelabs.com/DataSource?snapid=73106) / [code](http://github.com/tokumine/fusion-tables/blob/master/examples/compare_tweets.rb)
|
10
|
+
* Boris bike [demo](http://tables.googlelabs.com/DataSource?snapid=78314) / [code](http://github.com/tokumine/fusion-tables/blob/master/examples/boris_bikes.rb)
|
11
|
+
* [Tests](http://github.com/tokumine/fusion-tables/tree/master/test/)
|
12
|
+
|
13
|
+
Installation
|
14
|
+
-------------
|
15
|
+
|
16
|
+
``` bash
|
17
|
+
gem install fusion_tables
|
18
|
+
```
|
19
|
+
|
20
|
+
**Gem Dependencies**
|
21
|
+
|
22
|
+
* gdata_19 >= 1.1.2
|
23
|
+
|
24
|
+
**Rubies**
|
25
|
+
|
26
|
+
* 1.8.7
|
27
|
+
* 1.9.2
|
28
|
+
|
29
|
+
Usage
|
30
|
+
------
|
31
|
+
``` ruby
|
32
|
+
require 'fusion_tables'
|
33
|
+
|
34
|
+
# Connect to service
|
35
|
+
@ft = GData::Client::FusionTables.new
|
36
|
+
@ft.clientlogin(username, password)
|
37
|
+
|
38
|
+
# Browse existing tables
|
39
|
+
@ft.show_tables
|
40
|
+
# => [table_1, table_2]
|
41
|
+
|
42
|
+
# Getting table id suitable for using with google maps (see more below)
|
43
|
+
table_1.id #=> 42342 (the table's google id)
|
44
|
+
|
45
|
+
# Count data
|
46
|
+
table_1.count #=> 1
|
47
|
+
|
48
|
+
# Select data
|
49
|
+
table_1.select
|
50
|
+
#=> data
|
51
|
+
|
52
|
+
# Select data with conditions
|
53
|
+
table_1.select "name", "WHERE x=n"
|
54
|
+
#=> data
|
55
|
+
|
56
|
+
# Select ROWIDs
|
57
|
+
row_ids = table_1.select "ROWID"
|
58
|
+
|
59
|
+
# Drop tables
|
60
|
+
@ft.drop table_1.id # table id
|
61
|
+
@ft.drop [table_1.id, table_2.id] # arrays of table ids
|
62
|
+
@ft.drop /yacht/ # regex on table name
|
63
|
+
|
64
|
+
# Creating a table
|
65
|
+
cols = [{:name => "friend name", :type => 'string' },
|
66
|
+
{:name => "age", :type => 'number' },
|
67
|
+
{:name => "meeting time", :type => 'datetime' },
|
68
|
+
{:name => "where", :type => 'location' }]
|
69
|
+
|
70
|
+
new_table = @ft.create_table "My upcoming meetings", cols
|
71
|
+
|
72
|
+
# Inserting rows (auto chunks every 500)
|
73
|
+
data = [{"friend name" => "Eric Wimp",
|
74
|
+
"age" => 25,
|
75
|
+
"meeting time" => Time.utc(2010,"aug",10,20,15,1),
|
76
|
+
"where" => "29 Acacia Road, Nuttytown"}]
|
77
|
+
new_table.insert data
|
78
|
+
|
79
|
+
# Delete row
|
80
|
+
new_table.delete row_id
|
81
|
+
```
|
82
|
+
|
83
|
+
Currently only single row UPDATE query is implemented.
|
84
|
+
|
85
|
+
``` ruby
|
86
|
+
row_id = 1
|
87
|
+
data = [{"friend name" => "Eric Wimp",
|
88
|
+
"age" => 25,
|
89
|
+
"meeting time" => Time.utc(2010,"aug",10,20,15,1),
|
90
|
+
"where" => "29 Acacia Road, Nuttytown"}]
|
91
|
+
new_table.update row_id, data
|
92
|
+
```
|
93
|
+
|
94
|
+
Known Issues
|
95
|
+
-------------
|
96
|
+
|
97
|
+
* The Google gdata_19 gem conflicts with the GData2 gem. Only current fix is to uninstall GData2.
|
98
|
+
* You have to make a table public before you can display it on a map. This can only be done via FT web interface.
|
99
|
+
|
100
|
+
Note on Patches/Pull Requests
|
101
|
+
------------------------------
|
102
|
+
|
103
|
+
* Fork the project.
|
104
|
+
* Make your feature addition or bug fix.
|
105
|
+
* Add tests for it. This is important so I don't break it in a
|
106
|
+
future version unintentionally.
|
107
|
+
* Commit, do not mess with rakefile, version, or history.
|
108
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
109
|
+
* Send me a pull request. Bonus points for topic branches.
|
110
|
+
|
111
|
+
|
112
|
+
|
113
|
+
Contributors
|
114
|
+
-------------
|
115
|
+
|
116
|
+
Largely based on Tom Verbeure's [work for MTBGuru](http://code.google.com/p/mtbguru-fusiontables/)
|
117
|
+
|
118
|
+
* tokumine
|
119
|
+
* sikachu
|
120
|
+
* troy
|
121
|
+
* wynst
|
122
|
+
|
data/Rakefile
CHANGED
@@ -12,6 +12,7 @@ begin
|
|
12
12
|
gem.authors = ["Simon Tokumine", "Tom Verbeure"]
|
13
13
|
gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
14
14
|
gem.add_dependency "gdata_19", ">= 1.1.2"
|
15
|
+
gem.files.exclude 'pkg'
|
15
16
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
17
|
end
|
17
18
|
Jeweler::GemcutterTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.3
|
@@ -0,0 +1,159 @@
|
|
1
|
+
# This library creates a FT and posts data from the Boris Bikes API to it every minute
|
2
|
+
#
|
3
|
+
# Add photos to infowindow
|
4
|
+
# Add fusion table graphs to the inside of the infowindows too
|
5
|
+
|
6
|
+
|
7
|
+
require 'net/http'
|
8
|
+
require 'uri'
|
9
|
+
require 'rubygems'
|
10
|
+
require 'geo_ruby'
|
11
|
+
require 'fusion_tables'
|
12
|
+
require 'time'
|
13
|
+
require 'json'
|
14
|
+
require 'yaml'
|
15
|
+
require 'ap'
|
16
|
+
include GeoRuby
|
17
|
+
include SimpleFeatures
|
18
|
+
|
19
|
+
class Object
|
20
|
+
def try(method, *args, &block)
|
21
|
+
send(method, *args, &block)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def color max, number_to_color, min=0, opacity=80
|
26
|
+
color = ["FFFFB2", "FFFFB2", "FEB24C", "FD8D3C", "F03B20", "BD0026"]
|
27
|
+
#color = %w(FEE0D2 FCBBA1 FC9272 FB6A4A EF3B2C CB181D A50F15 67000D)
|
28
|
+
color.reverse!
|
29
|
+
#color = ["FFFFCC", "D9F0A3", "ADDD8E", "78C679", "31A354", "31A354"] #<- greens
|
30
|
+
chunk = (max-min)/color.size
|
31
|
+
index = (number_to_color/chunk).floor
|
32
|
+
"#{color[index]}#{opacity}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_google(x,y)
|
36
|
+
a = `echo "#{x} #{y}" | cs2cs + +init=epsg:4326 +to +init=epsg:3785 -f "%.12f"`
|
37
|
+
a = a.split(" ")
|
38
|
+
{:x => a[0], :y => a[1]}
|
39
|
+
end
|
40
|
+
|
41
|
+
def from_google(x,y)
|
42
|
+
a = `echo "#{x} #{y}" | cs2cs + +init=epsg:3785 +to +init=epsg:4326 -f "%.12f"`
|
43
|
+
a = a.split(" ")
|
44
|
+
{:x => a[0], :y => a[1]}
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def buffer(center_x, center_y, radius, quality = 4, precision = 12)
|
49
|
+
points = []
|
50
|
+
radians = Math::PI / 180
|
51
|
+
|
52
|
+
coords = to_google(center_x, center_y)
|
53
|
+
center_x = coords[:x].to_f
|
54
|
+
center_y = coords[:y].to_f
|
55
|
+
|
56
|
+
0.step(360, quality) do |i|
|
57
|
+
x = center_x + (radius * Math.cos(i * radians))
|
58
|
+
y = center_y + (radius * Math.sin(i * radians))
|
59
|
+
coords = from_google(x,y)
|
60
|
+
points << Point.from_x_y(round(coords[:x].to_f, precision), round(coords[:y].to_f, precision))
|
61
|
+
end
|
62
|
+
points
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def round number, precision = 12
|
67
|
+
(number * 10**precision).round.to_f / 10**precision
|
68
|
+
end
|
69
|
+
|
70
|
+
# Configure settings
|
71
|
+
config = YAML::load_file(File.join(File.dirname(__FILE__), 'credentials.yml'))
|
72
|
+
DEFAULT_SRID = 4328
|
73
|
+
|
74
|
+
|
75
|
+
# Configure fusion tables
|
76
|
+
ft = GData::Client::FusionTables.new
|
77
|
+
ft.clientlogin(config["google_username"], config["google_password"])
|
78
|
+
table_name = "Boris Bikes"
|
79
|
+
cols = [
|
80
|
+
{:name => 'name', :type => 'string'},
|
81
|
+
{:name => 'created_at', :type => 'datetime'},
|
82
|
+
{:name => 'updated_at', :type => 'datetime'},
|
83
|
+
{:name => 'boris_id', :type => 'number'},
|
84
|
+
{:name => 'temporary', :type => 'number'},
|
85
|
+
{:name => 'installed', :type => 'number'},
|
86
|
+
{:name => 'locked', :type => 'number'},
|
87
|
+
{:name => 'nb_empty_docs',:type => 'number'},
|
88
|
+
{:name => 'nb_bikes', :type => 'number'},
|
89
|
+
{:name => 'nb_docs', :type => 'number'},
|
90
|
+
{:name => 'image', :type => 'string'},
|
91
|
+
{:name => 'geom', :type => 'location'},
|
92
|
+
{:name => 'geom_fill', :type => 'string'},
|
93
|
+
{:name => 'geom_border', :type => 'string'},
|
94
|
+
]
|
95
|
+
|
96
|
+
# Create FT if it doesn't exist
|
97
|
+
tables = ft.show_tables
|
98
|
+
table = tables.select{|t| t.name == table_name}.first
|
99
|
+
table = ft.create_table(table_name, cols) if !table
|
100
|
+
|
101
|
+
while true do
|
102
|
+
bikes = JSON.parse(Net::HTTP.get(URI.parse('http://borisapi.heroku.com/stations.json')))
|
103
|
+
|
104
|
+
# get largest bike rack to calibrate buffer
|
105
|
+
max = 0
|
106
|
+
bikes.each do |b|
|
107
|
+
slots = b["nb_empty_docks"] + b["nb_bikes"]
|
108
|
+
max = slots if slots > max
|
109
|
+
end
|
110
|
+
|
111
|
+
# loop through data constructing fusion table date
|
112
|
+
data = []
|
113
|
+
max_radius = 150.0 #in meters
|
114
|
+
buffer_chunk = max_radius / max
|
115
|
+
|
116
|
+
bikes.each do |b|
|
117
|
+
if b["lat"].to_f > 50 #ignore non geographic ones
|
118
|
+
docs = (b["nb_bikes"] + b["nb_empty_docks"])
|
119
|
+
geom = Polygon.from_points [buffer(b["long"].to_f, b["lat"].to_f, docs*buffer_chunk)]
|
120
|
+
#geom = Point.from_x_y b["long"].to_f, b["lat"].to_f
|
121
|
+
|
122
|
+
data << {
|
123
|
+
"name" => b["name"],
|
124
|
+
"created_at" => Time::parse(b["created_at"]),
|
125
|
+
"updated_at" => Time::parse(b["updated_at"]),
|
126
|
+
"boris_id" => b["id"],
|
127
|
+
"temporary" => (b["temporary"] ? 1 : 0),
|
128
|
+
"installed" => (b["installed"] ? 1 : 0),
|
129
|
+
"locked" => (b["locked"] ? 1 : 0),
|
130
|
+
"nb_empty_docs" => b["nb_empty_docks"],
|
131
|
+
"nb_bikes" => b["nb_bikes"],
|
132
|
+
"nb_docs" => docs,
|
133
|
+
"image" => "",
|
134
|
+
"geom" => geom.as_kml,
|
135
|
+
"geom_fill" => color(max,b["nb_bikes"]),
|
136
|
+
"geom_border" => color(max,b["nb_bikes"],0,"FF"),
|
137
|
+
}
|
138
|
+
puts "packing data for #{b["name"]}"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# get current number of rows ready to delete
|
143
|
+
row_ids = table.select "ROWID"
|
144
|
+
|
145
|
+
# put new data up
|
146
|
+
puts "sending bikes to fusion tables..."
|
147
|
+
table.insert data
|
148
|
+
|
149
|
+
# remove old data
|
150
|
+
puts "deleting old rows"
|
151
|
+
row_ids.each do |id|
|
152
|
+
table.delete id[:rowid]
|
153
|
+
end
|
154
|
+
|
155
|
+
# Be nice and wait
|
156
|
+
puts "...done! sleeping..."
|
157
|
+
sleep 500
|
158
|
+
end
|
159
|
+
|
data/examples/compare_tweets.rb
CHANGED
@@ -49,7 +49,7 @@ places = {
|
|
49
49
|
# Configure fusion tables
|
50
50
|
ft = GData::Client::FusionTables.new
|
51
51
|
ft.clientlogin(config["google_username"], config["google_password"])
|
52
|
-
table_name = "
|
52
|
+
table_name = "TwitterFusion"
|
53
53
|
cols = [
|
54
54
|
{:name => 'screen_name', :type => 'string'},
|
55
55
|
{:name => 'avatar', :type => 'string'},
|
data/fusion_tables.gemspec
CHANGED
@@ -5,26 +5,28 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{fusion_tables}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Simon Tokumine", "Tom Verbeure"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2011-06-03}
|
13
13
|
s.description = %q{A simple Google Fusion Tables API wrapper. Supports bulk inserts and most API functions}
|
14
14
|
s.email = %q{simon@tinypla.net}
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE",
|
17
|
-
"README.
|
17
|
+
"README.md",
|
18
18
|
"TODO"
|
19
19
|
]
|
20
20
|
s.files = [
|
21
21
|
".document",
|
22
22
|
".gitignore",
|
23
|
+
"CHANGELOG",
|
23
24
|
"LICENSE",
|
24
|
-
"README.
|
25
|
+
"README.md",
|
25
26
|
"Rakefile",
|
26
27
|
"TODO",
|
27
28
|
"VERSION",
|
29
|
+
"examples/boris_bikes.rb",
|
28
30
|
"examples/compare_tweets.rb",
|
29
31
|
"examples/credentials.example.yml",
|
30
32
|
"fusion_tables.gemspec",
|
@@ -33,12 +35,6 @@ Gem::Specification.new do |s|
|
|
33
35
|
"lib/fusion_tables/data/data.rb",
|
34
36
|
"lib/fusion_tables/data/table.rb",
|
35
37
|
"lib/fusion_tables/ext/fusion_tables.rb",
|
36
|
-
"pkg/fusion_tables-0.1.0.gem",
|
37
|
-
"pkg/fusion_tables-0.1.1.gem",
|
38
|
-
"pkg/fusion_tables-0.1.2.gem",
|
39
|
-
"pkg/fusion_tables-0.2.0.gem",
|
40
|
-
"pkg/fusion_tables-0.2.1.gem",
|
41
|
-
"pkg/fusion_tables-0.2.2.gem",
|
42
38
|
"test/README",
|
43
39
|
"test/helper.rb",
|
44
40
|
"test/test_client.rb",
|
@@ -49,18 +45,18 @@ Gem::Specification.new do |s|
|
|
49
45
|
s.homepage = %q{http://github.com/tokumine/fusion-tables}
|
50
46
|
s.rdoc_options = ["--charset=UTF-8"]
|
51
47
|
s.require_paths = ["lib"]
|
52
|
-
s.rubygems_version = %q{1.
|
48
|
+
s.rubygems_version = %q{1.4.1}
|
53
49
|
s.summary = %q{Google Fusion Tables API wrapper}
|
54
50
|
s.test_files = [
|
55
51
|
"test/helper.rb",
|
56
52
|
"test/test_client.rb",
|
57
53
|
"test/test_ext.rb",
|
58
54
|
"test/test_table.rb",
|
55
|
+
"examples/boris_bikes.rb",
|
59
56
|
"examples/compare_tweets.rb"
|
60
57
|
]
|
61
58
|
|
62
59
|
if s.respond_to? :specification_version then
|
63
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
64
60
|
s.specification_version = 3
|
65
61
|
|
66
62
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
@@ -52,8 +52,10 @@ module GData
|
|
52
52
|
|
53
53
|
# Returns a count of rows. SQL conditions optional
|
54
54
|
#
|
55
|
+
# Note: handles odd FT response: when table has 0 rows, returns empty array.
|
55
56
|
def count conditions=nil
|
56
|
-
select("count()", conditions)
|
57
|
+
result = select("count()", conditions)
|
58
|
+
result.empty? ? 0 : result.first[:"count()"].to_i
|
57
59
|
end
|
58
60
|
|
59
61
|
|
@@ -66,7 +68,8 @@ module GData
|
|
66
68
|
# Fields are escaped and formatted for FT based on type
|
67
69
|
#
|
68
70
|
def insert data
|
69
|
-
|
71
|
+
data = [data] unless data.respond_to?(:to_ary)
|
72
|
+
|
70
73
|
# encode values to insert
|
71
74
|
data = encode data
|
72
75
|
|
@@ -85,26 +88,24 @@ module GData
|
|
85
88
|
end
|
86
89
|
end
|
87
90
|
|
88
|
-
# Runs update on
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
# data = data.to_a.map{|x| x.join("=")}.join(", ")
|
96
|
-
#
|
97
|
-
# sql = "UPDATE #{@id} SET #{data} WHERE ROWID = #{row_id}"
|
98
|
-
# GData::Client::FusionTables::Data.parse(@client.sql_post(sql)).body
|
99
|
-
#end
|
91
|
+
# Runs update on row specified and return data obj
|
92
|
+
def update row_id, data
|
93
|
+
data = encode([data]).first
|
94
|
+
data = data.to_a.map{|x| x.join("=")}.join(", ")
|
95
|
+
sql = "UPDATE #{@id} SET #{data} WHERE ROWID = '#{row_id}'"
|
96
|
+
GData::Client::FusionTables::Data.parse(@client.sql_post(sql)).body
|
97
|
+
end
|
100
98
|
|
101
99
|
# delete row
|
102
|
-
# no bulk delete so may aswell drop table and start again
|
103
100
|
def delete row_id
|
104
101
|
sql = "DELETE FROM #{@id} WHERE rowid='#{row_id}'"
|
105
102
|
GData::Client::FusionTables::Data.parse(@client.sql_post(sql)).body
|
106
103
|
end
|
107
104
|
|
105
|
+
# delete all rows
|
106
|
+
def truncate!
|
107
|
+
GData::Client::FusionTables::Data.parse(@client.sql_post("DELETE FROM #{@id}")).body
|
108
|
+
end
|
108
109
|
|
109
110
|
def get_headers
|
110
111
|
@headers ||= describe
|
@@ -114,10 +115,15 @@ module GData
|
|
114
115
|
data.inject([]) do |ar,h|
|
115
116
|
ret = {}
|
116
117
|
h.each do |key, value|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
118
|
+
if value.nil?
|
119
|
+
#empty string for nils
|
120
|
+
ret["'#{key.to_s}'"] = "''"
|
121
|
+
else
|
122
|
+
ret["'#{key.to_s}'"] = case get_datatype(key)
|
123
|
+
when "number" then "#{value}"
|
124
|
+
when "datetime" then "'#{value.strftime("%m-%d-%Y %H:%M:%S")}'"
|
125
|
+
else "'#{value.gsub(/\\/, '\&\&').gsub(/'/, "''")}'"
|
126
|
+
end
|
121
127
|
end
|
122
128
|
end
|
123
129
|
ar << ret
|
@@ -134,9 +140,9 @@ module GData
|
|
134
140
|
@headers.each do |h|
|
135
141
|
return h[:type] if h[:name] == column_name.to_s
|
136
142
|
end
|
137
|
-
raise ArgumentError "The column doesn't exist"
|
143
|
+
raise ArgumentError, "The column doesn't exist"
|
138
144
|
end
|
139
145
|
end
|
140
146
|
end
|
141
147
|
end
|
142
|
-
end
|
148
|
+
end
|
data/test/test_client.rb
CHANGED
@@ -10,12 +10,12 @@ class TestClient < Test::Unit::TestCase
|
|
10
10
|
end
|
11
11
|
|
12
12
|
should "be properly setup" do
|
13
|
-
assert_equal @ft.clientlogin_service
|
14
|
-
assert_equal @ft.headers["Content-Type"]
|
13
|
+
assert_equal "fusiontables", @ft.clientlogin_service
|
14
|
+
assert_equal "application/x-www-form-urlencoded", @ft.headers["Content-Type"]
|
15
15
|
end
|
16
16
|
|
17
17
|
should "be able to authenticate with the google services" do
|
18
|
-
assert_equal @ft.auth_handler.service
|
18
|
+
assert_equal "fusiontables", @ft.auth_handler.service
|
19
19
|
assert @ft.auth_handler.token
|
20
20
|
end
|
21
21
|
end
|
data/test/test_ext.rb
CHANGED
@@ -18,40 +18,40 @@ class TestExt < Test::Unit::TestCase
|
|
18
18
|
|
19
19
|
should "let you create a table if you get everything right" do
|
20
20
|
table = @ft.create_table "test_table", [{:name => "test_col", :type => "string" }]
|
21
|
-
assert_equal
|
21
|
+
assert_equal GData::Client::FusionTables::Table, table.class
|
22
22
|
@ft.drop(table.id)
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
should "correct your table name to a certain degree on create" do
|
26
26
|
table = @ft.create_table "test table", [{:name => "test col", :type => "string" }]
|
27
|
-
assert_equal table.name
|
27
|
+
assert_equal "test_table", table.name
|
28
28
|
@ft.drop(table.id)
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
should "return you a list of your fusion tables" do
|
32
32
|
resp = @ft.show_tables
|
33
|
-
assert_equal
|
33
|
+
assert_equal GData::Client::FusionTables::Table, resp.first.class if resp.first
|
34
34
|
end
|
35
35
|
|
36
36
|
should "be possible to delete a table with an id" do
|
37
37
|
table = @ft.create_table "test_table", [{:name => "test col", :type => "string" }]
|
38
|
-
assert_equal @ft.drop(table.id)
|
38
|
+
assert_equal 1, @ft.drop(table.id)
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
should "be possible to delete tables with an array of ids" do
|
42
42
|
table1 = @ft.create_table "test_table", [{:name => "test col", :type => "string" }]
|
43
43
|
table2 = @ft.create_table "test_table", [{:name => "test col", :type => "string" }]
|
44
|
-
assert_equal @ft.drop([table1.id, table2.id])
|
44
|
+
assert_equal 2, @ft.drop([table1.id, table2.id])
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
should "be possible to delete multiple tables with a regex" do
|
48
48
|
table1 = @ft.create_table "test_table", [{:name => "test col", :type => "string" }]
|
49
49
|
table2 = @ft.create_table "test_table", [{:name => "test col", :type => "string" }]
|
50
|
-
assert_equal @ft.drop(/^test_/)
|
50
|
+
assert_equal 2, @ft.drop(/^test_/)
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
should "return zero if passed a silly id" do
|
54
|
-
assert_equal @ft.drop(235243875629384756)
|
54
|
+
assert_equal 0, @ft.drop(235243875629384756)
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
data/test/test_table.rb
CHANGED
@@ -18,12 +18,11 @@ class TestTable < Test::Unit::TestCase
|
|
18
18
|
:phone => 12,
|
19
19
|
:dob => Time.utc(2010,"aug",10,20,15,1),
|
20
20
|
:house => "POINT(1,1)"}]
|
21
|
-
|
22
21
|
row = data.first
|
23
|
-
assert_equal
|
24
|
-
assert_equal
|
25
|
-
assert_equal
|
26
|
-
assert_equal
|
22
|
+
assert_equal "'\\\\bob''s pizza'", row["'firstname'"]
|
23
|
+
assert_equal "#{12}", row["'phone'"]
|
24
|
+
assert_equal "'08-10-2010 20:15:01'", row["'dob'"]
|
25
|
+
assert_equal "'POINT(1,1)'", row["'house'"]
|
27
26
|
end
|
28
27
|
|
29
28
|
should "be able to insert 1 row of data" do
|
@@ -33,7 +32,7 @@ class TestTable < Test::Unit::TestCase
|
|
33
32
|
:dob => Time.utc(2010,"aug",10,20,15,1),
|
34
33
|
:house => '<Point><coordinates>-74.006393,40.714172,0</coordinates></Point>'}
|
35
34
|
}
|
36
|
-
|
35
|
+
|
37
36
|
@table.insert data
|
38
37
|
end
|
39
38
|
|
@@ -47,8 +46,8 @@ class TestTable < Test::Unit::TestCase
|
|
47
46
|
|
48
47
|
@table.insert data
|
49
48
|
end
|
50
|
-
|
51
|
-
|
49
|
+
|
50
|
+
|
52
51
|
should "be able to count the number of rows" do
|
53
52
|
data = 2.times.inject([]) { |a,i|
|
54
53
|
a << {:firstname => "Person-#{i}",
|
@@ -56,9 +55,9 @@ class TestTable < Test::Unit::TestCase
|
|
56
55
|
:dob => Time.utc(2010,"aug",10,20,15,1),
|
57
56
|
:house => "<Point><coordinates>#{180-rand(360)},#{90-rand(180)},0</coordinates></Point>"}
|
58
57
|
}
|
59
|
-
|
58
|
+
|
60
59
|
@table.insert data
|
61
|
-
assert_equal @table.count
|
60
|
+
assert_equal 2, @table.count
|
62
61
|
end
|
63
62
|
|
64
63
|
should "be able to select the rows" do
|
@@ -68,9 +67,25 @@ class TestTable < Test::Unit::TestCase
|
|
68
67
|
:dob => Time.utc(2010,"aug",10,20,15,1),
|
69
68
|
:house => "<Point><coordinates>1,1,0</coordinates></Point>"}
|
70
69
|
}
|
71
|
-
|
70
|
+
|
72
71
|
@table.insert data
|
73
|
-
assert_equal
|
72
|
+
assert_equal [{:firstname=>"Person-0", :phone=>"12", :dob=>"08-10-2010 20:15:01", :house=>"<Point><coordinates>1,1,0</coordinates></Point>"}, {:firstname=>"Person-1", :phone=>"12", :dob=>"08-10-2010 20:15:01", :house=>"<Point><coordinates>1,1,0</coordinates></Point>"}], @table.select
|
74
73
|
end
|
74
|
+
|
75
|
+
should "be able to truncate all rows and start again" do
|
76
|
+
data = 2.times.inject([]) { |a,i|
|
77
|
+
a << {:firstname => "Person-#{i}",
|
78
|
+
:phone => 12,
|
79
|
+
:dob => Time.utc(2010,"aug",10,20,15,1),
|
80
|
+
:house => "<Point><coordinates>#{180-rand(360)},#{90-rand(180)},0</coordinates></Point>"}
|
81
|
+
}
|
82
|
+
|
83
|
+
@table.insert data
|
84
|
+
assert_equal 2, @table.count
|
85
|
+
@table.truncate!
|
86
|
+
assert_equal 0, @table.count
|
87
|
+
@table.insert data
|
88
|
+
assert_equal 2, @table.count
|
89
|
+
end
|
75
90
|
end
|
76
91
|
end
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fusion_tables
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 17
|
5
|
+
prerelease:
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 2
|
8
|
-
-
|
9
|
-
version: 0.2.
|
9
|
+
- 3
|
10
|
+
version: 0.2.3
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Simon Tokumine
|
@@ -15,7 +16,7 @@ autorequire:
|
|
15
16
|
bindir: bin
|
16
17
|
cert_chain: []
|
17
18
|
|
18
|
-
date:
|
19
|
+
date: 2011-06-03 00:00:00 +01:00
|
19
20
|
default_executable:
|
20
21
|
dependencies:
|
21
22
|
- !ruby/object:Gem::Dependency
|
@@ -26,6 +27,7 @@ dependencies:
|
|
26
27
|
requirements:
|
27
28
|
- - ">="
|
28
29
|
- !ruby/object:Gem::Version
|
30
|
+
hash: 3
|
29
31
|
segments:
|
30
32
|
- 0
|
31
33
|
version: "0"
|
@@ -39,6 +41,7 @@ dependencies:
|
|
39
41
|
requirements:
|
40
42
|
- - ">="
|
41
43
|
- !ruby/object:Gem::Version
|
44
|
+
hash: 23
|
42
45
|
segments:
|
43
46
|
- 1
|
44
47
|
- 1
|
@@ -54,16 +57,18 @@ extensions: []
|
|
54
57
|
|
55
58
|
extra_rdoc_files:
|
56
59
|
- LICENSE
|
57
|
-
- README.
|
60
|
+
- README.md
|
58
61
|
- TODO
|
59
62
|
files:
|
60
63
|
- .document
|
61
64
|
- .gitignore
|
65
|
+
- CHANGELOG
|
62
66
|
- LICENSE
|
63
|
-
- README.
|
67
|
+
- README.md
|
64
68
|
- Rakefile
|
65
69
|
- TODO
|
66
70
|
- VERSION
|
71
|
+
- examples/boris_bikes.rb
|
67
72
|
- examples/compare_tweets.rb
|
68
73
|
- examples/credentials.example.yml
|
69
74
|
- fusion_tables.gemspec
|
@@ -72,12 +77,6 @@ files:
|
|
72
77
|
- lib/fusion_tables/data/data.rb
|
73
78
|
- lib/fusion_tables/data/table.rb
|
74
79
|
- lib/fusion_tables/ext/fusion_tables.rb
|
75
|
-
- pkg/fusion_tables-0.1.0.gem
|
76
|
-
- pkg/fusion_tables-0.1.1.gem
|
77
|
-
- pkg/fusion_tables-0.1.2.gem
|
78
|
-
- pkg/fusion_tables-0.2.0.gem
|
79
|
-
- pkg/fusion_tables-0.2.1.gem
|
80
|
-
- pkg/fusion_tables-0.2.2.gem
|
81
80
|
- test/README
|
82
81
|
- test/helper.rb
|
83
82
|
- test/test_client.rb
|
@@ -98,6 +97,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
98
97
|
requirements:
|
99
98
|
- - ">="
|
100
99
|
- !ruby/object:Gem::Version
|
100
|
+
hash: 3
|
101
101
|
segments:
|
102
102
|
- 0
|
103
103
|
version: "0"
|
@@ -106,13 +106,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
106
106
|
requirements:
|
107
107
|
- - ">="
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
+
hash: 3
|
109
110
|
segments:
|
110
111
|
- 0
|
111
112
|
version: "0"
|
112
113
|
requirements: []
|
113
114
|
|
114
115
|
rubyforge_project:
|
115
|
-
rubygems_version: 1.
|
116
|
+
rubygems_version: 1.4.1
|
116
117
|
signing_key:
|
117
118
|
specification_version: 3
|
118
119
|
summary: Google Fusion Tables API wrapper
|
@@ -121,4 +122,5 @@ test_files:
|
|
121
122
|
- test/test_client.rb
|
122
123
|
- test/test_ext.rb
|
123
124
|
- test/test_table.rb
|
125
|
+
- examples/boris_bikes.rb
|
124
126
|
- examples/compare_tweets.rb
|
data/README.textile
DELETED
@@ -1,144 +0,0 @@
|
|
1
|
-
h1. fusion-tables
|
2
|
-
|
3
|
-
This gem lets you easily interact with Google Fusion Tables from your Ruby application. Here are some "example maps and charts":http://www.tokumine.com/2010/08/10/fusion-tables-gem/.
|
4
|
-
|
5
|
-
h2. Gem Dependencies
|
6
|
-
|
7
|
-
* gdata_19 >= 1.1.2
|
8
|
-
|
9
|
-
h2. Installation
|
10
|
-
|
11
|
-
bc. gem install fusion_tables
|
12
|
-
|
13
|
-
h2. Rubies
|
14
|
-
|
15
|
-
Tested on:
|
16
|
-
|
17
|
-
* 1.8.7
|
18
|
-
* 1.9.2-p0
|
19
|
-
|
20
|
-
h2. To Use
|
21
|
-
|
22
|
-
bc. require 'fusion_tables'
|
23
|
-
|
24
|
-
or in Rails 2.3.x
|
25
|
-
|
26
|
-
bc. config.gem 'fusion_tables'
|
27
|
-
|
28
|
-
h2. API examples
|
29
|
-
|
30
|
-
Please explore the "worked twitter example":http://github.com/tokumine/fusion-tables/blob/master/examples/compare_tweets.rb and the "tests":http://github.com/tokumine/fusion-tables/tree/master/test/. Here is a brief rundown:
|
31
|
-
|
32
|
-
<pre><code># Connect to service
|
33
|
-
@ft = GData::Client::FusionTables.new
|
34
|
-
@ft.clientlogin(username, password)
|
35
|
-
|
36
|
-
# Browse existing tables
|
37
|
-
@ft.show_tables
|
38
|
-
# => [table_1, table_2]
|
39
|
-
|
40
|
-
# Getting table id suitable for using with google maps (see more below)
|
41
|
-
table_1.id #=> 42342 (the table's google id)
|
42
|
-
|
43
|
-
# Count data
|
44
|
-
table_1.count #=> 1
|
45
|
-
|
46
|
-
# Select data
|
47
|
-
table_1.select
|
48
|
-
#=> data
|
49
|
-
|
50
|
-
# Select data with conditions
|
51
|
-
table_1.select "name", "WHERE x=n"
|
52
|
-
#=> data
|
53
|
-
|
54
|
-
# Select ROWIDs
|
55
|
-
row_ids = table_1.select "ROWID"
|
56
|
-
|
57
|
-
# Drop tables
|
58
|
-
@ft.drop table_1.id # table id
|
59
|
-
@ft.drop [table_1.id, table_2.id] # arrays of table ids
|
60
|
-
@ft.drop /yacht/ # regex on table name
|
61
|
-
|
62
|
-
# Creating a table
|
63
|
-
cols = [{:name => "friend name", :type => 'string' },
|
64
|
-
{:name => "age", :type => 'number' },
|
65
|
-
{:name => "meeting time", :type => 'datetime' },
|
66
|
-
{:name => "where", :type => 'location' }]
|
67
|
-
|
68
|
-
new_table = @ft.create_table "My upcoming meetings", cols
|
69
|
-
|
70
|
-
# Inserting rows (auto chunks every 500)
|
71
|
-
data = [{"friend name" => "Eric Wimp",
|
72
|
-
"age" => 25,
|
73
|
-
"meeting time" => Time.utc(2010,"aug",10,20,15,1),
|
74
|
-
"where" => "29 Acacia Road, Nuttytown"}]
|
75
|
-
new_table.insert data
|
76
|
-
|
77
|
-
# Delete row
|
78
|
-
new_table.delete row_id
|
79
|
-
</code></pre>
|
80
|
-
|
81
|
-
h2. Fusion Tables secret Geospatial Sauce
|
82
|
-
|
83
|
-
*"Geolocated Tweets example":http://tables.googlelabs.com/DataSource?snapid=73106*
|
84
|
-
|
85
|
-
Fusion Tables is a labs product from Google. You can "read more here":http://tables.googlelabs.com/, but the key thing is that it gives you *access to the google tile mill for fast generation of google map layers across large datasets*
|
86
|
-
|
87
|
-
Fusion Tables supports the following geometry types:
|
88
|
-
|
89
|
-
* lat/long
|
90
|
-
* addresses (automatically geocodes them for you)
|
91
|
-
* KML (point, polyline, polygon, multipolygon)
|
92
|
-
|
93
|
-
h2. Integrate with google maps v3
|
94
|
-
|
95
|
-
Adding a fusion tables datalayer with many points/polygons to your v3 map is as simple as:
|
96
|
-
|
97
|
-
bc. layer = new google.maps.FusionTablesLayer(139529);
|
98
|
-
|
99
|
-
That's it
|
100
|
-
|
101
|
-
You can also refine the tiles by SQL, and can even do so dynamically:
|
102
|
-
|
103
|
-
<pre><code>
|
104
|
-
layer = new google.maps.FusionTablesLayer(198945, {
|
105
|
-
query: "SELECT address FROM 198945 WHERE ridership > 5000"}
|
106
|
-
);
|
107
|
-
</code></pre>
|
108
|
-
|
109
|
-
Finally, fusion tables also lets you make Heatmaps
|
110
|
-
|
111
|
-
<pre><code>
|
112
|
-
layer = new google.maps.FusionTablesLayer(136705, {
|
113
|
-
heatmap: true
|
114
|
-
});
|
115
|
-
</code></pre>
|
116
|
-
|
117
|
-
You can also export your data (filtered and geocoded) to KML. As an example, here are "all the Gasoline filling stations in the UK":http://tables.googlelabs.com/exporttable?query=select+col0%2Ccol1%2Ccol2%2Ccol3%2Ccol4%2Ccol5%2Ccol6%2Ccol12%2Ccol13%2Ccol14%2Ccol15%2Ccol16%2Ccol17%2Ccol18%2Ccol19%2Ccol20%2Ccol21+from+214045+&o=kmllink&g=col0
|
118
|
-
|
119
|
-
read "more here":http://code.google.com/apis/maps/documentation/javascript/overlays.html#FusionTables
|
120
|
-
|
121
|
-
h2. A few words of warning...
|
122
|
-
|
123
|
-
# The API is still very young and *will probably change*
|
124
|
-
# Currently you have to make a table public before you can display it on a map, unfortunately, this can only be done on the web interface. A suggested workaround is to put all your data in 1 big public table, and then query for the data you want to display based off a key/flag column
|
125
|
-
|
126
|
-
h2. Note on Patches/Pull Requests
|
127
|
-
|
128
|
-
* Fork the project.
|
129
|
-
* Make your feature addition or bug fix.
|
130
|
-
* Add tests for it. This is important so I don't break it in a
|
131
|
-
future version unintentionally.
|
132
|
-
* Commit, do not mess with rakefile, version, or history.
|
133
|
-
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
134
|
-
* Send me a pull request. Bonus points for topic branches.
|
135
|
-
|
136
|
-
h2. Copyright
|
137
|
-
|
138
|
-
Largely based on Tom Verbeure's work for MTBGuru: http://code.google.com/p/mtbguru-fusiontables/
|
139
|
-
|
140
|
-
Copyright (c) 2010 Tom Verbeure, Simon Tokumine. See LICENSE for details.
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
data/pkg/fusion_tables-0.1.0.gem
DELETED
Binary file
|
data/pkg/fusion_tables-0.1.1.gem
DELETED
Binary file
|
data/pkg/fusion_tables-0.1.2.gem
DELETED
Binary file
|
data/pkg/fusion_tables-0.2.0.gem
DELETED
Binary file
|
data/pkg/fusion_tables-0.2.1.gem
DELETED
Binary file
|
data/pkg/fusion_tables-0.2.2.gem
DELETED
Binary file
|