google_drive 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +2 -0
- data/lib/google_drive.rb +7 -1
- data/lib/google_drive/collection.rb +103 -17
- data/lib/google_drive/file.rb +51 -12
- data/lib/google_drive/list.rb +4 -0
- data/lib/google_drive/list_row.rb +4 -0
- data/lib/google_drive/oauth2_fetcher.rb +2 -2
- data/lib/google_drive/session.rb +34 -10
- data/lib/google_drive/spreadsheet.rb +1 -2
- data/lib/google_drive/util.rb +13 -1
- data/lib/google_drive/worksheet.rb +34 -4
- metadata +37 -11
data/README.rdoc
CHANGED
data/lib/google_drive.rb
CHANGED
@@ -29,7 +29,10 @@ module GoogleDrive
|
|
29
29
|
# :authorize_url => "/o/oauth2/auth")
|
30
30
|
# auth_url = client.auth_code.authorize_url(
|
31
31
|
# :redirect_uri => "http://example.com/",
|
32
|
-
#
|
32
|
+
# :scope =>
|
33
|
+
# "https://docs.google.com/feeds/ " +
|
34
|
+
# "https://docs.googleusercontent.com/ " +
|
35
|
+
# "https://spreadsheets.google.com/feeds/")
|
33
36
|
# # Redirect the user to auth_url and get authorization code from redirect URL.
|
34
37
|
# auth_token = client.auth_code.get_token(
|
35
38
|
# authorization_code, :redirect_uri => "http://example.com/")
|
@@ -42,6 +45,9 @@ module GoogleDrive
|
|
42
45
|
# access_token = access_token.refresh!
|
43
46
|
# session = GoogleDrive.login_with_oauth(access_token)
|
44
47
|
#
|
48
|
+
# If your app is not a Web app, use "urn:ietf:wg:oauth:2.0:oob" as redirect_url. Then
|
49
|
+
# authorization code is shown after authorization.
|
50
|
+
#
|
45
51
|
# OAuth1 code example:
|
46
52
|
#
|
47
53
|
# 1) First generate OAuth consumer object with key and secret for your site by registering site
|
@@ -8,21 +8,45 @@ require "google_drive/spreadsheet"
|
|
8
8
|
|
9
9
|
module GoogleDrive
|
10
10
|
|
11
|
-
# Use GoogleDrive::Session#
|
12
|
-
|
11
|
+
# Use GoogleDrive::Session#root_collection, GoogleDrive::Collection#subcollections,
|
12
|
+
# or GoogleDrive::Session#collection_by_url to get GoogleDrive::Collection object.
|
13
|
+
class Collection < GoogleDrive::File
|
13
14
|
|
14
15
|
include(Util)
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
#:nodoc:
|
18
|
+
ROOT_URL = "#{DOCS_BASE_URL}/folder%3Aroot"
|
19
|
+
|
20
|
+
alias collection_feed_url document_feed_url
|
21
|
+
|
22
|
+
def contents_url
|
23
|
+
if self.root?
|
24
|
+
# The root collection doesn't have document feed.
|
25
|
+
return concat_url(ROOT_URL, "/contents")
|
26
|
+
else
|
27
|
+
return self.document_feed_entry.css(
|
28
|
+
"content[type='application/atom+xml;type=feed']")[0]["src"]
|
29
|
+
end
|
19
30
|
end
|
20
31
|
|
21
|
-
|
32
|
+
# Title of the collection.
|
33
|
+
#
|
34
|
+
# Set <tt>params[:reload]</tt> to true to force reloading the title.
|
35
|
+
def title(params = {})
|
36
|
+
if self.root?
|
37
|
+
# The root collection doesn't have document feed.
|
38
|
+
return nil
|
39
|
+
else
|
40
|
+
return super
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def resource_id
|
45
|
+
return self.root? ? nil : super
|
46
|
+
end
|
22
47
|
|
23
48
|
# Adds the given GoogleDrive::File to the collection.
|
24
49
|
def add(file)
|
25
|
-
contents_url = concat_url(@collection_feed_url, "/contents")
|
26
50
|
header = {"GData-Version" => "3.0", "Content-Type" => "application/atom+xml"}
|
27
51
|
xml = <<-"EOS"
|
28
52
|
<entry xmlns="http://www.w3.org/2005/Atom">
|
@@ -30,25 +54,87 @@ module GoogleDrive
|
|
30
54
|
</entry>
|
31
55
|
EOS
|
32
56
|
@session.request(
|
33
|
-
:post, contents_url, :data => xml, :header => header, :auth => :writely)
|
57
|
+
:post, self.contents_url, :data => xml, :header => header, :auth => :writely)
|
34
58
|
return nil
|
35
59
|
end
|
36
60
|
|
37
|
-
#
|
38
|
-
def
|
39
|
-
contents_url = concat_url(@collection_feed_url, "/contents")
|
61
|
+
# Creates a sub-collection with given title. Returns GoogleDrive::Collection object.
|
62
|
+
def create_subcollection(title)
|
40
63
|
header = {"GData-Version" => "3.0", "Content-Type" => "application/atom+xml"}
|
41
|
-
|
42
|
-
|
64
|
+
xml = <<-EOS
|
65
|
+
<entry xmlns="http://www.w3.org/2005/Atom">
|
66
|
+
<category scheme="http://schemas.google.com/g/2005#kind"
|
67
|
+
term="http://schemas.google.com/docs/2007#folder"/>
|
68
|
+
<title>#{h(title)}</title>
|
69
|
+
</entry>
|
70
|
+
EOS
|
71
|
+
doc = @session.request(
|
72
|
+
:post, contents_url, :data => xml, :header => header, :auth => :writely)
|
73
|
+
return @session.entry_element_to_file(doc)
|
43
74
|
end
|
44
|
-
|
75
|
+
|
76
|
+
# Removes the given GoogleDrive::File from the collection.
|
77
|
+
def remove(file)
|
78
|
+
url = to_v3_url("#{contents_url}/#{file.resource_id}")
|
79
|
+
@session.request(:delete, url, :auth => :writely, :header => {"If-Match" => "*"})
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns true if this is a root collection
|
83
|
+
def root?
|
84
|
+
self.document_feed_url == ROOT_URL
|
85
|
+
end
|
86
|
+
|
87
|
+
# Returns all the files (including spreadsheets, documents, subcollections) in the collection.
|
88
|
+
#
|
89
|
+
# You can specify query parameters described at
|
90
|
+
# https://developers.google.com/google-apps/documents-list/#getting_a_list_of_documents_and_files
|
91
|
+
#
|
92
|
+
# e.g.
|
93
|
+
#
|
94
|
+
# # Gets all the files in collection, including subcollections.
|
95
|
+
# collection.files
|
96
|
+
#
|
97
|
+
# # Gets only files with title "hoge".
|
98
|
+
# collection.files("title" => "hoge", "title-exact" => "true")
|
99
|
+
def files(params = {})
|
100
|
+
return files_with_type(nil, params)
|
101
|
+
end
|
102
|
+
|
103
|
+
alias contents files
|
104
|
+
|
45
105
|
# Returns all the spreadsheets in the collection.
|
46
|
-
def spreadsheets
|
47
|
-
return
|
106
|
+
def spreadsheets(params = {})
|
107
|
+
return files_with_type("spreadsheet", params)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Returns all the Google Docs documents in the collection.
|
111
|
+
def documents(params = {})
|
112
|
+
return files_with_type("document", params)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Returns all its subcollections.
|
116
|
+
def subcollections(params = {})
|
117
|
+
return files_with_type("folder", params)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Returns its subcollection whose title exactly matches +title+ as GoogleDrive::Collection.
|
121
|
+
# Returns nil if not found. If multiple collections with the +title+ are found, returns
|
122
|
+
# one of them.
|
123
|
+
def subcollection_by_title(title)
|
124
|
+
return subcollections("title" => title, "title-exact" => "true")[0]
|
48
125
|
end
|
49
126
|
|
50
|
-
|
127
|
+
private
|
51
128
|
|
129
|
+
def files_with_type(type, params = {})
|
130
|
+
contents_url = self.contents_url
|
131
|
+
contents_url = concat_url(contents_url, "/-/#{type}") if type
|
132
|
+
contents_url = concat_url(contents_url, "?" + encode_query(params))
|
133
|
+
header = {"GData-Version" => "3.0", "Content-Type" => "application/atom+xml"}
|
134
|
+
doc = @session.request(:get, contents_url, :header => header, :auth => :writely)
|
135
|
+
return doc.css("feed > entry").map(){ |e| @session.entry_element_to_file(e) }
|
136
|
+
end
|
137
|
+
|
52
138
|
end
|
53
139
|
|
54
140
|
end
|
data/lib/google_drive/file.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# Author: Hiroshi Ichikawa <http://gimite.net/>
|
2
2
|
# The license of this source is "New BSD Licence"
|
3
3
|
|
4
|
+
require "cgi"
|
4
5
|
require "stringio"
|
5
6
|
|
6
7
|
require "google_drive/util"
|
@@ -17,11 +18,24 @@ module GoogleDrive
|
|
17
18
|
|
18
19
|
include(Util)
|
19
20
|
|
20
|
-
def initialize(session,
|
21
|
+
def initialize(session, entry_or_url) #:nodoc:
|
21
22
|
@session = session
|
22
|
-
|
23
|
-
|
24
|
-
|
23
|
+
if !entry_or_url
|
24
|
+
# TODO Delete this after editing spreadsheet.rb.
|
25
|
+
@document_feed_entry = nil
|
26
|
+
@document_feed_url = entry_or_url
|
27
|
+
elsif entry_or_url.is_a?(String)
|
28
|
+
@document_feed_entry = nil
|
29
|
+
@document_feed_url = entry_or_url
|
30
|
+
else
|
31
|
+
@document_feed_entry = entry_or_url
|
32
|
+
# This is usually equal to the URL in <link rel="self">. But the URL in
|
33
|
+
# <link rel="self"> in collection feed is e.g.
|
34
|
+
# https://docs.google.com/feeds/default/private/full/folder%3Aroot/contents/folder%3Axxx
|
35
|
+
# and deletion of the URL doesn't delete the file itself.
|
36
|
+
# So we construct the URL here using resource ID instead.
|
37
|
+
@document_feed_url = "%s/%s" % [DOCS_BASE_URL, CGI.escape(self.resource_id)]
|
38
|
+
end
|
25
39
|
@acl = nil
|
26
40
|
end
|
27
41
|
|
@@ -29,10 +43,32 @@ module GoogleDrive
|
|
29
43
|
attr_reader(:document_feed_url)
|
30
44
|
|
31
45
|
# <entry> element of document list feed as Nokogiri::XML::Element.
|
32
|
-
|
33
|
-
|
46
|
+
#
|
47
|
+
# Set <tt>params[:reload]</tt> to true to force reloading the feed.
|
48
|
+
def document_feed_entry(params = {})
|
49
|
+
if !@document_feed_entry || params[:reload]
|
50
|
+
@document_feed_entry =
|
51
|
+
@session.request(:get, self.document_feed_url, :auth => :writely).css("entry")[0]
|
52
|
+
end
|
53
|
+
return @document_feed_entry
|
54
|
+
end
|
55
|
+
|
56
|
+
# Resource ID.
|
57
|
+
def resource_id
|
58
|
+
return self.document_feed_entry.css("gd|resourceId").text
|
59
|
+
end
|
60
|
+
|
61
|
+
# The type of resourse. e.g. "document", "spreadsheet", "folder"
|
62
|
+
def resource_type
|
63
|
+
return self.resource_id.split(/:/)[0]
|
64
|
+
end
|
65
|
+
|
34
66
|
# Title of the file.
|
35
|
-
|
67
|
+
#
|
68
|
+
# Set <tt>params[:reload]</tt> to true to force reloading the title.
|
69
|
+
def title(params = {})
|
70
|
+
return document_feed_entry(params).css("title").text
|
71
|
+
end
|
36
72
|
|
37
73
|
# URL to view/edit the file in a Web browser.
|
38
74
|
#
|
@@ -50,7 +86,7 @@ module GoogleDrive
|
|
50
86
|
return orig_acl_feed_url
|
51
87
|
when %r{^https?://docs.google.com/feeds/acl/private/full/([^\?]*)(\?.*)?$}
|
52
88
|
# URL of old API version. Converts to v3 URL.
|
53
|
-
return "
|
89
|
+
return "#{DOCS_BASE_URL}/#{$1}/acl"
|
54
90
|
else
|
55
91
|
raise(GoogleDrive::Error,
|
56
92
|
"ACL feed URL is in unknown format: #{orig_acl_feed_url}")
|
@@ -149,8 +185,9 @@ module GoogleDrive
|
|
149
185
|
# If +permanent+ is +false+, moves the file to the trash.
|
150
186
|
# If +permanent+ is +true+, deletes the file permanently.
|
151
187
|
def delete(permanent = false)
|
152
|
-
|
153
|
-
|
188
|
+
url = to_v3_url(self.document_feed_url)
|
189
|
+
url = concat_url(url, "?delete=true") if permanent
|
190
|
+
@session.request(:delete, url,
|
154
191
|
:auth => :writely, :header => {"If-Match" => "*"})
|
155
192
|
end
|
156
193
|
|
@@ -180,7 +217,7 @@ module GoogleDrive
|
|
180
217
|
# With the object, you can see and modify people who can access the file.
|
181
218
|
# Modifications take effect immediately.
|
182
219
|
#
|
183
|
-
# Set <tt>params[:reload]</tt> to true to force reloading the
|
220
|
+
# Set <tt>params[:reload]</tt> to true to force reloading the data.
|
184
221
|
#
|
185
222
|
# e.g.
|
186
223
|
# # Dumps people who have access:
|
@@ -209,7 +246,9 @@ module GoogleDrive
|
|
209
246
|
end
|
210
247
|
|
211
248
|
def inspect
|
212
|
-
|
249
|
+
fields = {:document_feed_url => self.document_feed_url}
|
250
|
+
fields[:title] = self.title if @document_feed_entry
|
251
|
+
return "\#<%p %s>" % [self.class, fields.map(){ |k, v| "%s=%p" % [k, v] }.join(", ")]
|
213
252
|
end
|
214
253
|
|
215
254
|
end
|
data/lib/google_drive/list.rb
CHANGED
@@ -97,6 +97,10 @@ module GoogleDrive
|
|
97
97
|
return @worksheet[index + 2, key_to_col(key)]
|
98
98
|
end
|
99
99
|
|
100
|
+
def numeric_value(index, key) #:nodoc:
|
101
|
+
return @worksheet.numeric_value(index + 2, key_to_col(key))
|
102
|
+
end
|
103
|
+
|
100
104
|
def set(index, key, value) #:nodoc:
|
101
105
|
@worksheet[index + 2, key_to_col(key)] = value
|
102
106
|
end
|
@@ -35,9 +35,9 @@ module GoogleDrive
|
|
35
35
|
|
36
36
|
def request_raw(method, url, data, extra_header, auth)
|
37
37
|
if method == :delete || method == :get
|
38
|
-
raw_res = @oauth2_token.request(method, url, {:
|
38
|
+
raw_res = @oauth2_token.request(method, url, {:headers => extra_header})
|
39
39
|
else
|
40
|
-
raw_res = @oauth2_token.request(method, url, {:
|
40
|
+
raw_res = @oauth2_token.request(method, url, {:headers => extra_header, :body => data})
|
41
41
|
end
|
42
42
|
return Response.new(raw_res)
|
43
43
|
end
|
data/lib/google_drive/session.rb
CHANGED
@@ -112,12 +112,14 @@ module GoogleDrive
|
|
112
112
|
# You can specify query parameters described at
|
113
113
|
# https://developers.google.com/google-apps/documents-list/#getting_a_list_of_documents_and_files
|
114
114
|
#
|
115
|
+
# files doesn't return collections unless "showfolders" => true is specified.
|
116
|
+
#
|
115
117
|
# e.g.
|
116
118
|
# session.files
|
117
119
|
# session.files("title" => "hoge", "title-exact" => "true")
|
118
120
|
def files(params = {})
|
119
121
|
url = concat_url(
|
120
|
-
"
|
122
|
+
"#{DOCS_BASE_URL}?v=3", "?" + encode_query(params))
|
121
123
|
doc = request(:get, url, :auth => :writely)
|
122
124
|
return doc.css("feed > entry").map(){ |e| entry_element_to_file(e) }
|
123
125
|
end
|
@@ -200,7 +202,25 @@ module GoogleDrive
|
|
200
202
|
def worksheet_by_url(url)
|
201
203
|
return Worksheet.new(self, nil, url)
|
202
204
|
end
|
203
|
-
|
205
|
+
|
206
|
+
# Returns the root collection.
|
207
|
+
def root_collection
|
208
|
+
return Collection.new(self, Collection::ROOT_URL)
|
209
|
+
end
|
210
|
+
|
211
|
+
# Returns the top-level collections (direct children of the root collection).
|
212
|
+
def collections
|
213
|
+
return self.root_collection.subcollections
|
214
|
+
end
|
215
|
+
|
216
|
+
# Returns a top-level collection whose title exactly matches +title+ as
|
217
|
+
# GoogleDrive::Collection.
|
218
|
+
# Returns nil if not found. If multiple collections with the +title+ are found, returns
|
219
|
+
# one of them.
|
220
|
+
def collection_by_title(title)
|
221
|
+
return self.root_collection.subcollection_by_title(title)
|
222
|
+
end
|
223
|
+
|
204
224
|
# Returns GoogleDrive::Collection with given +url+.
|
205
225
|
# You must specify either of:
|
206
226
|
# - URL of the page you get when you go to https://docs.google.com/ with your browser and
|
@@ -219,7 +239,7 @@ module GoogleDrive
|
|
219
239
|
if ["docs.google.com", "drive.google.com"].include?(uri.host) &&
|
220
240
|
uri.fragment =~ /^folders\/(.+)$/
|
221
241
|
# Looks like a URL of human-readable collection page. Converts to collection feed URL.
|
222
|
-
url = "
|
242
|
+
url = "#{DOCS_BASE_URL}/folder%3A#{$1}"
|
223
243
|
end
|
224
244
|
return Collection.new(self, url)
|
225
245
|
end
|
@@ -289,7 +309,7 @@ module GoogleDrive
|
|
289
309
|
# Uploads a file. Reads content from +io+.
|
290
310
|
# Returns a GoogleSpreadsheet::File object.
|
291
311
|
def upload_from_io(io, title = "Untitled", params = {})
|
292
|
-
doc = request(:get, "
|
312
|
+
doc = request(:get, "#{DOCS_BASE_URL}?v=3",
|
293
313
|
:auth => :writely)
|
294
314
|
initial_url = doc.css(
|
295
315
|
"link[rel='http://schemas.google.com/g/2005#resumable-create-media']")[0]["href"]
|
@@ -352,13 +372,17 @@ module GoogleDrive
|
|
352
372
|
end
|
353
373
|
|
354
374
|
def entry_element_to_file(entry) #:nodoc:
|
375
|
+
type, resource_id = entry.css("gd|resourceId").text.split(/:/)
|
355
376
|
title = entry.css("title").text
|
356
|
-
|
357
|
-
"
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
377
|
+
case type
|
378
|
+
when "folder"
|
379
|
+
return Collection.new(self, entry)
|
380
|
+
when "spreadsheet"
|
381
|
+
worksheets_feed_link = entry.css(
|
382
|
+
"link[rel='http://schemas.google.com/spreadsheets/2006#worksheetsfeed']")[0]
|
383
|
+
return Spreadsheet.new(self, worksheets_feed_link["href"], title)
|
384
|
+
else
|
385
|
+
return GoogleDrive::File.new(self, entry)
|
362
386
|
end
|
363
387
|
end
|
364
388
|
|
@@ -103,7 +103,6 @@ module GoogleDrive
|
|
103
103
|
# Creates copy of this spreadsheet with the given title.
|
104
104
|
def duplicate(new_title = nil)
|
105
105
|
new_title ||= (self.title ? "Copy of " + self.title : "Untitled")
|
106
|
-
post_url = "https://docs.google.com/feeds/default/private/full/"
|
107
106
|
header = {"GData-Version" => "3.0", "Content-Type" => "application/atom+xml"}
|
108
107
|
xml = <<-"EOS"
|
109
108
|
<entry xmlns='http://www.w3.org/2005/Atom'>
|
@@ -112,7 +111,7 @@ module GoogleDrive
|
|
112
111
|
</entry>
|
113
112
|
EOS
|
114
113
|
doc = @session.request(
|
115
|
-
:post,
|
114
|
+
:post, DOCS_BASE_URL, :data => xml, :header => header, :auth => :writely)
|
116
115
|
ss_url = doc.css(
|
117
116
|
"link[rel='http://schemas.google.com/spreadsheets/2006#worksheetsfeed']")[0]["href"]
|
118
117
|
return Spreadsheet.new(@session, ss_url, new_title)
|
data/lib/google_drive/util.rb
CHANGED
@@ -7,6 +7,9 @@ require "cgi"
|
|
7
7
|
module GoogleDrive
|
8
8
|
|
9
9
|
module Util #:nodoc:
|
10
|
+
|
11
|
+
# The beginning of Doc List API URL that is used in all requests (version 3).
|
12
|
+
DOCS_BASE_URL = "https://docs.google.com/feeds/default/private/full"
|
10
13
|
|
11
14
|
EXT_TO_CONTENT_TYPE = {
|
12
15
|
".csv" =>"text/csv",
|
@@ -45,7 +48,16 @@ module GoogleDrive
|
|
45
48
|
(piece_base || "") +
|
46
49
|
(result_query.empty? ? "" : "?#{result_query}")
|
47
50
|
end
|
48
|
-
|
51
|
+
|
52
|
+
# Returns a URL with added version parameter ("?v=3") if needed.
|
53
|
+
def to_v3_url(url)
|
54
|
+
if url =~ %r{docs.google.com/feeds/default/private/} && !(url =~ /[?&]v=3/)
|
55
|
+
return concat_url(url, "?v=3")
|
56
|
+
else
|
57
|
+
return url
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
49
61
|
def h(str)
|
50
62
|
return CGI.escapeHTML(str.to_s())
|
51
63
|
end
|
@@ -26,6 +26,7 @@ module GoogleDrive
|
|
26
26
|
|
27
27
|
@cells = nil
|
28
28
|
@input_values = nil
|
29
|
+
@numeric_values = nil
|
29
30
|
@modified = Set.new()
|
30
31
|
@list = nil
|
31
32
|
|
@@ -86,6 +87,7 @@ module GoogleDrive
|
|
86
87
|
reload() if !@cells
|
87
88
|
@cells[[row, col]] = value
|
88
89
|
@input_values[[row, col]] = value
|
90
|
+
@numeric_values[[row, col]] = nil
|
89
91
|
@modified.add([row, col])
|
90
92
|
self.max_rows = row if row > @max_rows
|
91
93
|
self.max_cols = col if col > @max_cols
|
@@ -116,6 +118,25 @@ module GoogleDrive
|
|
116
118
|
return @input_values[[row, col]] || ""
|
117
119
|
end
|
118
120
|
|
121
|
+
# Returns the numeric value of the cell. Arguments must be either
|
122
|
+
# (row number, column number) or cell name. Top-left cell is [1, 1].
|
123
|
+
#
|
124
|
+
# e.g.
|
125
|
+
# worksheet[1, 3] #=> "3,0" # it depends on locale, currency...
|
126
|
+
# worksheet.numeric_value(1, 3) #=> 3.0
|
127
|
+
#
|
128
|
+
# Returns nil if the cell is empty or contains non-number.
|
129
|
+
#
|
130
|
+
# If you modify the cell, its numeric_value is nil until you call save() and reload().
|
131
|
+
#
|
132
|
+
# For details, see:
|
133
|
+
# https://developers.google.com/google-apps/spreadsheets/#working_with_cell-based_feeds
|
134
|
+
def numeric_value(*args)
|
135
|
+
(row, col) = parse_cell_args(args)
|
136
|
+
reload() if !@cells
|
137
|
+
return @numeric_values[[row, col]]
|
138
|
+
end
|
139
|
+
|
119
140
|
# Row number of the bottom-most non-empty row.
|
120
141
|
def num_rows
|
121
142
|
reload() if !@cells
|
@@ -176,8 +197,9 @@ module GoogleDrive
|
|
176
197
|
end
|
177
198
|
|
178
199
|
# An array of spreadsheet rows. Each row contains an array of
|
179
|
-
# columns. Note that resulting array is 0-origin so
|
180
|
-
#
|
200
|
+
# columns. Note that resulting array is 0-origin so:
|
201
|
+
#
|
202
|
+
# worksheet.rows[0][0] == worksheet[1, 1]
|
181
203
|
def rows(skip = 0)
|
182
204
|
nc = self.num_cols
|
183
205
|
result = ((1 + skip)..self.num_rows).map() do |row|
|
@@ -197,12 +219,15 @@ module GoogleDrive
|
|
197
219
|
|
198
220
|
@cells = {}
|
199
221
|
@input_values = {}
|
222
|
+
@numeric_values = {}
|
200
223
|
doc.css("feed > entry").each() do |entry|
|
201
224
|
cell = entry.css("gs|cell")[0]
|
202
225
|
row = cell["row"].to_i()
|
203
226
|
col = cell["col"].to_i()
|
204
227
|
@cells[[row, col]] = cell.inner_text
|
205
228
|
@input_values[[row, col]] = cell["inputValue"]
|
229
|
+
numeric_value = cell["numericValue"]
|
230
|
+
@numeric_values[[row, col]] = numeric_value ? numeric_value.to_f() : nil
|
206
231
|
end
|
207
232
|
@modified.clear()
|
208
233
|
@meta_modified = false
|
@@ -433,10 +458,15 @@ module GoogleDrive
|
|
433
458
|
if args.size == 1 && args[0].is_a?(String)
|
434
459
|
return cell_name_to_row_col(args[0])
|
435
460
|
elsif args.size == 2 && args[0].is_a?(Integer) && args[1].is_a?(Integer)
|
436
|
-
|
461
|
+
if args[0] >= 1 && args[1] >= 1
|
462
|
+
return args
|
463
|
+
else
|
464
|
+
raise(ArgumentError,
|
465
|
+
"Row/col must be >= 1 (1-origin), but are %d/%d" % [args[0], args[1]])
|
466
|
+
end
|
437
467
|
else
|
438
468
|
raise(ArgumentError,
|
439
|
-
"Arguments must be either one String or two Integer's, but are %p" % args)
|
469
|
+
"Arguments must be either one String or two Integer's, but are %p" % [args])
|
440
470
|
end
|
441
471
|
end
|
442
472
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: google_drive
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-07-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -27,10 +27,21 @@ dependencies:
|
|
27
27
|
version: 1.5.2
|
28
28
|
type: :runtime
|
29
29
|
prerelease: false
|
30
|
-
version_requirements:
|
30
|
+
version_requirements: !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ! '>='
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 1.4.4
|
36
|
+
- - ! '!='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: 1.5.1
|
39
|
+
- - ! '!='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 1.5.2
|
31
42
|
- !ruby/object:Gem::Dependency
|
32
43
|
name: oauth
|
33
|
-
requirement:
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
34
45
|
none: false
|
35
46
|
requirements:
|
36
47
|
- - ! '>='
|
@@ -38,10 +49,15 @@ dependencies:
|
|
38
49
|
version: 0.3.6
|
39
50
|
type: :runtime
|
40
51
|
prerelease: false
|
41
|
-
version_requirements:
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ! '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 0.3.6
|
42
58
|
- !ruby/object:Gem::Dependency
|
43
59
|
name: oauth2
|
44
|
-
requirement:
|
60
|
+
requirement: !ruby/object:Gem::Requirement
|
45
61
|
none: false
|
46
62
|
requirements:
|
47
63
|
- - ! '>='
|
@@ -49,10 +65,15 @@ dependencies:
|
|
49
65
|
version: 0.5.0
|
50
66
|
type: :runtime
|
51
67
|
prerelease: false
|
52
|
-
version_requirements:
|
68
|
+
version_requirements: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ! '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 0.5.0
|
53
74
|
- !ruby/object:Gem::Dependency
|
54
75
|
name: rake
|
55
|
-
requirement:
|
76
|
+
requirement: !ruby/object:Gem::Requirement
|
56
77
|
none: false
|
57
78
|
requirements:
|
58
79
|
- - ! '>='
|
@@ -60,7 +81,12 @@ dependencies:
|
|
60
81
|
version: 0.8.0
|
61
82
|
type: :development
|
62
83
|
prerelease: false
|
63
|
-
version_requirements:
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.8.0
|
64
90
|
description: A library to read/write files/spreadsheets in Google Drive/Docs.
|
65
91
|
email:
|
66
92
|
- gimite+github@gmail.com
|
@@ -114,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
114
140
|
version: '0'
|
115
141
|
requirements: []
|
116
142
|
rubyforge_project:
|
117
|
-
rubygems_version: 1.8.
|
143
|
+
rubygems_version: 1.8.23
|
118
144
|
signing_key:
|
119
145
|
specification_version: 3
|
120
146
|
summary: A library to read/write files/spreadsheets in Google Drive/Docs.
|