google_drive 0.3.11 → 1.0.0.pre1
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.
- checksums.yaml +7 -7
- data/README.rdoc +27 -10
- data/lib/google_drive/acl.rb +40 -58
- data/lib/google_drive/acl_entry.rb +76 -56
- data/lib/google_drive/api_client_fetcher.rb +49 -0
- data/lib/google_drive/collection.rb +69 -71
- data/lib/google_drive/file.rb +171 -128
- data/lib/google_drive/session.rb +234 -268
- data/lib/google_drive/spreadsheet.rb +19 -163
- data/lib/google_drive/util.rb +126 -17
- data/lib/google_drive/worksheet.rb +108 -80
- data/lib/google_drive.rb +63 -57
- data/lib/google_drive_v1/acl.rb +115 -0
- data/lib/google_drive_v1/acl_entry.rb +100 -0
- data/lib/google_drive_v1/api_client_fetcher.rb +47 -0
- data/lib/google_drive_v1/authentication_error.rb +14 -0
- data/lib/{google_drive → google_drive_v1}/basic_fetcher.rb +1 -1
- data/lib/{google_drive → google_drive_v1}/client_login_fetcher.rb +2 -2
- data/lib/google_drive_v1/collection.rb +167 -0
- data/lib/google_drive_v1/error.rb +12 -0
- data/lib/google_drive_v1/file.rb +258 -0
- data/lib/google_drive_v1/list.rb +119 -0
- data/lib/google_drive_v1/list_row.rb +88 -0
- data/lib/{google_drive → google_drive_v1}/oauth1_fetcher.rb +1 -1
- data/lib/{google_drive → google_drive_v1}/oauth2_fetcher.rb +2 -2
- data/lib/google_drive_v1/record.rb +31 -0
- data/lib/google_drive_v1/session.rb +522 -0
- data/lib/google_drive_v1/spreadsheet.rb +248 -0
- data/lib/google_drive_v1/table.rb +60 -0
- data/lib/google_drive_v1/util.rb +73 -0
- data/lib/google_drive_v1/worksheet.rb +498 -0
- data/lib/google_drive_v1.rb +148 -0
- metadata +112 -77
- data/doc_src/google_drive/acl_entry.rb +0 -33
data/lib/google_drive/file.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
# The license of this source is "New BSD Licence"
|
3
3
|
|
4
4
|
require "cgi"
|
5
|
+
require "forwardable"
|
5
6
|
require "stringio"
|
6
7
|
|
7
8
|
require "google_drive/util"
|
@@ -14,109 +15,90 @@ module GoogleDrive
|
|
14
15
|
#
|
15
16
|
# Use GoogleDrive::Session#files or GoogleDrive::Session#file_by_title to
|
16
17
|
# get this object.
|
18
|
+
#
|
19
|
+
# In addition to the methods below, properties defined here are also available as attributes:
|
20
|
+
# https://developers.google.com/drive/v2/reference/files#resource
|
21
|
+
#
|
22
|
+
# e.g.,
|
23
|
+
# file.mime_type # ==> "text/plain"
|
17
24
|
class File
|
18
25
|
|
19
26
|
include(Util)
|
27
|
+
extend(Forwardable)
|
20
28
|
|
21
|
-
def initialize(session,
|
29
|
+
def initialize(session, api_file) #:nodoc:
|
22
30
|
@session = session
|
23
|
-
|
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?v=3" % [DOCS_BASE_URL, CGI.escape(self.resource_id)]
|
38
|
-
end
|
31
|
+
@api_file = api_file
|
39
32
|
@acl = nil
|
33
|
+
delegate_api_methods(self, @api_file, ["title"])
|
40
34
|
end
|
41
|
-
|
42
|
-
# URL of feed used in document list feed API.
|
43
|
-
attr_reader(:document_feed_url)
|
44
|
-
|
45
|
-
# <entry> element of document list feed as Nokogiri::XML::Element.
|
46
|
-
#
|
47
|
-
# Set <tt>params[:reload]</tt> to true to force reloading the feed.
|
48
|
-
def document_feed_entry(params = {})
|
49
|
-
warn(
|
50
|
-
"WARNING: GoogleDrive::file\#document_feed_entry is deprecated and will be removed " +
|
51
|
-
"in the next version.")
|
52
|
-
return self.document_feed_entry_internal(params)
|
53
|
-
end
|
54
35
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
36
|
+
# Wrapped Google::APIClient::Schema::Drive::V2::File object.
|
37
|
+
attr_reader(:api_file)
|
38
|
+
|
39
|
+
# Reloads file metadata such as title and acl.
|
40
|
+
def reload_metadata()
|
41
|
+
api_result = @session.execute!(
|
42
|
+
:api_method => @session.drive.files.get,
|
43
|
+
:parameters => { "fileId" => self.id })
|
44
|
+
@api_file = api_result.data
|
45
|
+
if @acl
|
46
|
+
@acl = Acl.new(@session, self)
|
59
47
|
end
|
60
|
-
return @document_feed_entry
|
61
48
|
end
|
62
49
|
|
63
|
-
#
|
50
|
+
# Returns resource_type + ":" + id.
|
64
51
|
def resource_id
|
65
|
-
return self.
|
52
|
+
return "%s:%s" % [self.resource_type, self.id]
|
53
|
+
end
|
54
|
+
|
55
|
+
# URL of feed used in the deprecated document list feed API.
|
56
|
+
def document_feed_url
|
57
|
+
return "https://docs.google.com/feeds/default/private/full/" + CGI.escape(self.resource_id)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Deprecated ACL feed URL of the file.
|
61
|
+
def acl_feed_url
|
62
|
+
return self.document_feed_url + "/acl"
|
66
63
|
end
|
67
64
|
|
68
65
|
# The type of resourse. e.g. "document", "spreadsheet", "folder"
|
69
66
|
def resource_type
|
70
|
-
return self.
|
67
|
+
return self.mime_type.slice(/^application\/vnd.google-apps.(.+)$/, 1) || "file"
|
71
68
|
end
|
72
69
|
|
73
70
|
# Title of the file.
|
74
|
-
#
|
75
|
-
# Set <tt>params[:reload]</tt> to true to force reloading the title.
|
76
71
|
def title(params = {})
|
77
|
-
|
72
|
+
reload_metadata() if params[:reload]
|
73
|
+
return self.api_file.title
|
78
74
|
end
|
79
75
|
|
80
76
|
# URL to view/edit the file in a Web browser.
|
81
77
|
#
|
82
78
|
# e.g. "https://docs.google.com/file/d/xxxx/edit"
|
83
79
|
def human_url
|
84
|
-
return self.
|
80
|
+
return self.alternate_link
|
85
81
|
end
|
86
82
|
|
87
|
-
# ACL feed URL of the file.
|
88
|
-
def acl_feed_url
|
89
|
-
orig_acl_feed_url = self.document_feed_entry_internal.css(
|
90
|
-
"gd|feedLink[rel='http://schemas.google.com/acl/2007#accessControlList']")[0]["href"]
|
91
|
-
case orig_acl_feed_url
|
92
|
-
when %r{^https?://docs.google.com/feeds/default/private/full/.*/acl(\?.*)?$}
|
93
|
-
return orig_acl_feed_url
|
94
|
-
when %r{^https?://docs.google.com/feeds/acl/private/full/([^\?]*)(\?.*)?$}
|
95
|
-
# URL of old API version. Converts to v3 URL.
|
96
|
-
return "#{DOCS_BASE_URL}/#{$1}/acl"
|
97
|
-
else
|
98
|
-
raise(GoogleDrive::Error,
|
99
|
-
"ACL feed URL is in unknown format: #{orig_acl_feed_url}")
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
83
|
# Content types you can specify in methods download_to_file, download_to_string,
|
104
84
|
# download_to_io .
|
85
|
+
#
|
86
|
+
# This returns zero or one file type. You may be able to download the file in other formats using
|
87
|
+
# export_as_file, export_as_string, or export_to_io. Use export_links method to get available formats
|
88
|
+
# in these methods.
|
105
89
|
def available_content_types
|
106
|
-
|
90
|
+
if self.api_file.download_url
|
91
|
+
return [self.api_file.mime_type]
|
92
|
+
else
|
93
|
+
return []
|
94
|
+
end
|
107
95
|
end
|
108
96
|
|
109
|
-
# Downloads the file to a local file.
|
110
|
-
#
|
111
|
-
# e.g.
|
97
|
+
# Downloads the file to a local file. e.g.
|
112
98
|
# file.download_to_file("/path/to/hoge.txt")
|
113
|
-
#
|
99
|
+
#
|
100
|
+
# To export the file in other formats, use export_as_file.
|
114
101
|
def download_to_file(path, params = {})
|
115
|
-
params = params.dup()
|
116
|
-
if !params[:content_type]
|
117
|
-
params[:content_type] = EXT_TO_CONTENT_TYPE[::File.extname(path).downcase]
|
118
|
-
params[:content_type_is_hint] = true
|
119
|
-
end
|
120
102
|
open(path, "wb") do |f|
|
121
103
|
download_to_io(f, params)
|
122
104
|
end
|
@@ -124,9 +106,7 @@ module GoogleDrive
|
|
124
106
|
|
125
107
|
# Downloads the file and returns as a String.
|
126
108
|
#
|
127
|
-
#
|
128
|
-
# file.download_to_string() #=> "Hello world."
|
129
|
-
# file.download_to_string(:content_type => "text/plain") #=> "Hello world."
|
109
|
+
# To export the file in other formats, use export_as_string.
|
130
110
|
def download_to_string(params = {})
|
131
111
|
sio = StringIO.new()
|
132
112
|
download_to_io(sio, params)
|
@@ -134,42 +114,73 @@ module GoogleDrive
|
|
134
114
|
end
|
135
115
|
|
136
116
|
# Downloads the file and writes it to +io+.
|
117
|
+
#
|
118
|
+
# To export the file in other formats, use export_to_io.
|
137
119
|
def download_to_io(io, params = {})
|
138
|
-
|
139
|
-
|
140
|
-
contents = all_contents.select(){ |c| c["type"] == params[:content_type] }
|
141
|
-
else
|
142
|
-
contents = all_contents
|
120
|
+
if !self.api_file.download_url
|
121
|
+
raise(GoogleDrive::Error, "Downloading is not supported for this file.")
|
143
122
|
end
|
144
|
-
if
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
123
|
+
# TODO Use streaming if possible.
|
124
|
+
api_result = @session.execute!(:uri => self.api_file.download_url)
|
125
|
+
io.write(api_result.body)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Export the file to +path+ in content type +format+.
|
129
|
+
# If +format+ is nil, it is guessed from the file name.
|
130
|
+
#
|
131
|
+
# e.g.,
|
132
|
+
# spreadsheet.export_as_file("/path/to/hoge.csv")
|
133
|
+
# spreadsheet.export_as_file("/path/to/hoge", "text/csv")
|
134
|
+
#
|
135
|
+
# If you want to download the file in the original format, use download_to_file instead.
|
136
|
+
def export_as_file(path, format = nil)
|
137
|
+
if !format
|
138
|
+
format = EXT_TO_CONTENT_TYPE[::File.extname(path).downcase]
|
139
|
+
if !format
|
140
|
+
raise(ArgumentError,
|
141
|
+
("Cannot guess format from the file name: %s\n" +
|
142
|
+
"Specify format argument explicitly.") %
|
143
|
+
path)
|
157
144
|
end
|
158
145
|
end
|
159
|
-
|
160
|
-
|
161
|
-
|
146
|
+
open(path, "wb") do |f|
|
147
|
+
export_to_io(f, format)
|
148
|
+
end
|
162
149
|
end
|
163
150
|
|
164
|
-
#
|
151
|
+
# Export the file as String in content type +format+.
|
165
152
|
#
|
166
|
-
# e.g
|
167
|
-
#
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
153
|
+
# e.g.,
|
154
|
+
# spreadsheet.export_as_string("text/csv")
|
155
|
+
#
|
156
|
+
# If you want to download the file in the original format, use download_to_string instead.
|
157
|
+
def export_as_string(format)
|
158
|
+
sio = StringIO.new()
|
159
|
+
export_to_io(sio, format)
|
160
|
+
return sio.string
|
161
|
+
end
|
162
|
+
|
163
|
+
# Export the file to +io+ in content type +format+.
|
164
|
+
#
|
165
|
+
# If you want to download the file in the original format, use download_to_io instead.
|
166
|
+
def export_to_io(io, format)
|
167
|
+
mime_type = EXT_TO_CONTENT_TYPE["." + format] || format
|
168
|
+
if !self.export_links
|
169
|
+
raise(
|
170
|
+
GoogleDrive::Error,
|
171
|
+
"This file doesn't support exporting. You may still download the file in the " +
|
172
|
+
"original format using download_to_file, download_to_string or download_to_io.")
|
173
|
+
end
|
174
|
+
export_url = self.export_links[mime_type]
|
175
|
+
if !export_url
|
176
|
+
raise(
|
177
|
+
GoogleDrive::Error,
|
178
|
+
"This file doesn't support export with mime type %p. Supported mime types: %p" %
|
179
|
+
[mime_type, self.export_links.to_hash().keys])
|
172
180
|
end
|
181
|
+
# TODO Use streaming if possible.
|
182
|
+
api_result = @session.execute!(:uri => export_url)
|
183
|
+
io.write(api_result.body)
|
173
184
|
end
|
174
185
|
|
175
186
|
# Updates the file with +content+.
|
@@ -177,50 +188,84 @@ module GoogleDrive
|
|
177
188
|
# e.g.
|
178
189
|
# file.update_from_string("Good bye, world.")
|
179
190
|
def update_from_string(content, params = {})
|
180
|
-
|
191
|
+
media = new_upload_io(StringIO.new(content), params)
|
192
|
+
return update_from_media(media, params)
|
181
193
|
end
|
182
194
|
|
195
|
+
# Updates the file with the content of the local file.
|
196
|
+
#
|
197
|
+
# e.g.
|
198
|
+
# file.update_from_file("/path/to/hoge.txt")
|
199
|
+
def update_from_file(path, params = {})
|
200
|
+
file_name = ::File.basename(path)
|
201
|
+
params = {:file_name => file_name}.merge(params)
|
202
|
+
media = new_upload_io(path, params)
|
203
|
+
return update_from_media(media, params)
|
204
|
+
end
|
205
|
+
|
183
206
|
# Reads content from +io+ and updates the file with the content.
|
184
207
|
def update_from_io(io, params = {})
|
185
|
-
|
186
|
-
|
187
|
-
"link[rel='http://schemas.google.com/g/2005#resumable-edit-media']")[0]["href"]
|
188
|
-
@document_feed_entry = @session.upload_raw(
|
189
|
-
:put, initial_url, io, self.title, params)
|
208
|
+
media = new_upload_io(io, params)
|
209
|
+
return update_from_media(media, params)
|
190
210
|
end
|
191
|
-
|
211
|
+
|
212
|
+
# Reads content from +media+ and updates the file with the content.
|
213
|
+
def update_from_media(media, params = {})
|
214
|
+
api_result = @session.execute!(
|
215
|
+
:api_method => @session.drive.files.update,
|
216
|
+
:media => media,
|
217
|
+
:parameters => {
|
218
|
+
"fileId" => self.id,
|
219
|
+
"uploadType" => "media",
|
220
|
+
})
|
221
|
+
return @session.wrap_api_file(api_result.data)
|
222
|
+
end
|
223
|
+
|
192
224
|
# If +permanent+ is +false+, moves the file to the trash.
|
193
225
|
# If +permanent+ is +true+, deletes the file permanently.
|
194
226
|
def delete(permanent = false)
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
227
|
+
if permanent
|
228
|
+
@session.execute!(
|
229
|
+
:api_method => @session.drive.files.delete,
|
230
|
+
:parameters => {"fileId" => self.id})
|
231
|
+
else
|
232
|
+
@session.execute!(
|
233
|
+
:api_method => @session.drive.files.trash,
|
234
|
+
:parameters => {"fileId" => self.id})
|
235
|
+
end
|
236
|
+
return nil
|
199
237
|
end
|
200
238
|
|
201
239
|
# Renames title of the file.
|
202
240
|
def rename(title)
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
<atom:title>#{h(title)}</atom:title>
|
209
|
-
</atom:entry>
|
210
|
-
EOS
|
211
|
-
header = {"Content-Type" => "application/atom+xml;charset=utf-8", "If-Match" => "*"}
|
212
|
-
@session.request(:put, edit_url, :data => xml, :auth => :writely, :header => header)
|
241
|
+
api_result = @session.execute!(
|
242
|
+
:api_method => @session.drive.files.patch,
|
243
|
+
:body_object => {"title" => title},
|
244
|
+
:parameters => {"fileId" => self.id})
|
245
|
+
@api_file = api_result.data
|
213
246
|
end
|
214
247
|
|
215
248
|
alias title= rename
|
249
|
+
|
250
|
+
# Creates copy of this file with the given title.
|
251
|
+
def copy(title)
|
252
|
+
copied_file = @session.drive.files.copy.request_schema.new({
|
253
|
+
"title" => title,
|
254
|
+
})
|
255
|
+
api_result = @session.execute!(
|
256
|
+
:api_method => @session.drive.files.copy,
|
257
|
+
:body_object => copied_file,
|
258
|
+
:parameters => {"fileId" => self.id})
|
259
|
+
return @session.wrap_api_file(api_result.data)
|
260
|
+
end
|
261
|
+
|
262
|
+
alias duplicate copy
|
216
263
|
|
217
264
|
# Returns GoogleDrive::Acl object for the file.
|
218
265
|
#
|
219
266
|
# With the object, you can see and modify people who can access the file.
|
220
267
|
# Modifications take effect immediately.
|
221
268
|
#
|
222
|
-
# Set <tt>params[:reload]</tt> to true to force reloading the data.
|
223
|
-
#
|
224
269
|
# e.g.
|
225
270
|
# # Dumps people who have access:
|
226
271
|
# for entry in file.acl
|
@@ -231,9 +276,9 @@ module GoogleDrive
|
|
231
276
|
# # Shares the file with new people:
|
232
277
|
# # NOTE: This sends email to the new people.
|
233
278
|
# file.acl.push(
|
234
|
-
# {:
|
279
|
+
# {:type => "user", :value => "example2@gmail.com", :role => "reader"})
|
235
280
|
# file.acl.push(
|
236
|
-
# {:
|
281
|
+
# {:type => "user", :value => "example3@gmail.com", :role => "writer"})
|
237
282
|
#
|
238
283
|
# # Changes the role of a person:
|
239
284
|
# file.acl[1].role = "writer"
|
@@ -242,15 +287,13 @@ module GoogleDrive
|
|
242
287
|
# file.acl.delete(file.acl[1])
|
243
288
|
def acl(params = {})
|
244
289
|
if !@acl || params[:reload]
|
245
|
-
@acl = Acl.new(@session, self
|
290
|
+
@acl = Acl.new(@session, self)
|
246
291
|
end
|
247
292
|
return @acl
|
248
293
|
end
|
249
294
|
|
250
295
|
def inspect
|
251
|
-
|
252
|
-
fields[:title] = self.title if @document_feed_entry
|
253
|
-
return "\#<%p %s>" % [self.class, fields.map(){ |k, v| "%s=%p" % [k, v] }.join(", ")]
|
296
|
+
return "\#<%p id=%p title=%p>" % [self.class, self.id, self.title]
|
254
297
|
end
|
255
298
|
|
256
299
|
end
|