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.
Files changed (34) hide show
  1. checksums.yaml +7 -7
  2. data/README.rdoc +27 -10
  3. data/lib/google_drive/acl.rb +40 -58
  4. data/lib/google_drive/acl_entry.rb +76 -56
  5. data/lib/google_drive/api_client_fetcher.rb +49 -0
  6. data/lib/google_drive/collection.rb +69 -71
  7. data/lib/google_drive/file.rb +171 -128
  8. data/lib/google_drive/session.rb +234 -268
  9. data/lib/google_drive/spreadsheet.rb +19 -163
  10. data/lib/google_drive/util.rb +126 -17
  11. data/lib/google_drive/worksheet.rb +108 -80
  12. data/lib/google_drive.rb +63 -57
  13. data/lib/google_drive_v1/acl.rb +115 -0
  14. data/lib/google_drive_v1/acl_entry.rb +100 -0
  15. data/lib/google_drive_v1/api_client_fetcher.rb +47 -0
  16. data/lib/google_drive_v1/authentication_error.rb +14 -0
  17. data/lib/{google_drive → google_drive_v1}/basic_fetcher.rb +1 -1
  18. data/lib/{google_drive → google_drive_v1}/client_login_fetcher.rb +2 -2
  19. data/lib/google_drive_v1/collection.rb +167 -0
  20. data/lib/google_drive_v1/error.rb +12 -0
  21. data/lib/google_drive_v1/file.rb +258 -0
  22. data/lib/google_drive_v1/list.rb +119 -0
  23. data/lib/google_drive_v1/list_row.rb +88 -0
  24. data/lib/{google_drive → google_drive_v1}/oauth1_fetcher.rb +1 -1
  25. data/lib/{google_drive → google_drive_v1}/oauth2_fetcher.rb +2 -2
  26. data/lib/google_drive_v1/record.rb +31 -0
  27. data/lib/google_drive_v1/session.rb +522 -0
  28. data/lib/google_drive_v1/spreadsheet.rb +248 -0
  29. data/lib/google_drive_v1/table.rb +60 -0
  30. data/lib/google_drive_v1/util.rb +73 -0
  31. data/lib/google_drive_v1/worksheet.rb +498 -0
  32. data/lib/google_drive_v1.rb +148 -0
  33. metadata +112 -77
  34. 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(["xls", "csv", "pdf", "ods", "tsv", "html"])
23
+ SUPPORTED_EXPORT_FORMAT = Set.new(["xlsx", "csv", "pdf"])
24
24
 
25
- def initialize(session, worksheets_feed_url, title = nil) #:nodoc:
26
- super(session, nil)
27
- @worksheets_feed_url = worksheets_feed_url
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
- attr_reader(:worksheets_feed_url)
33
-
34
- # Title of the spreadsheet.
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
- # Key of the spreadsheet.
45
- def key
46
- if !(@worksheets_feed_url =~
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/#{self.key}"
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/#{self.key}/tables"
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, @worksheets_feed_url)
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
- @worksheets_feed_url)
63
+ self.worksheets_feed_url)
192
64
  end
193
- result = []
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, @worksheets_feed_url, :data => xml)
223
- url = doc.css(
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
@@ -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/, '&#x0a;')
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