ft 0.0.1 → 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/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ task :default => :test
2
+
3
+ desc "Run all tests"
4
+ task :test do
5
+ require "cutest"
6
+
7
+ files = Dir["./test/*.rb"]
8
+
9
+ if !files.include?("./test/private.rb")
10
+ $stderr.puts("Couldn't find a test/private.rb file, so skipping tests that require authentication.\nIf you want to run them, take a look at test/private.example.rb")
11
+ files.delete("./test/authenticated.rb")
12
+ end
13
+
14
+ Cutest.run(files)
15
+ end
data/ft.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "ft"
3
- s.version = "0.0.1"
3
+ s.version = "0.0.2"
4
4
  s.summary = "Low-level interface to Google's Fusion Tables + CLI tool"
5
5
  s.authors = ["Damian Janowski"]
6
6
  s.email = ["djanowski@dimaion.com"]
@@ -14,6 +14,7 @@ Gem::Specification.new do |s|
14
14
 
15
15
  s.files = Dir[
16
16
  "*.gemspec",
17
+ "CHANGELOG.*",
17
18
  "LICENSE",
18
19
  "README*",
19
20
  "Rakefile",
data/lib/ft.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "csv"
2
2
  require "net/http/persistent"
3
+ require "net/https"
3
4
 
4
5
  class FusionTables
5
6
  Error = Class.new(RuntimeError)
@@ -13,15 +14,16 @@ class FusionTables
13
14
  end
14
15
  end
15
16
 
17
+ # Queries the Fusion Tables API with the given SQL and returns an
18
+ # array of arrays for rows and columns.
16
19
  def query(sql)
17
- url = URL.dup
18
-
19
- url.query = "sql=#{URI.escape(sql)}"
20
- res = http.request(url)
20
+ res = process_sql(sql)
21
21
 
22
22
  case res
23
23
  when Net::HTTPOK
24
24
  CSV.parse(res.body.force_encoding(Encoding::UTF_8))
25
+ when Net::HTTPFound
26
+ raise Error.new("Authentication required. See #{self.class}#authenticate")
25
27
  when Net::HTTPBadRequest
26
28
  message = CGI.unescapeHTML(res.body[%r[<title>(.*)</title>]i, 1])
27
29
  raise Error.new("#{message}. SQL was: #{sql}")
@@ -29,5 +31,71 @@ class FusionTables
29
31
  raise "Got #{res.class}: #{res.body}"
30
32
  end
31
33
  end
34
+
35
+ # Authenticates against Google using your email and password.
36
+ #
37
+ # Note that this method uses the ClientLogin mechanism and it
38
+ # only stores the resulting token as an instance variable. Your
39
+ # credentials are discarded after the authentication process.
40
+ def authenticate(email, password)
41
+ uri = URI.parse("https://www.google.com/accounts/ClientLogin")
42
+
43
+ http = Net::HTTP.new(uri.host, uri.port)
44
+ http.use_ssl = true
45
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
46
+
47
+ request = Net::HTTP::Post.new(uri.request_uri)
48
+
49
+ request.set_form_data({
50
+ "accountType" => "GOOGLE",
51
+ "Email" => email,
52
+ "Passwd" => password,
53
+ "service" => "fusiontables"
54
+ })
55
+
56
+ response = http.request(request)
57
+
58
+ case response
59
+ when Net::HTTPOK
60
+ @token = response.body[/^Auth=(.*)$/, 1]
61
+ return true
62
+ else
63
+ @token = nil
64
+ return false
65
+ end
66
+ end
67
+
68
+ # Prevents any authorization tokens from being exposed in error logs
69
+ # and the like.
70
+ def inspect
71
+ "#<#{self.class}>"
72
+ end
73
+
74
+ # Safely quotes a value.
75
+ def self.quote(value)
76
+ "'#{value.to_s.gsub("'", "\\\\'")}'"
77
+ end
78
+
79
+ protected
80
+
81
+ # Takes SQL and queries the Fusion Tables API.
82
+ def process_sql(sql)
83
+ url = URL.dup
84
+
85
+ if @token
86
+ http.headers["Authorization"] = "GoogleLogin auth=#{@token}"
87
+ end
88
+
89
+ if sql =~ /^select/i
90
+ url.query = "sql=#{URI.escape(sql)}"
91
+ res = http.request(url)
92
+ else
93
+ req = Net::HTTP::Post.new(url.path)
94
+ req.set_form_data(sql: sql)
95
+ res = http.request(url, req)
96
+ end
97
+
98
+ res
99
+ end
32
100
  end
33
101
  end
@@ -0,0 +1,48 @@
1
+ require "cutest"
2
+ require "./lib/ft"
3
+ require "./test/private"
4
+
5
+ setup do
6
+ [FusionTables::Connection.new, ENV["EMAIL"], ENV["PASSWORD"], ENV["PRIVATE_TABLE_ID"]]
7
+ end
8
+
9
+ test "authenticated SELECTs" do |conn, email, password, table_id|
10
+ conn.authenticate(email, password)
11
+
12
+ result = conn.query("SELECT Client, Invoice FROM #{table_id}")
13
+
14
+ assert_equal result, [
15
+ ["Client", "Invoice"],
16
+ ["Madalyn Streich", "1"],
17
+ ["Mr. Vincenza Bailey", "2"]
18
+ ]
19
+
20
+ assert conn.inspect !~ /token/
21
+ end
22
+
23
+ test "INSERT" do |conn, email, password, table_id|
24
+ conn.authenticate(email, password)
25
+
26
+ begin
27
+ result = conn.query("INSERT INTO #{table_id} (Client) VALUES ('Foo')")
28
+
29
+ assert_equal result[0][0], "rowid"
30
+ assert result[1][0] =~ /^\d+$/
31
+ ensure
32
+ conn.query("DELETE FROM #{table_id} WHERE ROWID = '#{result[1][0]}'") if result
33
+ end
34
+ end
35
+
36
+ test "DELETE" do |conn, email, password, table_id|
37
+ conn.authenticate(email, password)
38
+
39
+ result = conn.query("INSERT INTO #{table_id} (Client) VALUES ('Foo')")
40
+
41
+ rowid = result[1][0]
42
+
43
+ conn.query("DELETE FROM #{table_id} WHERE ROWID = '#{rowid}'")
44
+
45
+ result = conn.query("SELECT ROWID FROM #{table_id} WHERE ROWID = '#{rowid}'")
46
+
47
+ assert_equal result[1], nil
48
+ end
data/test/ft.rb CHANGED
@@ -16,3 +16,13 @@ test "raises errors" do |conn|
16
16
  conn.query("SELECT foo FROM 1310767")
17
17
  end
18
18
  end
19
+
20
+ test "raises on authentication errors" do |conn|
21
+ assert_raise FusionTables::Error do
22
+ conn.query("INSERT INTO 1310767 (Name) VALUES ('Foo')")
23
+ end
24
+ end
25
+
26
+ test "quoting" do |conn|
27
+ assert_equal FusionTables::Connection.quote("C'mon"), %q{'C\'mon'}
28
+ end
@@ -0,0 +1,8 @@
1
+ # This example works with OS X's keychain, but you can set the variables
2
+ # as you please.
3
+ #
4
+
5
+ # ENV["EMAIL"] = "<your google account email>" # If not already in your shell.
6
+ ENV["PASSWORD"] = `security 2>&1 find-internet-password -g -s www.google.com -a #{ENV["EMAIL"]}`[/^password: "(.*)"/, 1]
7
+
8
+ ENV["PRIVATE_TABLE_ID"] = "<your private table id>"
data/test/private.rb ADDED
@@ -0,0 +1,3 @@
1
+ ENV["EMAIL"] = "damian.janowski@gmail.com"
2
+ ENV["PASSWORD"] = `security 2>&1 find-internet-password -g -s www.google.com -a #{ENV["EMAIL"]}`[/^password: "(.*)"/, 1]
3
+ ENV["PRIVATE_TABLE_ID"] = "1340856"
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: ft
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.1
5
+ version: 0.0.2
6
6
  platform: ruby
7
7
  authors:
8
8
  - Damian Janowski
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-08-18 00:00:00 -03:00
13
+ date: 2011-08-26 00:00:00 -03:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -57,10 +57,14 @@ extra_rdoc_files: []
57
57
 
58
58
  files:
59
59
  - ft.gemspec
60
+ - Rakefile
60
61
  - bin/ft
61
62
  - lib/ft.rb
63
+ - test/authenticated.rb
62
64
  - test/cli.rb
63
65
  - test/ft.rb
66
+ - test/private.example.rb
67
+ - test/private.rb
64
68
  has_rdoc: true
65
69
  homepage: http://github.com/djanowski/ft
66
70
  licenses: []