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
@@ -20,50 +20,29 @@ module GoogleDrive
|
|
20
20
|
|
21
21
|
include(Util)
|
22
22
|
|
23
|
-
SUPPORTED_EXPORT_FORMAT = Set.new(["
|
23
|
+
SUPPORTED_EXPORT_FORMAT = Set.new(["xlsx", "csv", "pdf"])
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
@title = title
|
25
|
+
# Key of the spreadsheet.
|
26
|
+
def key
|
27
|
+
return self.id
|
29
28
|
end
|
30
|
-
|
29
|
+
|
31
30
|
# URL of worksheet-based feed of the spreadsheet.
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
#
|
36
|
-
# Set <tt>params[:reload]</tt> to true to force reloading the title.
|
37
|
-
def title(params = {})
|
38
|
-
if !@title || params[:reload]
|
39
|
-
@title = spreadsheet_feed_entry_internal(params).css("title").text
|
40
|
-
end
|
41
|
-
return @title
|
31
|
+
def worksheets_feed_url
|
32
|
+
return "https://spreadsheets.google.com/feeds/worksheets/%s/private/full" %
|
33
|
+
self.id
|
42
34
|
end
|
43
35
|
|
44
|
-
#
|
45
|
-
def
|
46
|
-
|
47
|
-
%r{^https?://spreadsheets.google.com/feeds/worksheets/(.*)/private/.*$})
|
48
|
-
raise(GoogleDrive::Error,
|
49
|
-
"Worksheets feed URL is in unknown format: #{@worksheets_feed_url}")
|
50
|
-
end
|
51
|
-
return $1
|
36
|
+
# URL of feed used in the deprecated document list feed API.
|
37
|
+
def document_feed_url
|
38
|
+
return "https://docs.google.com/feeds/documents/private/full/" + CGI.escape(self.resource_id)
|
52
39
|
end
|
53
|
-
|
40
|
+
|
54
41
|
# Spreadsheet feed URL of the spreadsheet.
|
55
42
|
def spreadsheet_feed_url
|
56
|
-
return "https://spreadsheets.google.com/feeds/spreadsheets/private/full
|
43
|
+
return "https://spreadsheets.google.com/feeds/spreadsheets/private/full/" + self.id
|
57
44
|
end
|
58
45
|
|
59
|
-
# URL which you can open the spreadsheet in a Web browser with.
|
60
|
-
#
|
61
|
-
# e.g. "http://spreadsheets.google.com/ccc?key=pz7XtlQC-PYx-jrVMJErTcg"
|
62
|
-
def human_url
|
63
|
-
# Uses Document feed because Spreadsheet feed returns wrong URL for Apps account.
|
64
|
-
return self.document_feed_entry_internal.css("link[rel='alternate']")[0]["href"]
|
65
|
-
end
|
66
|
-
|
67
46
|
# DEPRECATED: Table and Record feeds are deprecated and they will not be available after
|
68
47
|
# March 2012.
|
69
48
|
#
|
@@ -72,133 +51,18 @@ module GoogleDrive
|
|
72
51
|
warn(
|
73
52
|
"DEPRECATED: Google Spreadsheet Table and Record feeds are deprecated and they " +
|
74
53
|
"will not be available after March 2012.")
|
75
|
-
return "https://spreadsheets.google.com/feeds
|
54
|
+
return "https://spreadsheets.google.com/feeds/%s/tables" % self.id
|
76
55
|
end
|
77
56
|
|
78
|
-
# URL of feed used in document list feed API.
|
79
|
-
def document_feed_url
|
80
|
-
return "https://docs.google.com/feeds/documents/private/full/spreadsheet%3A#{self.key}"
|
81
|
-
end
|
82
|
-
|
83
|
-
# <entry> element of spreadsheet feed as Nokogiri::XML::Element.
|
84
|
-
#
|
85
|
-
# Set <tt>params[:reload]</tt> to true to force reloading the feed.
|
86
|
-
def spreadsheet_feed_entry(params = {})
|
87
|
-
warn(
|
88
|
-
"WARNING: GoogleDrive::Spreadsheet\#spreadsheet_feed_entry is deprecated and will be removed " +
|
89
|
-
"in the next version.")
|
90
|
-
return spreadsheet_feed_entry_internal(params)
|
91
|
-
end
|
92
|
-
|
93
|
-
def spreadsheet_feed_entry_internal(params = {}) #:nodoc
|
94
|
-
if !@spreadsheet_feed_entry || params[:reload]
|
95
|
-
@spreadsheet_feed_entry =
|
96
|
-
@session.request(:get, self.spreadsheet_feed_url).css("entry")[0]
|
97
|
-
end
|
98
|
-
return @spreadsheet_feed_entry
|
99
|
-
end
|
100
|
-
|
101
|
-
# <entry> element of document list feed as Nokogiri::XML::Element.
|
102
|
-
#
|
103
|
-
# Set <tt>params[:reload]</tt> to true to force reloading the feed.
|
104
|
-
def document_feed_entry(params = {})
|
105
|
-
warn(
|
106
|
-
"WARNING: GoogleDrive::Spreadsheet\#document_feed_entry is deprecated and will be removed " +
|
107
|
-
"in the next version.")
|
108
|
-
if !@document_feed_entry || params[:reload]
|
109
|
-
@document_feed_entry =
|
110
|
-
@session.request(:get, self.document_feed_url, :auth => :writely).css("entry")[0]
|
111
|
-
end
|
112
|
-
return @document_feed_entry
|
113
|
-
end
|
114
|
-
|
115
|
-
# Creates copy of this spreadsheet with the given title.
|
116
|
-
def duplicate(new_title = nil)
|
117
|
-
new_title ||= (self.title ? "Copy of " + self.title : "Untitled")
|
118
|
-
header = {"GData-Version" => "3.0", "Content-Type" => "application/atom+xml;charset=utf-8"}
|
119
|
-
xml = <<-"EOS"
|
120
|
-
<entry xmlns='http://www.w3.org/2005/Atom'>
|
121
|
-
<id>#{h(self.document_feed_url)}</id>
|
122
|
-
<title>#{h(new_title)}</title>
|
123
|
-
</entry>
|
124
|
-
EOS
|
125
|
-
doc = @session.request(
|
126
|
-
:post, DOCS_BASE_URL, :data => xml, :header => header, :auth => :writely)
|
127
|
-
ss_url = doc.css(
|
128
|
-
"link[rel='http://schemas.google.com/spreadsheets/2006#worksheetsfeed']")[0]["href"]
|
129
|
-
return Spreadsheet.new(@session, ss_url, new_title)
|
130
|
-
end
|
131
|
-
|
132
|
-
# Exports the spreadsheet in +format+ and returns it as String.
|
133
|
-
#
|
134
|
-
# +format+ can be either "csv" or "pdf".
|
135
|
-
# In format such as "csv", only the worksheet specified with +worksheet_index+ is
|
136
|
-
# exported.
|
137
|
-
def export_as_string(format, worksheet_index = nil)
|
138
|
-
if ["xls", "ods", "tsv", "html"].include?(format)
|
139
|
-
warn("WARNING: Export with format '%s' is deprecated, and will not work in the next version." % format)
|
140
|
-
end
|
141
|
-
gid_param = worksheet_index ? "&gid=#{worksheet_index}" : ""
|
142
|
-
format_string = "&format=#{format}"
|
143
|
-
if self.human_url.match("edit")
|
144
|
-
url = self.human_url.gsub(/edit/, "export") + gid_param + format_string
|
145
|
-
else
|
146
|
-
url =
|
147
|
-
"https://spreadsheets.google.com/feeds/download/spreadsheets/Export" +
|
148
|
-
"?key=#{key}&exportFormat=#{format}#{gid_param}"
|
149
|
-
end
|
150
|
-
return @session.request(:get, url, :response_type => :raw)
|
151
|
-
end
|
152
|
-
|
153
|
-
# Exports the spreadsheet in +format+ as a local file.
|
154
|
-
#
|
155
|
-
# +format+ can be either "xls", "csv", "pdf", "ods", "tsv" or "html".
|
156
|
-
# If +format+ is nil, it is guessed from the file name.
|
157
|
-
# In format such as "csv", only the worksheet specified with +worksheet_index+ is exported.
|
158
|
-
#
|
159
|
-
# e.g.
|
160
|
-
# spreadsheet.export_as_file("hoge.ods")
|
161
|
-
# spreadsheet.export_as_file("hoge.csv", nil, 0)
|
162
|
-
def export_as_file(local_path, format = nil, worksheet_index = nil)
|
163
|
-
if !format
|
164
|
-
format = ::File.extname(local_path).gsub(/^\./, "")
|
165
|
-
if !SUPPORTED_EXPORT_FORMAT.include?(format)
|
166
|
-
raise(ArgumentError,
|
167
|
-
("Cannot guess format from the file name: %s\n" +
|
168
|
-
"Specify format argument explicitly.") %
|
169
|
-
local_path)
|
170
|
-
end
|
171
|
-
end
|
172
|
-
open(local_path, "wb") do |f|
|
173
|
-
f.write(export_as_string(format, worksheet_index))
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
def download_to_io(io, params = {})
|
178
|
-
# General downloading API doesn't work for spreadsheets because it requires a different
|
179
|
-
# authorization token, and it has a bug that it downloads PDF when text/html is
|
180
|
-
# requested.
|
181
|
-
raise(NotImplementedError,
|
182
|
-
"Use export_as_file or export_as_string instead for GoogleDrive::Spreadsheet.")
|
183
|
-
end
|
184
|
-
|
185
57
|
# Returns worksheets of the spreadsheet as array of GoogleDrive::Worksheet.
|
186
58
|
def worksheets
|
187
|
-
doc = @session.request(:get,
|
59
|
+
doc = @session.request(:get, self.worksheets_feed_url)
|
188
60
|
if doc.root.name != "feed"
|
189
61
|
raise(GoogleDrive::Error,
|
190
62
|
"%s doesn't look like a worksheets feed URL because its root is not <feed>." %
|
191
|
-
|
63
|
+
self.worksheets_feed_url)
|
192
64
|
end
|
193
|
-
|
194
|
-
doc.css("entry").each() do |entry|
|
195
|
-
title = entry.css("title").text
|
196
|
-
updated = Time.parse(entry.css("updated").text)
|
197
|
-
url = entry.css(
|
198
|
-
"link[rel='http://schemas.google.com/spreadsheets/2006#cellsfeed']")[0]["href"]
|
199
|
-
result.push(Worksheet.new(@session, self, url, title, updated))
|
200
|
-
end
|
201
|
-
return result.freeze()
|
65
|
+
return doc.css("entry").map(){ |e| Worksheet.new(@session, self, e) }.freeze
|
202
66
|
end
|
203
67
|
|
204
68
|
# Returns a GoogleDrive::Worksheet with the given title in the spreadsheet.
|
@@ -219,10 +83,8 @@ module GoogleDrive
|
|
219
83
|
<gs:colCount>#{h(max_cols)}</gs:colCount>
|
220
84
|
</entry>
|
221
85
|
EOS
|
222
|
-
doc = @session.request(:post,
|
223
|
-
|
224
|
-
"link[rel='http://schemas.google.com/spreadsheets/2006#cellsfeed']")[0]["href"]
|
225
|
-
return Worksheet.new(@session, self, url, title)
|
86
|
+
doc = @session.request(:post, self.worksheets_feed_url, :data => xml)
|
87
|
+
return Worksheet.new(@session, self, doc.root)
|
226
88
|
end
|
227
89
|
|
228
90
|
# DEPRECATED: Table and Record feeds are deprecated and they will not be available after
|
@@ -237,12 +99,6 @@ module GoogleDrive
|
|
237
99
|
return doc.css("entry").map(){ |e| Table.new(@session, e) }.freeze()
|
238
100
|
end
|
239
101
|
|
240
|
-
def inspect
|
241
|
-
fields = {:worksheets_feed_url => self.worksheets_feed_url}
|
242
|
-
fields[:title] = @title if @title
|
243
|
-
return "\#<%p %s>" % [self.class, fields.map(){ |k, v| "%s=%p" % [k, v] }.join(", ")]
|
244
|
-
end
|
245
|
-
|
246
102
|
end
|
247
103
|
|
248
104
|
end
|
data/lib/google_drive/util.rb
CHANGED
@@ -3,14 +3,13 @@
|
|
3
3
|
|
4
4
|
require "cgi"
|
5
5
|
|
6
|
+
require "google/api_client"
|
7
|
+
|
6
8
|
|
7
9
|
module GoogleDrive
|
8
10
|
|
9
11
|
module Util #:nodoc:
|
10
12
|
|
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"
|
13
|
-
|
14
13
|
EXT_TO_CONTENT_TYPE = {
|
15
14
|
".csv" =>"text/csv",
|
16
15
|
".tsv" =>"text/tab-separated-values",
|
@@ -37,11 +36,6 @@ module GoogleDrive
|
|
37
36
|
module_function
|
38
37
|
|
39
38
|
def encode_query(params)
|
40
|
-
for k, v in params
|
41
|
-
if ["ocr", "targetLanguage", "sourceLanguage"].include?(k.to_s())
|
42
|
-
warn("WARNING: Parameter '%s' is deprecated, and will not work in the next version." % k)
|
43
|
-
end
|
44
|
-
end
|
45
39
|
return params.map(){ |k, v| CGI.escape(k.to_s()) + "=" + CGI.escape(v.to_s()) }.join("&")
|
46
40
|
end
|
47
41
|
|
@@ -54,20 +48,135 @@ module GoogleDrive
|
|
54
48
|
(result_query.empty? ? "" : "?#{result_query}")
|
55
49
|
end
|
56
50
|
|
57
|
-
# Returns a URL with added version parameter ("?v=3") if needed.
|
58
|
-
def to_v3_url(url)
|
59
|
-
if url =~ %r{docs.google.com/feeds/default/private/} && !(url =~ /[?&]v=3/)
|
60
|
-
return concat_url(url, "?v=3")
|
61
|
-
else
|
62
|
-
return url
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
51
|
def h(str)
|
67
52
|
# Should also escape "\n" to keep it in cell contents.
|
68
53
|
return CGI.escapeHTML(str.to_s()).gsub(/\n/, '
')
|
69
54
|
end
|
70
55
|
|
56
|
+
def construct_query(arg)
|
57
|
+
|
58
|
+
case arg
|
59
|
+
|
60
|
+
when String
|
61
|
+
return arg
|
62
|
+
|
63
|
+
when Array
|
64
|
+
if arg[0].scan(/\?/).size != arg.size - 1
|
65
|
+
raise(
|
66
|
+
ArgumentError,
|
67
|
+
"The number of placeholders doesn't match the number of arguments: %p" % [arg])
|
68
|
+
end
|
69
|
+
i = 1
|
70
|
+
return arg[0].gsub(/\?/) do
|
71
|
+
v = arg[i]
|
72
|
+
i += 1
|
73
|
+
case v
|
74
|
+
when String
|
75
|
+
"'%s'" % v.gsub(/['\\]/){ "\\" + $& }
|
76
|
+
when Time
|
77
|
+
"'%s'" % v.iso8601
|
78
|
+
when TrueClass
|
79
|
+
"true"
|
80
|
+
when FalseClass
|
81
|
+
"false"
|
82
|
+
else
|
83
|
+
raise(ArgumentError, "Expected String, Time, true or false, but got %p" % [v])
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
else
|
88
|
+
raise(ArgumentError, "Expected String or Array, but got %p" % [arg])
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
def construct_and_query(args)
|
95
|
+
return args.select(){ |a| a }.map(){ |a| "(%s)" % construct_query(a) }.join(" and ")
|
96
|
+
end
|
97
|
+
|
98
|
+
def convert_params(params)
|
99
|
+
str_params = {}
|
100
|
+
for k, v in params
|
101
|
+
str_params[k.to_s()] = v
|
102
|
+
end
|
103
|
+
old_terms = []
|
104
|
+
new_params = {}
|
105
|
+
for k, v in str_params
|
106
|
+
case k
|
107
|
+
when "q"
|
108
|
+
new_params["q"] = construct_query(v)
|
109
|
+
# Parameters in the old API.
|
110
|
+
when "title"
|
111
|
+
if str_params["title-exact"].to_s() == "true"
|
112
|
+
old_terms.push(["title = ?", v])
|
113
|
+
else
|
114
|
+
old_terms.push(["title contains ?", v])
|
115
|
+
end
|
116
|
+
when "title-exact"
|
117
|
+
# Skips it. It is handled above.
|
118
|
+
when "opened-min"
|
119
|
+
old_terms.push(["lastViewedByMeDate >= ?", v])
|
120
|
+
when "opened-max"
|
121
|
+
old_terms.push(["lastViewedByMeDate <= ?", v])
|
122
|
+
when "edited-min"
|
123
|
+
old_terms.push(["modifiedDate >= ?", v])
|
124
|
+
when "edited-max"
|
125
|
+
old_terms.push(["modifiedDate <= ?", v])
|
126
|
+
when "owner"
|
127
|
+
old_terms.push(["? in owners", v])
|
128
|
+
when "writer"
|
129
|
+
old_terms.push(["? in writers", v])
|
130
|
+
when "reader"
|
131
|
+
old_terms.push(["? in readers", v])
|
132
|
+
when "showfolders"
|
133
|
+
if v.to_s() == "false"
|
134
|
+
old_terms.push("mimeType != 'application/vnd.google-apps.folder'")
|
135
|
+
end
|
136
|
+
when "showdeleted"
|
137
|
+
if v.to_s() == "false"
|
138
|
+
old_terms.push("trashed = false")
|
139
|
+
end
|
140
|
+
when "ocr", "targetLanguage", "sourceLanguage"
|
141
|
+
raise(ArgumentError, "'%s' parameter is no longer supported." % k)
|
142
|
+
else
|
143
|
+
new_params[k] = v
|
144
|
+
end
|
145
|
+
end
|
146
|
+
if !old_terms.empty?
|
147
|
+
if new_params.has_key?("q")
|
148
|
+
raise(ArgumentError, "Cannot specify both 'q' parameter and old query parameters.")
|
149
|
+
else
|
150
|
+
new_params["q"] = construct_and_query(old_terms)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
return new_params
|
154
|
+
end
|
155
|
+
|
156
|
+
def singleton_class(obj)
|
157
|
+
class << obj
|
158
|
+
return self
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def delegate_api_methods(obj, api_obj, exceptions = [])
|
163
|
+
sc = singleton_class(obj)
|
164
|
+
names = api_obj.class.keys.keys - exceptions
|
165
|
+
names.each() do |name|
|
166
|
+
sc.__send__(:define_method, name) do
|
167
|
+
api_obj.__send__(name)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def new_upload_io(path_or_io, params)
|
173
|
+
content_type =
|
174
|
+
params[:content_type] ||
|
175
|
+
(params[:file_name] ? EXT_TO_CONTENT_TYPE[::File.extname(params[:file_name]).downcase] : nil) ||
|
176
|
+
"application/octet-stream"
|
177
|
+
return Google::APIClient::UploadIO.new(path_or_io, content_type)
|
178
|
+
end
|
179
|
+
|
71
180
|
end
|
72
181
|
|
73
182
|
end
|