google_drive 0.3.11 → 1.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
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