google_drive 0.3.0
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/README.rdoc +89 -0
- data/doc_src/google_drive/acl.rb +20 -0
- data/doc_src/google_drive/acl_entry.rb +33 -0
- data/lib/google_drive.rb +120 -0
- data/lib/google_drive/acl.rb +124 -0
- data/lib/google_drive/acl_entry.rb +58 -0
- data/lib/google_drive/authentication_error.rb +14 -0
- data/lib/google_drive/client_login_fetcher.rb +56 -0
- data/lib/google_drive/collection.rb +54 -0
- data/lib/google_drive/error.rb +12 -0
- data/lib/google_drive/file.rb +217 -0
- data/lib/google_drive/list.rb +115 -0
- data/lib/google_drive/list_row.rb +84 -0
- data/lib/google_drive/oauth1_fetcher.rb +26 -0
- data/lib/google_drive/oauth2_fetcher.rb +47 -0
- data/lib/google_drive/record.rb +31 -0
- data/lib/google_drive/session.rb +436 -0
- data/lib/google_drive/spreadsheet.rb +220 -0
- data/lib/google_drive/table.rb +60 -0
- data/lib/google_drive/util.rb +55 -0
- data/lib/google_drive/worksheet.rb +445 -0
- metadata +121 -0
data/README.rdoc
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
This is a Ruby 1.8/1.9 library to read/write files/spreadsheets in Google Drive/Docs.
|
2
|
+
|
3
|
+
|
4
|
+
= How to install
|
5
|
+
|
6
|
+
$ sudo gem install google_drive
|
7
|
+
|
8
|
+
|
9
|
+
= How to use
|
10
|
+
|
11
|
+
Example to read/write files in Google Drive:
|
12
|
+
|
13
|
+
require "rubygems"
|
14
|
+
require "google_drive"
|
15
|
+
|
16
|
+
# Logs in.
|
17
|
+
# You can also use OAuth. See document of
|
18
|
+
# GoogleDrive.login_with_oauth for details.
|
19
|
+
session = GoogleDrive.login("username@gmail.com", "mypassword")
|
20
|
+
|
21
|
+
# Gets list of remote files.
|
22
|
+
for file in session.files
|
23
|
+
p file.title
|
24
|
+
end
|
25
|
+
|
26
|
+
# Uploads a local file.
|
27
|
+
session.upload_from_file("/path/to/hello.txt", "hello.txt", :convert => false)
|
28
|
+
|
29
|
+
# Downloads to a local file.
|
30
|
+
file = session.file_by_title("hello.txt")
|
31
|
+
file.download_to_file("/path/to/hello.txt")
|
32
|
+
|
33
|
+
# Updates content of the remote file.
|
34
|
+
file.update_from_file("/path/to/hello.txt")
|
35
|
+
|
36
|
+
Example to read/write spreadsheets:
|
37
|
+
|
38
|
+
require "rubygems"
|
39
|
+
require "google_drive"
|
40
|
+
|
41
|
+
# Logs in.
|
42
|
+
# You can also use OAuth. See document of
|
43
|
+
# GoogleDrive.login_with_oauth for details.
|
44
|
+
session = GoogleDrive.login("username@gmail.com", "mypassword")
|
45
|
+
|
46
|
+
# First worksheet of
|
47
|
+
# https://docs.google.com/spreadsheet/ccc?key=pz7XtlQC-PYx-jrVMJErTcg
|
48
|
+
ws = session.spreadsheet_by_key("pz7XtlQC-PYx-jrVMJErTcg").worksheets[0]
|
49
|
+
|
50
|
+
# Gets content of A2 cell.
|
51
|
+
p ws[2, 1] #==> "hoge"
|
52
|
+
|
53
|
+
# Changes content of cells.
|
54
|
+
# Changes are not sent to the server until you call ws.save().
|
55
|
+
ws[2, 1] = "foo"
|
56
|
+
ws[2, 2] = "bar"
|
57
|
+
ws.save()
|
58
|
+
|
59
|
+
# Dumps all cells.
|
60
|
+
for row in 1..ws.num_rows
|
61
|
+
for col in 1..ws.num_cols
|
62
|
+
p ws[row, col]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Yet another way to do so.
|
67
|
+
p ws.rows #==> [["fuga", ""], ["foo", "bar]]
|
68
|
+
|
69
|
+
# Reloads the worksheet to get changes by other clients.
|
70
|
+
ws.reload()
|
71
|
+
|
72
|
+
API document: http://gimite.net/doc/google-drive-ruby/
|
73
|
+
|
74
|
+
|
75
|
+
= Source code
|
76
|
+
|
77
|
+
http://github.com/gimite/google-drive-ruby
|
78
|
+
|
79
|
+
The license of this source is "New BSD Licence"
|
80
|
+
|
81
|
+
|
82
|
+
= Supported environments
|
83
|
+
|
84
|
+
Ruby 1.8.x and Ruby 1.9.x. Checked with Ruby 1.8.7 and Ruby 1.9.3.
|
85
|
+
|
86
|
+
|
87
|
+
= Author
|
88
|
+
|
89
|
+
Hiroshi Ichikawa - http://gimite.net/en/index.php?Contact
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module GoogleDrive
|
2
|
+
|
3
|
+
class Acl
|
4
|
+
|
5
|
+
# Returns the number of entries.
|
6
|
+
def size
|
7
|
+
end
|
8
|
+
|
9
|
+
# Returns GoogleDrive::AclEntry object at +index+.
|
10
|
+
def [](index)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Iterates over GoogleDrive::AclEntry objects.
|
14
|
+
def each(&block)
|
15
|
+
yield(entry)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module GoogleDrive
|
2
|
+
|
3
|
+
class AclEntry
|
4
|
+
|
5
|
+
# Type of the scope. One of:
|
6
|
+
#
|
7
|
+
# - "user": scope is a user's email address.
|
8
|
+
# - "group": scope is a Google Group email address.
|
9
|
+
# - "domain": scope is a Google Apps domain.
|
10
|
+
# - "default": Publicly shared with all users. scope is +nil+.
|
11
|
+
attr_reader(:scope_type)
|
12
|
+
|
13
|
+
# The scope. See scope_type.
|
14
|
+
attr_reader(:scope)
|
15
|
+
|
16
|
+
# The role given to the scope. One of:
|
17
|
+
# - "owner": The owner.
|
18
|
+
# - "writer": With read/write access.
|
19
|
+
# - "reader": With read-only access.
|
20
|
+
attr_reader(:role)
|
21
|
+
|
22
|
+
# Title of the entry.
|
23
|
+
attr_reader(:title)
|
24
|
+
|
25
|
+
# Edit URL of the entry.
|
26
|
+
attr_reader(:edit_url)
|
27
|
+
|
28
|
+
# E-tag of the entry.
|
29
|
+
attr_reader(:etag)
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/lib/google_drive.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
# Author: Hiroshi Ichikawa <http://gimite.net/>
|
2
|
+
# The license of this source is "New BSD Licence"
|
3
|
+
|
4
|
+
require "google_drive/session"
|
5
|
+
|
6
|
+
|
7
|
+
module GoogleDrive
|
8
|
+
|
9
|
+
# Authenticates with given +mail+ and +password+, and returns GoogleDrive::Session
|
10
|
+
# if succeeds. Raises GoogleDrive::AuthenticationError if fails.
|
11
|
+
# Google Apps account is supported.
|
12
|
+
#
|
13
|
+
# +proxy+ can be nil or return value of Net::HTTP.Proxy. If +proxy+ is specified, all
|
14
|
+
# HTTP access in the session uses the proxy. If +proxy+ is nil, it uses the proxy
|
15
|
+
# specified by http_proxy environment variable if available. Otherwise it performs direct
|
16
|
+
# access.
|
17
|
+
def self.login(mail, password, proxy = nil)
|
18
|
+
return Session.login(mail, password, proxy)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Authenticates with given OAuth1 or OAuth2 token.
|
22
|
+
#
|
23
|
+
# OAuth2 code example:
|
24
|
+
#
|
25
|
+
# client = OAuth2::Client.new(
|
26
|
+
# your_client_id, your_client_secret,
|
27
|
+
# :site => "https://accounts.google.com",
|
28
|
+
# :token_url => "/o/oauth2/token",
|
29
|
+
# :authorize_url => "/o/oauth2/auth")
|
30
|
+
# auth_url = client.auth_code.authorize_url(
|
31
|
+
# :redirect_uri => "http://example.com/",
|
32
|
+
# "scope" => "https://spreadsheets.google.com/feeds https://docs.google.com/feeds/")
|
33
|
+
# # Redirect the user to auth_url and get authorization code from redirect URL.
|
34
|
+
# auth_token = client.auth_code.get_token(
|
35
|
+
# authorization_code, :redirect_uri => "http://example.com/")
|
36
|
+
# session = GoogleDrive.login_with_oauth(auth_token)
|
37
|
+
#
|
38
|
+
# Or, from existing refresh token:
|
39
|
+
#
|
40
|
+
# access_token = OAuth2::AccessToken.from_hash(client,
|
41
|
+
# {:refresh_token => refresh_token, :expires_at => expires_at})
|
42
|
+
# access_token = access_token.refresh!
|
43
|
+
# session = GoogleDrive.login_with_oauth(access_token)
|
44
|
+
#
|
45
|
+
# OAuth1 code example:
|
46
|
+
#
|
47
|
+
# 1) First generate OAuth consumer object with key and secret for your site by registering site
|
48
|
+
# with Google.
|
49
|
+
# @consumer = OAuth::Consumer.new( "key","secret", {:site=>"https://agree2"})
|
50
|
+
# 2) Request token with OAuth.
|
51
|
+
# @request_token = @consumer.get_request_token
|
52
|
+
# session[:request_token] = @request_token
|
53
|
+
# redirect_to @request_token.authorize_url
|
54
|
+
# 3) Create an oauth access token.
|
55
|
+
# @oauth_access_token = @request_token.get_access_token
|
56
|
+
# @access_token = OAuth::AccessToken.new(
|
57
|
+
# @consumer, @oauth_access_token.token, @oauth_access_token.secret)
|
58
|
+
#
|
59
|
+
# See these documents for details:
|
60
|
+
#
|
61
|
+
# - https://github.com/intridea/oauth2
|
62
|
+
# - http://code.google.com/apis/accounts/docs/OAuth2.html
|
63
|
+
# - http://oauth.rubyforge.org/
|
64
|
+
# - http://code.google.com/apis/accounts/docs/OAuth.html
|
65
|
+
def self.login_with_oauth(oauth_token)
|
66
|
+
return Session.login_with_oauth(oauth_token)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Restores session using return value of auth_tokens method of previous session.
|
70
|
+
#
|
71
|
+
# See GoogleDrive.login for description of parameter +proxy+.
|
72
|
+
def self.restore_session(auth_tokens, proxy = nil)
|
73
|
+
return Session.restore_session(auth_tokens, proxy)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Restores GoogleDrive::Session from +path+ and returns it.
|
77
|
+
# If +path+ doesn't exist or authentication has failed, prompts mail and password on console,
|
78
|
+
# authenticates with them, stores the session to +path+ and returns it.
|
79
|
+
#
|
80
|
+
# See login for description of parameter +proxy+.
|
81
|
+
#
|
82
|
+
# This method requires Highline library: http://rubyforge.org/projects/highline/
|
83
|
+
def self.saved_session(path = ENV["HOME"] + "/.ruby_google_drive.token", proxy = nil)
|
84
|
+
tokens = {}
|
85
|
+
if ::File.exist?(path)
|
86
|
+
open(path) do |f|
|
87
|
+
for auth in [:wise, :writely]
|
88
|
+
line = f.gets()
|
89
|
+
tokens[auth] = line && line.chomp()
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
session = Session.new(tokens, nil, proxy)
|
94
|
+
session.on_auth_fail = proc() do
|
95
|
+
begin
|
96
|
+
require "highline"
|
97
|
+
rescue LoadError
|
98
|
+
raise(LoadError,
|
99
|
+
"GoogleDrive.saved_session requires Highline library.\n" +
|
100
|
+
"Run\n" +
|
101
|
+
" \$ sudo gem install highline\n" +
|
102
|
+
"to install it.")
|
103
|
+
end
|
104
|
+
highline = HighLine.new()
|
105
|
+
mail = highline.ask("Mail: ")
|
106
|
+
password = highline.ask("Password: "){ |q| q.echo = false }
|
107
|
+
session.login(mail, password)
|
108
|
+
open(path, "w", 0600) do |f|
|
109
|
+
f.puts(session.auth_token(:wise))
|
110
|
+
f.puts(session.auth_token(:writely))
|
111
|
+
end
|
112
|
+
true
|
113
|
+
end
|
114
|
+
if !session.auth_token
|
115
|
+
session.on_auth_fail.call()
|
116
|
+
end
|
117
|
+
return session
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# Author: Guy Boertje <https://github.com/guyboertje>
|
2
|
+
# Author: David R. Albrecht <https://github.com/eldavido>
|
3
|
+
# Author: Hiroshi Ichikawa <http://gimite.net/>
|
4
|
+
# The license of this source is "New BSD Licence"
|
5
|
+
|
6
|
+
require "google_drive/acl_entry"
|
7
|
+
|
8
|
+
|
9
|
+
module GoogleDrive
|
10
|
+
|
11
|
+
# ACL (access control list) of a spreadsheet.
|
12
|
+
#
|
13
|
+
# Use GoogleDrive::Spreadsheet#acl to get GoogleDrive::Acl object.
|
14
|
+
# See GoogleDrive::Spreadsheet#acl for usage example.
|
15
|
+
#
|
16
|
+
# This code is based on https://github.com/guyboertje/gdata-spreadsheet-ruby .
|
17
|
+
class Acl
|
18
|
+
|
19
|
+
include(Util)
|
20
|
+
extend(Forwardable)
|
21
|
+
|
22
|
+
def initialize(session, acls_feed_url) #:nodoc:
|
23
|
+
@session = session
|
24
|
+
@acls_feed_url = acls_feed_url
|
25
|
+
header = {"GData-Version" => "3.0"}
|
26
|
+
doc = @session.request(:get, @acls_feed_url, :header => header, :auth => :writely)
|
27
|
+
@acls = doc.css("entry").map(){ |e| AclEntry.new(entry_to_params(e)) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def_delegators(:@acls, :size, :[], :each)
|
31
|
+
|
32
|
+
# Adds a new entry. +entry+ is either a GoogleDrive::AclEntry or a Hash with keys
|
33
|
+
# :scope_type, :scope and :role. See GoogleDrive::AclEntry#scope_type and
|
34
|
+
# GoogleDrive::AclEntry#role for the document of the fields.
|
35
|
+
#
|
36
|
+
# NOTE: This sends email to the new people.
|
37
|
+
#
|
38
|
+
# e.g.
|
39
|
+
# spreadsheet.acl.push(
|
40
|
+
# {:scope_type => "user", :scope => "example2@gmail.com", :role => "reader"})
|
41
|
+
# spreadsheet.acl.push(
|
42
|
+
# {:scope_type => "user", :scope => "example3@gmail.com", :role => "writer"})
|
43
|
+
def push(entry)
|
44
|
+
|
45
|
+
entry = AclEntry.new(entry) if entry.is_a?(Hash)
|
46
|
+
|
47
|
+
header = {"GData-Version" => "3.0", "Content-Type" => "application/atom+xml"}
|
48
|
+
value_attr = entry.scope ? "value='#{h(entry.scope)}'" : ""
|
49
|
+
xml = <<-EOS
|
50
|
+
<entry
|
51
|
+
xmlns='http://www.w3.org/2005/Atom'
|
52
|
+
xmlns:gAcl='http://schemas.google.com/acl/2007'>
|
53
|
+
<category scheme='http://schemas.google.com/g/2005#kind'
|
54
|
+
term='http://schemas.google.com/acl/2007#accessRule'/>
|
55
|
+
<gAcl:role value='#{h(entry.role)}'/>
|
56
|
+
<gAcl:scope type='#{h(entry.scope_type)}' #{value_attr}/>
|
57
|
+
</entry>
|
58
|
+
EOS
|
59
|
+
doc = @session.request(
|
60
|
+
:post, @acls_feed_url, :data => xml, :header => header, :auth => :writely)
|
61
|
+
|
62
|
+
entry.params = entry_to_params(doc.root)
|
63
|
+
@acls.push(entry)
|
64
|
+
return entry
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
# Deletes an ACL entry.
|
69
|
+
#
|
70
|
+
# e.g.
|
71
|
+
# spreadsheet.acl.delete(spreadsheet.acl[1])
|
72
|
+
def delete(entry)
|
73
|
+
header = {"GData-Version" => "3.0"}
|
74
|
+
@session.request(:delete, entry.edit_url, :header => header, :auth => :writely)
|
75
|
+
@acls.delete(entry)
|
76
|
+
end
|
77
|
+
|
78
|
+
def update_role(entry, role) #:nodoc:
|
79
|
+
|
80
|
+
header = {"GData-Version" => "3.0", "Content-Type" => "application/atom+xml"}
|
81
|
+
value_attr = entry.scope ? "value='#{h(entry.scope)}'" : ""
|
82
|
+
xml = <<-EOS
|
83
|
+
<entry
|
84
|
+
xmlns='http://www.w3.org/2005/Atom'
|
85
|
+
xmlns:gAcl='http://schemas.google.com/acl/2007'
|
86
|
+
xmlns:gd='http://schemas.google.com/g/2005'
|
87
|
+
gd:etag='#{h(entry.etag)}'>
|
88
|
+
<category
|
89
|
+
scheme='http://schemas.google.com/g/2005#kind'
|
90
|
+
term='http://schemas.google.com/acl/2007#accessRule'/>
|
91
|
+
<gAcl:role value='#{h(role)}'/>
|
92
|
+
<gAcl:scope type='#{h(entry.scope_type)}' #{value_attr}/>
|
93
|
+
</entry>
|
94
|
+
EOS
|
95
|
+
doc = @session.request(
|
96
|
+
:put, entry.edit_url, :data => xml, :header => header, :auth => :writely)
|
97
|
+
|
98
|
+
entry.params = entry_to_params(doc.root)
|
99
|
+
return entry
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
def inspect
|
104
|
+
return "\#<%p %p>" % [self.class, @acls]
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
def entry_to_params(entry)
|
110
|
+
# TODO Support with-link roles.
|
111
|
+
return {
|
112
|
+
:acl => self,
|
113
|
+
:scope_type => entry.css("gAcl|scope")[0]["type"],
|
114
|
+
:scope => entry.css("gAcl|scope")[0]["value"],
|
115
|
+
:role => entry.css("gAcl|role")[0]["value"],
|
116
|
+
:title => entry.css("title").text,
|
117
|
+
:edit_url => entry.css("link[rel='edit']")[0]["href"],
|
118
|
+
:etag => entry["etag"],
|
119
|
+
}
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# Author: Guy Boertje <https://github.com/guyboertje>
|
2
|
+
# Author: David R. Albrecht <https://github.com/eldavido>
|
3
|
+
# Author: Hiroshi Ichikawa <http://gimite.net/>
|
4
|
+
# The license of this source is "New BSD Licence"
|
5
|
+
|
6
|
+
# acl.rb, derived from https://github.com/guyboertje/gdata-spreadsheet-ruby/blob/master/lib/document.rb
|
7
|
+
# more frankensteining of the original library
|
8
|
+
|
9
|
+
module GoogleDrive
|
10
|
+
|
11
|
+
# An entry of an ACL (access control list) of a spreadsheet.
|
12
|
+
#
|
13
|
+
# Use GoogleDrive::Acl#[] to get GoogleDrive::AclEntry object.
|
14
|
+
#
|
15
|
+
# This code is based on https://github.com/guyboertje/gdata-spreadsheet-ruby .
|
16
|
+
class AclEntry
|
17
|
+
|
18
|
+
include(Util)
|
19
|
+
|
20
|
+
PARAM_NAMES = [:acl, :scope_type, :scope, :role, :title, :edit_url, :etag] #:nodoc:
|
21
|
+
|
22
|
+
# +params+ is a Hash object with keys +:scope_type+, +:scope+ and +:role+.
|
23
|
+
# See scope_type and role for the document of the fields.
|
24
|
+
def initialize(params)
|
25
|
+
@params = {:role => "reader"}
|
26
|
+
for name, value in params
|
27
|
+
if !PARAM_NAMES.include?(name)
|
28
|
+
raise(ArgumentError, "Invalid key: %p" % name)
|
29
|
+
end
|
30
|
+
@params[name] = value
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
attr_accessor(:params) #:nodoc:
|
35
|
+
|
36
|
+
PARAM_NAMES.each() do |name|
|
37
|
+
define_method(name) do
|
38
|
+
return @params[name]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Changes the role of the scope.
|
43
|
+
#
|
44
|
+
# e.g.
|
45
|
+
# spreadsheet.acl[1].role = "writer"
|
46
|
+
def role=(role)
|
47
|
+
@params[:acl].update_role(self, role)
|
48
|
+
end
|
49
|
+
|
50
|
+
def inspect
|
51
|
+
return "\#<%p scope_type=%p, scope=%p, role=%p>" %
|
52
|
+
[self.class, @params[:scope_type], @params[:scope], @params[:role]]
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|