google_drive 1.0.6 → 2.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.
@@ -1,77 +1,74 @@
1
1
  # Author: Hiroshi Ichikawa <http://gimite.net/>
2
2
  # The license of this source is "New BSD Licence"
3
3
 
4
- require "time"
5
-
6
- require "google_drive/util"
7
- require "google_drive/error"
8
- require "google_drive/worksheet"
9
- require "google_drive/acl"
10
- require "google_drive/file"
4
+ require 'time'
11
5
 
6
+ require 'google_drive/util'
7
+ require 'google_drive/error'
8
+ require 'google_drive/worksheet'
9
+ require 'google_drive/acl'
10
+ require 'google_drive/file'
12
11
 
13
12
  module GoogleDrive
14
-
15
- # A spreadsheet.
16
- #
17
- # Use methods in GoogleDrive::Session to get GoogleDrive::Spreadsheet object.
18
- class Spreadsheet < GoogleDrive::File
13
+ # A spreadsheet.
14
+ #
15
+ # Use methods in GoogleDrive::Session to get GoogleDrive::Spreadsheet object.
16
+ class Spreadsheet < GoogleDrive::File
17
+ include(Util)
19
18
 
20
- include(Util)
21
-
22
- SUPPORTED_EXPORT_FORMAT = Set.new(["xlsx", "csv", "pdf"])
19
+ SUPPORTED_EXPORT_FORMAT = Set.new(%w(xlsx csv pdf))
20
+
21
+ # Key of the spreadsheet.
22
+ def key
23
+ id
24
+ end
23
25
 
24
- # Key of the spreadsheet.
25
- def key
26
- return self.id
27
- end
28
-
29
- # URL of worksheet-based feed of the spreadsheet.
30
- def worksheets_feed_url
31
- return "https://spreadsheets.google.com/feeds/worksheets/%s/private/full" %
32
- self.id
33
- end
26
+ # URL of worksheet-based feed of the spreadsheet.
27
+ def worksheets_feed_url
28
+ 'https://spreadsheets.google.com/feeds/worksheets/%s/private/full' %
29
+ id
30
+ end
34
31
 
35
- # URL of feed used in the deprecated document list feed API.
36
- def document_feed_url
37
- return "https://docs.google.com/feeds/documents/private/full/" + CGI.escape(self.resource_id)
38
- end
32
+ # URL of feed used in the deprecated document list feed API.
33
+ def document_feed_url
34
+ 'https://docs.google.com/feeds/documents/private/full/' + CGI.escape(resource_id)
35
+ end
39
36
 
40
- # Spreadsheet feed URL of the spreadsheet.
41
- def spreadsheet_feed_url
42
- return "https://spreadsheets.google.com/feeds/spreadsheets/private/full/" + self.id
43
- end
44
-
45
- # Returns worksheets of the spreadsheet as array of GoogleDrive::Worksheet.
46
- def worksheets
47
- doc = @session.request(:get, self.worksheets_feed_url)
48
- if doc.root.name != "feed"
49
- raise(GoogleDrive::Error,
50
- "%s doesn't look like a worksheets feed URL because its root is not <feed>." %
51
- self.worksheets_feed_url)
52
- end
53
- return doc.css("entry").map(){ |e| Worksheet.new(@session, self, e) }.freeze
54
- end
55
-
56
- # Returns a GoogleDrive::Worksheet with the given title in the spreadsheet.
57
- #
58
- # Returns nil if not found. Returns the first one when multiple worksheets with the
59
- # title are found.
60
- def worksheet_by_title(title)
61
- return self.worksheets.find(){ |ws| ws.title == title }
62
- end
37
+ # Spreadsheet feed URL of the spreadsheet.
38
+ def spreadsheet_feed_url
39
+ 'https://spreadsheets.google.com/feeds/spreadsheets/private/full/' + id
40
+ end
63
41
 
64
- # Returns a GoogleDrive::Worksheet with the given gid.
65
- #
66
- # Returns nil if not found.
67
- def worksheet_by_gid(gid)
68
- gid = gid.to_s()
69
- return self.worksheets.find(){ |ws| ws.gid == gid }
70
- end
42
+ # Returns worksheets of the spreadsheet as array of GoogleDrive::Worksheet.
43
+ def worksheets
44
+ doc = @session.request(:get, worksheets_feed_url)
45
+ if doc.root.name != 'feed'
46
+ fail(GoogleDrive::Error,
47
+ "%s doesn't look like a worksheets feed URL because its root is not <feed>." %
48
+ worksheets_feed_url)
49
+ end
50
+ doc.css('entry').map { |e| Worksheet.new(@session, self, e) }.freeze
51
+ end
71
52
 
72
- # Adds a new worksheet to the spreadsheet. Returns added GoogleDrive::Worksheet.
73
- def add_worksheet(title, max_rows = 100, max_cols = 20)
74
- xml = <<-"EOS"
53
+ # Returns a GoogleDrive::Worksheet with the given title in the spreadsheet.
54
+ #
55
+ # Returns nil if not found. Returns the first one when multiple worksheets with the
56
+ # title are found.
57
+ def worksheet_by_title(title)
58
+ worksheets.find { |ws| ws.title == title }
59
+ end
60
+
61
+ # Returns a GoogleDrive::Worksheet with the given gid.
62
+ #
63
+ # Returns nil if not found.
64
+ def worksheet_by_gid(gid)
65
+ gid = gid.to_s
66
+ worksheets.find { |ws| ws.gid == gid }
67
+ end
68
+
69
+ # Adds a new worksheet to the spreadsheet. Returns added GoogleDrive::Worksheet.
70
+ def add_worksheet(title, max_rows = 100, max_cols = 20)
71
+ xml = <<-"EOS"
75
72
  <entry xmlns='http://www.w3.org/2005/Atom'
76
73
  xmlns:gs='http://schemas.google.com/spreadsheets/2006'>
77
74
  <title>#{h(title)}</title>
@@ -79,10 +76,8 @@ module GoogleDrive
79
76
  <gs:colCount>#{h(max_cols)}</gs:colCount>
80
77
  </entry>
81
78
  EOS
82
- doc = @session.request(:post, self.worksheets_feed_url, :data => xml)
83
- return Worksheet.new(@session, self, doc.root)
84
- end
85
-
79
+ doc = @session.request(:post, worksheets_feed_url, data: xml)
80
+ Worksheet.new(@session, self, doc.root)
86
81
  end
87
-
82
+ end
88
83
  end
@@ -1,182 +1,222 @@
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
+ require 'cgi'
5
5
 
6
- require "google/api_client"
6
+ module GoogleDrive
7
+ module Util #:nodoc:
8
+ EXT_TO_CONTENT_TYPE = {
9
+ '.csv' => 'text/csv',
10
+ '.tsv' => 'text/tab-separated-values',
11
+ '.tab' => 'text/tab-separated-values',
12
+ '.doc' => 'application/msword',
13
+ '.docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
14
+ '.ods' => 'application/x-vnd.oasis.opendocument.spreadsheet',
15
+ '.odt' => 'application/vnd.oasis.opendocument.text',
16
+ '.rtf' => 'application/rtf',
17
+ '.sxw' => 'application/vnd.sun.xml.writer',
18
+ '.txt' => 'text/plain',
19
+ '.xls' => 'application/vnd.ms-excel',
20
+ '.xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
21
+ '.pdf' => 'application/pdf',
22
+ '.png' => 'image/png',
23
+ '.ppt' => 'application/vnd.ms-powerpoint',
24
+ '.pps' => 'application/vnd.ms-powerpoint',
25
+ '.htm' => 'text/html',
26
+ '.html' => 'text/html',
27
+ '.zip' => 'application/zip',
28
+ '.swf' => 'application/x-shockwave-flash'
29
+ }
30
+
31
+ IMPORTABLE_CONTENT_TYPE_MAP = {
32
+ 'application/x-vnd.oasis.opendocument.presentation' => 'application/vnd.google-apps.presentation',
33
+ 'text/tab-separated-values' => 'application/vnd.google-apps.spreadsheet',
34
+ 'image/jpeg' => 'application/vnd.google-apps.document',
35
+ 'image/bmp' => 'application/vnd.google-apps.document',
36
+ 'image/gif' => 'application/vnd.google-apps.document',
37
+ 'application/vnd.ms-excel.sheet.macroenabled.12' => 'application/vnd.google-apps.spreadsheet',
38
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' => 'application/vnd.google-apps.document',
39
+ 'application/vnd.ms-powerpoint.presentation.macroenabled.12' => 'application/vnd.google-apps.presentation',
40
+ 'application/vnd.ms-word.template.macroenabled.12' => 'application/vnd.google-apps.document',
41
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'application/vnd.google-apps.document',
42
+ 'image/pjpeg' => 'application/vnd.google-apps.document',
43
+ 'application/vnd.google-apps.script+text/plain' => 'application/vnd.google-apps.script',
44
+ 'application/vnd.ms-excel' => 'application/vnd.google-apps.spreadsheet',
45
+ 'application/vnd.sun.xml.writer' => 'application/vnd.google-apps.document',
46
+ 'application/vnd.ms-word.document.macroenabled.12' => 'application/vnd.google-apps.document',
47
+ 'application/vnd.ms-powerpoint.slideshow.macroenabled.12' => 'application/vnd.google-apps.presentation',
48
+ 'text/rtf' => 'application/vnd.google-apps.document',
49
+ 'text/plain' => 'application/vnd.google-apps.document',
50
+ 'application/vnd.oasis.opendocument.spreadsheet' => 'application/vnd.google-apps.spreadsheet',
51
+ 'application/x-vnd.oasis.opendocument.spreadsheet' => 'application/vnd.google-apps.spreadsheet',
52
+ 'image/png' => 'application/vnd.google-apps.document',
53
+ 'application/x-vnd.oasis.opendocument.text' => 'application/vnd.google-apps.document',
54
+ 'application/msword' => 'application/vnd.google-apps.document',
55
+ 'application/pdf' => 'application/vnd.google-apps.document',
56
+ 'application/json' => 'application/vnd.google-apps.script',
57
+ 'application/x-msmetafile' => 'application/vnd.google-apps.drawing',
58
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' => 'application/vnd.google-apps.spreadsheet',
59
+ 'application/vnd.ms-powerpoint' => 'application/vnd.google-apps.presentation',
60
+ 'application/vnd.ms-excel.template.macroenabled.12' => 'application/vnd.google-apps.spreadsheet',
61
+ 'image/x-bmp' => 'application/vnd.google-apps.document',
62
+ 'application/rtf' => 'application/vnd.google-apps.document',
63
+ 'application/vnd.openxmlformats-officedocument.presentationml.template' => 'application/vnd.google-apps.presentation',
64
+ 'image/x-png' => 'application/vnd.google-apps.document',
65
+ 'text/html' => 'application/vnd.google-apps.document',
66
+ 'application/vnd.oasis.opendocument.text' => 'application/vnd.google-apps.document',
67
+ 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'application/vnd.google-apps.presentation',
68
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'application/vnd.google-apps.spreadsheet',
69
+ 'application/vnd.google-apps.script+json' => 'application/vnd.google-apps.script',
70
+ 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => 'application/vnd.google-apps.presentation',
71
+ 'application/vnd.ms-powerpoint.template.macroenabled.12' => 'application/vnd.google-apps.presentation',
72
+ 'text/csv' => 'application/vnd.google-apps.spreadsheet',
73
+ 'application/vnd.oasis.opendocument.presentation' => 'application/vnd.google-apps.presentation',
74
+ 'image/jpg' => 'application/vnd.google-apps.document',
75
+ 'text/richtext' => 'application/vnd.google-apps.document',
76
+ }
77
+
78
+ module_function
79
+
80
+ def encode_query(params)
81
+ params.map { |k, v| CGI.escape(k.to_s) + '=' + CGI.escape(v.to_s) }.join('&')
82
+ end
7
83
 
84
+ def concat_url(url, piece)
85
+ (url_base, url_query) = url.split(/\?/, 2)
86
+ (piece_base, piece_query) = piece.split(/\?/, 2)
87
+ result_query = [url_query, piece_query].select { |s| s && !s.empty? }.join('&')
88
+ (url_base || '') +
89
+ (piece_base || '') +
90
+ (result_query.empty? ? '' : "?#{result_query}")
91
+ end
8
92
 
9
- module GoogleDrive
10
-
11
- module Util #:nodoc:
12
-
13
- EXT_TO_CONTENT_TYPE = {
14
- ".csv" =>"text/csv",
15
- ".tsv" =>"text/tab-separated-values",
16
- ".tab" =>"text/tab-separated-values",
17
- ".doc" =>"application/msword",
18
- ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
19
- ".ods" =>"application/x-vnd.oasis.opendocument.spreadsheet",
20
- ".odt" =>"application/vnd.oasis.opendocument.text",
21
- ".rtf" =>"application/rtf",
22
- ".sxw" =>"application/vnd.sun.xml.writer",
23
- ".txt" =>"text/plain",
24
- ".xls" =>"application/vnd.ms-excel",
25
- ".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
26
- ".pdf" =>"application/pdf",
27
- ".png" =>"image/png",
28
- ".ppt" =>"application/vnd.ms-powerpoint",
29
- ".pps" =>"application/vnd.ms-powerpoint",
30
- ".htm" =>"text/html",
31
- ".html" =>"text/html",
32
- ".zip" =>"application/zip",
33
- ".swf" =>"application/x-shockwave-flash",
34
- }
35
-
36
- module_function
37
-
38
- def encode_query(params)
39
- return params.map(){ |k, v| CGI.escape(k.to_s()) + "=" + CGI.escape(v.to_s()) }.join("&")
40
- end
41
-
42
- def concat_url(url, piece)
43
- (url_base, url_query) = url.split(/\?/, 2)
44
- (piece_base, piece_query) = piece.split(/\?/, 2)
45
- result_query = [url_query, piece_query].select(){ |s| s && !s.empty? }.join("&")
46
- return (url_base || "") +
47
- (piece_base || "") +
48
- (result_query.empty? ? "" : "?#{result_query}")
49
- end
93
+ def h(str)
94
+ # Should also escape "\n" to keep it in cell contents.
95
+ CGI.escapeHTML(str.to_s).gsub(/\n/, '&#x0a;')
96
+ end
50
97
 
51
- def h(str)
52
- # Should also escape "\n" to keep it in cell contents.
53
- return CGI.escapeHTML(str.to_s()).gsub(/\n/, '&#x0a;')
54
- end
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])
98
+ def construct_query(arg)
99
+ case arg
89
100
 
90
- end
101
+ when String
102
+ return arg
91
103
 
104
+ when Array
105
+ if arg[0].scan(/\?/).size != arg.size - 1
106
+ fail(
107
+ ArgumentError,
108
+ "The number of placeholders doesn't match the number of arguments: %p" % [arg])
92
109
  end
93
-
94
- def construct_and_query(args)
95
- return args.select(){ |a| a }.map(){ |a| "(%s)" % construct_query(a) }.join(" and ")
110
+ i = 1
111
+ return arg[0].gsub(/\?/) do
112
+ v = arg[i]
113
+ i += 1
114
+ case v
115
+ when String
116
+ "'%s'" % v.gsub(/['\\]/) { '\\' + $& }
117
+ when Time
118
+ "'%s'" % v.iso8601
119
+ when TrueClass
120
+ 'true'
121
+ when FalseClass
122
+ 'false'
123
+ else
124
+ fail(ArgumentError, 'Expected String, Time, true or false, but got %p' % [v])
125
+ end
96
126
  end
97
127
 
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
128
+ else
129
+ fail(ArgumentError, 'Expected String or Array, but got %p' % [arg])
130
+
131
+ end
132
+ end
133
+
134
+ def construct_and_query(args)
135
+ args.select { |a| a }.map { |a| '(%s)' % construct_query(a) }.join(' and ')
136
+ end
137
+
138
+ def convert_params(params)
139
+ str_params = {}
140
+ params.each do |k, v|
141
+ str_params[k.to_s] = v
142
+ end
143
+
144
+ old_terms = []
145
+ new_params = {}
146
+ str_params.each do |k, v|
147
+ case k
148
+ when 'q'
149
+ new_params[:q] = construct_query(v)
150
+
151
+ # Parameters in the old API.
152
+ when 'title'
153
+ if str_params['title-exact'].to_s == 'true'
154
+ old_terms.push(['name = ?', v])
155
+ else
156
+ old_terms.push(['name contains ?', v])
145
157
  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
158
+ when 'title-exact'
159
+ # Skips it. It is handled above.
160
+ when 'opened-min'
161
+ old_terms.push(['lastViewedByMeDate >= ?', v])
162
+ when 'opened-max'
163
+ old_terms.push(['lastViewedByMeDate <= ?', v])
164
+ when 'edited-min'
165
+ old_terms.push(['modifiedDate >= ?', v])
166
+ when 'edited-max'
167
+ old_terms.push(['modifiedDate <= ?', v])
168
+ when 'owner'
169
+ old_terms.push(['? in owners', v])
170
+ when 'writer'
171
+ old_terms.push(['? in writers', v])
172
+ when 'reader'
173
+ old_terms.push(['? in readers', v])
174
+ when 'showfolders'
175
+ if v.to_s == 'false'
176
+ old_terms.push("mimeType != 'application/vnd.google-apps.folder'")
152
177
  end
153
- return new_params
178
+ when 'showdeleted'
179
+ old_terms.push('trashed = false') if v.to_s == 'false'
180
+ when 'ocr', 'targetLanguage', 'sourceLanguage'
181
+ fail(ArgumentError, "'%s' parameter is no longer supported." % k)
182
+ else
183
+ # e.g., 'pageToken' -> :page_token
184
+ new_key = k.
185
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
186
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
187
+ downcase.
188
+ intern
189
+ new_params[new_key] = v
154
190
  end
191
+ end
155
192
 
156
- def get_singleton_class(obj)
157
- class << obj
158
- return self
159
- end
193
+ unless old_terms.empty?
194
+ if new_params.key?(:q)
195
+ fail(ArgumentError, "Cannot specify both 'q' parameter and old query parameters.")
196
+ else
197
+ new_params[:q] = construct_and_query(old_terms)
160
198
  end
199
+ end
161
200
 
162
- def delegate_api_methods(obj, api_obj, exceptions = [])
163
- sc = get_singleton_class(obj)
164
- names = api_obj.class.keys.keys - exceptions.map(&:to_s)
165
- names.each() do |name|
166
- sc.__send__(:define_method, name) do
167
- api_obj.__send__(name)
168
- end
169
- end
170
- end
201
+ new_params
202
+ end
171
203
 
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)
204
+ def get_singleton_class(obj)
205
+ class << obj
206
+ return self
207
+ end
208
+ end
209
+
210
+ def delegate_api_methods(obj, api_obj, exceptions = [])
211
+ sc = get_singleton_class(obj)
212
+ names = api_obj.public_methods(false) - exceptions
213
+ names.each do |name|
214
+ if !(name.to_s =~ /=$/)
215
+ sc.__send__(:define_method, name) do
216
+ api_obj.__send__(name)
217
+ end
178
218
  end
179
-
219
+ end
180
220
  end
181
-
221
+ end
182
222
  end