google-ft 0.0.2
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/Gemfile +2 -0
- data/README.md +4 -0
- data/Rakefile +1 -0
- data/google-ft.gemspec +24 -0
- data/lib/google-ft.rb +96 -0
- data/lib/google-ft/table.rb +173 -0
- data/lib/google-ft/table/column.rb +16 -0
- data/lib/google-ft/table/permission.rb +32 -0
- metadata +118 -0
data/Gemfile
ADDED
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/google-ft.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "google-ft"
|
6
|
+
s.version = "0.0.2"
|
7
|
+
s.authors = ["Jon Durbin"]
|
8
|
+
s.email = ["jond@greenviewdata.com"]
|
9
|
+
s.homepage = "https://github.com/gdi/google-ft"
|
10
|
+
s.summary = %q{Work with Google Fusion Tables using a service account}
|
11
|
+
s.description = %q{Work with Google Fusion Tables using a service account}
|
12
|
+
|
13
|
+
s.rubyforge_project = "google-ft"
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
|
20
|
+
s.add_dependency 'rspec'
|
21
|
+
s.add_dependency 'bundler'
|
22
|
+
s.add_dependency 'google-sa-auth'
|
23
|
+
s.add_dependency 'json'
|
24
|
+
end
|
data/lib/google-ft.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'curb-fu'
|
3
|
+
require 'google-sa-auth'
|
4
|
+
require 'google-ft/table'
|
5
|
+
require 'google-ft/table/column'
|
6
|
+
require 'google-ft/table/permission'
|
7
|
+
|
8
|
+
# Quick and dirty method to symbolize keys of a hash.
|
9
|
+
class Hash
|
10
|
+
def symbolize
|
11
|
+
self.inject({}){|item,(k,v)| item[k.to_sym] = v; item}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class GoogleFT
|
16
|
+
class << self
|
17
|
+
# Method to convert values into google-compatible format.
|
18
|
+
def to_google_ft_format(value)
|
19
|
+
if value.class == String
|
20
|
+
bytes = value.bytes.each.collect {|l| l.chr.gsub(/\\|'/) { |c| "\\#{c}" }.gsub('&', '%26').gsub("\b", '\\b').gsub("\f", '\\f').gsub("\n", '\\n').gsub("\r", '\\r').gsub("\t",'\\t')}
|
21
|
+
"'#{bytes.join}'"
|
22
|
+
elsif value.class == Array
|
23
|
+
"'#{value.first} #{value.last}'"
|
24
|
+
else
|
25
|
+
value.to_json
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Quick wrapper method for utilizing curb-fu.
|
30
|
+
def get_and_parse_response(args)
|
31
|
+
response = GoogleSAAuth::Client.run(args)
|
32
|
+
|
33
|
+
# Make sure we get a 20* status.
|
34
|
+
unless response.status.to_s =~ /^20/
|
35
|
+
puts response.body.to_s
|
36
|
+
raise RuntimeError
|
37
|
+
end
|
38
|
+
|
39
|
+
# Return the symbolized hash of the response body.
|
40
|
+
begin
|
41
|
+
JSON.parse(response.body).symbolize
|
42
|
+
rescue
|
43
|
+
response.body
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
attr_accessor :authorization, :token
|
49
|
+
|
50
|
+
def get_auth_token(args)
|
51
|
+
# Make sure the token wasn't already set and hasn't yet expired.
|
52
|
+
@authorization = nil unless has_auth?
|
53
|
+
|
54
|
+
# (Re)create the authorization.
|
55
|
+
@authorization ||= GoogleSAAuth.new(args)
|
56
|
+
|
57
|
+
# Save the token.
|
58
|
+
@token = @authorization.token
|
59
|
+
@authorization
|
60
|
+
end
|
61
|
+
|
62
|
+
def show_tables
|
63
|
+
require_auth
|
64
|
+
GoogleFT::Table.show_tables(@authorization.token_string)
|
65
|
+
end
|
66
|
+
|
67
|
+
def create_table(args)
|
68
|
+
require_auth
|
69
|
+
|
70
|
+
# Create the table and save it.
|
71
|
+
args[:token] = @authorization.token_string
|
72
|
+
table = GoogleFT::Table.new(args)
|
73
|
+
table.save
|
74
|
+
table
|
75
|
+
end
|
76
|
+
|
77
|
+
def delete_table(table_id)
|
78
|
+
require_auth
|
79
|
+
GoogleFT::Table.get_table_by_id(table_id, @authorization.token_string).delete
|
80
|
+
end
|
81
|
+
|
82
|
+
def get_table(table_id)
|
83
|
+
require_auth
|
84
|
+
GoogleFT::Table.get_table_by_id(table_id, @authorization.token_string)
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
def has_auth?
|
89
|
+
return false unless @token
|
90
|
+
@token.expired? ? false : true
|
91
|
+
end
|
92
|
+
|
93
|
+
def require_auth
|
94
|
+
raise RuntimeError unless has_auth?
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
class GoogleFT
|
2
|
+
class Table
|
3
|
+
# Base URI for the fusion tables API.
|
4
|
+
$FT_BASE_URI = 'https://www.googleapis.com/fusiontables/v1/tables'
|
5
|
+
|
6
|
+
class << self
|
7
|
+
# Show a list of tables, requires the authentication token.
|
8
|
+
def show_tables(token)
|
9
|
+
args = {
|
10
|
+
:uri => "#{$FT_BASE_URI}",
|
11
|
+
:method => 'get',
|
12
|
+
:headers => {
|
13
|
+
'Authorization' => "Bearer #{token}"
|
14
|
+
}
|
15
|
+
}
|
16
|
+
result = GoogleFT.get_and_parse_response(args)
|
17
|
+
return [] if result[:items].nil?
|
18
|
+
result[:items].each.collect do |table|
|
19
|
+
table = table.symbolize
|
20
|
+
GoogleFT::Table.new(
|
21
|
+
:token => token,
|
22
|
+
:id => table[:tableId],
|
23
|
+
:name => table[:name],
|
24
|
+
:columns => table[:columns],
|
25
|
+
:description => table[:description],
|
26
|
+
:exportable => table[:isExportable]
|
27
|
+
)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Get a table by it's ID and return a table object.
|
32
|
+
def get_table_by_id(table_id, token = nil)
|
33
|
+
args = {
|
34
|
+
:uri => "#{$FT_BASE_URI}/#{table_id}",
|
35
|
+
:method => 'get'
|
36
|
+
}
|
37
|
+
|
38
|
+
# Add the auth token if it was provided.
|
39
|
+
args[:headers] = {'Authorization' => "Bearer #{token}"} unless token.nil?
|
40
|
+
|
41
|
+
# Get and parse results.
|
42
|
+
result = GoogleFT.get_and_parse_response(args)
|
43
|
+
GoogleFT::Table.new(
|
44
|
+
:token => token,
|
45
|
+
:id => result[:tableId],
|
46
|
+
:name => result[:name],
|
47
|
+
:columns => result[:columns],
|
48
|
+
:description => result[:description],
|
49
|
+
:exportable => result[:isExportable]
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
# Accessors.
|
56
|
+
attr_accessor :columns, :id, :name, :description, :exportable, :token
|
57
|
+
attr_accessor :permissions
|
58
|
+
|
59
|
+
# Create a new table object.
|
60
|
+
def initialize(args = {})
|
61
|
+
# Clean-up args.
|
62
|
+
args = args.symbolize.delete_if {|k,v| ![:id, :name, :columns, :description, :exportable, :token].include?(k)}
|
63
|
+
|
64
|
+
# Create nicely formated columns.
|
65
|
+
self.columns = args[:columns].nil? ? [] : args[:columns].each.collect do |col|
|
66
|
+
name = col[:name] || col['name']
|
67
|
+
type = col[:type] || col['type']
|
68
|
+
GoogleFT::Table::Column.new(name, type)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Set other attributes.
|
72
|
+
self.token = args[:token]
|
73
|
+
self.id = args[:id]
|
74
|
+
self.name = args[:name].gsub(/[^a-zA-Z0-9_\-]/, '_')
|
75
|
+
self.description = args[:description] || ''
|
76
|
+
self.exportable = args[:exportable].nil? ? false : args[:exportable]
|
77
|
+
end
|
78
|
+
|
79
|
+
# Delete a table.
|
80
|
+
def delete
|
81
|
+
args = {
|
82
|
+
:uri => "#{$FT_BASE_URI}/#{self.id}",
|
83
|
+
:headers => {
|
84
|
+
'Authorization' => "Bearer #{self.token}",
|
85
|
+
},
|
86
|
+
:data => '',
|
87
|
+
:method => 'delete'
|
88
|
+
}
|
89
|
+
GoogleFT.get_and_parse_response(args)
|
90
|
+
true
|
91
|
+
end
|
92
|
+
|
93
|
+
# Save this table to Google.
|
94
|
+
# Used for creating or updating tables.
|
95
|
+
def save
|
96
|
+
# If ID exists, we are updating a table,
|
97
|
+
# otherwise, we are creating it.
|
98
|
+
method = self.id.nil? ? 'post' : 'put'
|
99
|
+
uri = 'https://www.googleapis.com/fusiontables/v1/tables'
|
100
|
+
uri += "/#{self.id}" unless self.id.nil?
|
101
|
+
args = {
|
102
|
+
:uri => uri,
|
103
|
+
:headers => {
|
104
|
+
'Content-Type' => 'application/json',
|
105
|
+
'Authorization' => "Bearer #{self.token}"
|
106
|
+
},
|
107
|
+
:data => post_args,
|
108
|
+
:method => method
|
109
|
+
}
|
110
|
+
result = GoogleFT.get_and_parse_response(args)
|
111
|
+
self.id = result[:tableId]
|
112
|
+
result
|
113
|
+
end
|
114
|
+
|
115
|
+
# Set permissions for a table.
|
116
|
+
def set_permissions(permission)
|
117
|
+
args = {
|
118
|
+
:uri => "https://www.googleapis.com/drive/v2/files/#{self.id}/permissions",
|
119
|
+
:headers => {
|
120
|
+
'Content-Type' => 'application/json',
|
121
|
+
'Authorization' => "Bearer #{self.token}"
|
122
|
+
},
|
123
|
+
:method => 'post',
|
124
|
+
:data => permission.post_args
|
125
|
+
}
|
126
|
+
GoogleFT.get_and_parse_response(args)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Return the JSON string of our table arguments.
|
130
|
+
# Used for creating and updating tables.
|
131
|
+
def post_args
|
132
|
+
{
|
133
|
+
:name => self.name,
|
134
|
+
:columns => self.columns.each.collect {|col| {:name => col.name, :type => col.type}},
|
135
|
+
:isExportable => self.exportable,
|
136
|
+
:description => self.description
|
137
|
+
}.to_json
|
138
|
+
end
|
139
|
+
|
140
|
+
# Insert rows into a table.
|
141
|
+
def insert(rows)
|
142
|
+
# Get the SQL-ish statement from arg hash.
|
143
|
+
inserts = []
|
144
|
+
|
145
|
+
# Go through each row.
|
146
|
+
rows.each do |row|
|
147
|
+
|
148
|
+
# Get all of the column/value pairs.
|
149
|
+
columns = []
|
150
|
+
values = []
|
151
|
+
row.each do |column,value|
|
152
|
+
columns.push(column)
|
153
|
+
values.push(value)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Add this insert line.
|
157
|
+
inserts.push("INSERT INTO #{self.id} (#{columns.join(',')}) VALUES (#{values.each.collect {|v| GoogleFT.to_google_ft_format(v)}.join(',')});")
|
158
|
+
end
|
159
|
+
|
160
|
+
# Post the insert's to Google.
|
161
|
+
args = {
|
162
|
+
:uri => 'https://www.googleapis.com/fusiontables/v1/query',
|
163
|
+
:headers => {
|
164
|
+
'Authorization' => "Bearer #{self.token}"
|
165
|
+
},
|
166
|
+
:method => 'post',
|
167
|
+
:data => "sql=#{inserts.join("\n")}"
|
168
|
+
}
|
169
|
+
puts "SQL:\n#{inserts.join("\n")}"
|
170
|
+
GoogleFT.get_and_parse_response(args)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class GoogleFT
|
2
|
+
class Table
|
3
|
+
class Column
|
4
|
+
attr_accessor :name, :type
|
5
|
+
|
6
|
+
def initialize(name, type = 'string')
|
7
|
+
# Cleanup the column name.
|
8
|
+
self.name = name.gsub(/[^a-zA-Z0-9_\-]/, '_')
|
9
|
+
|
10
|
+
# Store type and make sure it's valid.
|
11
|
+
self.type = type.upcase
|
12
|
+
raise ArgumentError unless ['STRING','NUMBER','DATETIME','LOCATION'].include?(self.type)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class GoogleFT
|
2
|
+
class Table
|
3
|
+
class Permission
|
4
|
+
attr_accessor :role, :type, :value, :require_link
|
5
|
+
def initialize(args)
|
6
|
+
# Clean up args and make sure we were at least supplied the required ones.
|
7
|
+
args = args.symbolize.delete_if {|k,v| ![:role, :type, :value, :require_link].include?(k)}
|
8
|
+
raise ArgumentError unless args[:role] && args[:type]
|
9
|
+
|
10
|
+
# Set defaults.
|
11
|
+
args[:value] ||= 'me'
|
12
|
+
args[:require_link] ||= false
|
13
|
+
|
14
|
+
# Set the attributes.
|
15
|
+
self.role = args[:role]
|
16
|
+
self.type = args[:type]
|
17
|
+
self.value = args[:value]
|
18
|
+
self.require_link = args[:require_link]
|
19
|
+
end
|
20
|
+
|
21
|
+
def post_args
|
22
|
+
# JSON formatted string for this permission.
|
23
|
+
{
|
24
|
+
:role => self.role,
|
25
|
+
:type => self.type,
|
26
|
+
:value => self.value,
|
27
|
+
:withLink => self.require_link
|
28
|
+
}.to_json
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: google-ft
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jon Durbin
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-07 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: bundler
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: google-sa-auth
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: json
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description: Work with Google Fusion Tables using a service account
|
79
|
+
email:
|
80
|
+
- jond@greenviewdata.com
|
81
|
+
executables: []
|
82
|
+
extensions: []
|
83
|
+
extra_rdoc_files: []
|
84
|
+
files:
|
85
|
+
- Gemfile
|
86
|
+
- README.md
|
87
|
+
- Rakefile
|
88
|
+
- google-ft.gemspec
|
89
|
+
- lib/google-ft.rb
|
90
|
+
- lib/google-ft/table.rb
|
91
|
+
- lib/google-ft/table/column.rb
|
92
|
+
- lib/google-ft/table/permission.rb
|
93
|
+
homepage: https://github.com/gdi/google-ft
|
94
|
+
licenses: []
|
95
|
+
post_install_message:
|
96
|
+
rdoc_options: []
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ! '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
requirements: []
|
112
|
+
rubyforge_project: google-ft
|
113
|
+
rubygems_version: 1.8.24
|
114
|
+
signing_key:
|
115
|
+
specification_version: 3
|
116
|
+
summary: Work with Google Fusion Tables using a service account
|
117
|
+
test_files: []
|
118
|
+
has_rdoc:
|