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
@@ -0,0 +1,248 @@
1
+ # Author: Hiroshi Ichikawa <http://gimite.net/>
2
+ # The license of this source is "New BSD Licence"
3
+
4
+ require "time"
5
+
6
+ require "google_drive_v1/util"
7
+ require "google_drive_v1/error"
8
+ require "google_drive_v1/worksheet"
9
+ require "google_drive_v1/table"
10
+ require "google_drive_v1/acl"
11
+ require "google_drive_v1/file"
12
+
13
+
14
+ module GoogleDriveV1
15
+
16
+ # A spreadsheet.
17
+ #
18
+ # Use methods in GoogleDriveV1::Session to get GoogleDriveV1::Spreadsheet object.
19
+ class Spreadsheet < GoogleDriveV1::File
20
+
21
+ include(Util)
22
+
23
+ SUPPORTED_EXPORT_FORMAT = Set.new(["xls", "csv", "pdf", "ods", "tsv", "html"])
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
29
+ end
30
+
31
+ # 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
42
+ end
43
+
44
+ # Key of the spreadsheet.
45
+ def key
46
+ if !(@worksheets_feed_url =~
47
+ %r{^https?://spreadsheets.google.com/feeds/worksheets/(.*)/private/.*$})
48
+ raise(GoogleDriveV1::Error,
49
+ "Worksheets feed URL is in unknown format: #{@worksheets_feed_url}")
50
+ end
51
+ return $1
52
+ end
53
+
54
+ # Spreadsheet feed URL of the spreadsheet.
55
+ def spreadsheet_feed_url
56
+ return "https://spreadsheets.google.com/feeds/spreadsheets/private/full/#{self.key}"
57
+ end
58
+
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
+ # DEPRECATED: Table and Record feeds are deprecated and they will not be available after
68
+ # March 2012.
69
+ #
70
+ # Tables feed URL of the spreadsheet.
71
+ def tables_feed_url
72
+ warn(
73
+ "DEPRECATED: Google Spreadsheet Table and Record feeds are deprecated and they " +
74
+ "will not be available after March 2012.")
75
+ return "https://spreadsheets.google.com/feeds/#{self.key}/tables"
76
+ end
77
+
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: GoogleDriveV1::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: GoogleDriveV1::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 GoogleDriveV1::Spreadsheet.")
183
+ end
184
+
185
+ # Returns worksheets of the spreadsheet as array of GoogleDriveV1::Worksheet.
186
+ def worksheets
187
+ doc = @session.request(:get, @worksheets_feed_url)
188
+ if doc.root.name != "feed"
189
+ raise(GoogleDriveV1::Error,
190
+ "%s doesn't look like a worksheets feed URL because its root is not <feed>." %
191
+ @worksheets_feed_url)
192
+ 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()
202
+ end
203
+
204
+ # Returns a GoogleDriveV1::Worksheet with the given title in the spreadsheet.
205
+ #
206
+ # Returns nil if not found. Returns the first one when multiple worksheets with the
207
+ # title are found.
208
+ def worksheet_by_title(title)
209
+ return self.worksheets.find(){ |ws| ws.title == title }
210
+ end
211
+
212
+ # Adds a new worksheet to the spreadsheet. Returns added GoogleDriveV1::Worksheet.
213
+ def add_worksheet(title, max_rows = 100, max_cols = 20)
214
+ xml = <<-"EOS"
215
+ <entry xmlns='http://www.w3.org/2005/Atom'
216
+ xmlns:gs='http://schemas.google.com/spreadsheets/2006'>
217
+ <title>#{h(title)}</title>
218
+ <gs:rowCount>#{h(max_rows)}</gs:rowCount>
219
+ <gs:colCount>#{h(max_cols)}</gs:colCount>
220
+ </entry>
221
+ 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)
226
+ end
227
+
228
+ # DEPRECATED: Table and Record feeds are deprecated and they will not be available after
229
+ # March 2012.
230
+ #
231
+ # Returns list of tables in the spreadsheet.
232
+ def tables
233
+ warn(
234
+ "DEPRECATED: Google Spreadsheet Table and Record feeds are deprecated and they " +
235
+ "will not be available after March 2012.")
236
+ doc = @session.request(:get, self.tables_feed_url)
237
+ return doc.css("entry").map(){ |e| Table.new(@session, e) }.freeze()
238
+ end
239
+
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
+ end
247
+
248
+ end
@@ -0,0 +1,60 @@
1
+ # Author: Hiroshi Ichikawa <http://gimite.net/>
2
+ # The license of this source is "New BSD Licence"
3
+
4
+ require "google_drive_v1/util"
5
+ require "google_drive_v1/error"
6
+ require "google_drive_v1/record"
7
+
8
+
9
+ module GoogleDriveV1
10
+
11
+ # DEPRECATED: Table and Record feeds are deprecated and they will not be available after
12
+ # March 2012.
13
+ #
14
+ # Use GoogleDriveV1::Worksheet#add_table to create table.
15
+ # Use GoogleDriveV1::Worksheet#tables to get GoogleDriveV1::Table objects.
16
+ class Table
17
+
18
+ include(Util)
19
+
20
+ def initialize(session, entry) #:nodoc:
21
+ @columns = {}
22
+ @worksheet_title = entry.css("gs|worksheet")[0]["name"]
23
+ @records_url = entry.css("content")[0]["src"]
24
+ @edit_url = entry.css("link[rel='edit']")[0]["href"]
25
+ @session = session
26
+ end
27
+
28
+ # Title of the worksheet the table belongs to.
29
+ attr_reader(:worksheet_title)
30
+
31
+ # Adds a record.
32
+ def add_record(values)
33
+ fields = ""
34
+ values.each() do |name, value|
35
+ fields += "<gs:field name='#{h(name)}'>#{h(value)}</gs:field>"
36
+ end
37
+ xml =<<-EOS
38
+ <entry
39
+ xmlns="http://www.w3.org/2005/Atom"
40
+ xmlns:gs="http://schemas.google.com/spreadsheets/2006">
41
+ #{fields}
42
+ </entry>
43
+ EOS
44
+ @session.request(:post, @records_url, :data => xml)
45
+ end
46
+
47
+ # Returns records in the table.
48
+ def records
49
+ doc = @session.request(:get, @records_url)
50
+ return doc.css("entry").map(){ |e| Record.new(@session, e) }
51
+ end
52
+
53
+ # Deletes this table. Deletion takes effect right away without calling save().
54
+ def delete
55
+ @session.request(:delete, @edit_url, :header => {"If-Match" => "*"})
56
+ end
57
+
58
+ end
59
+
60
+ end
@@ -0,0 +1,73 @@
1
+ # Author: Hiroshi Ichikawa <http://gimite.net/>
2
+ # The license of this source is "New BSD Licence"
3
+
4
+ require "cgi"
5
+
6
+
7
+ module GoogleDriveV1
8
+
9
+ module Util #:nodoc:
10
+
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
+ EXT_TO_CONTENT_TYPE = {
15
+ ".csv" =>"text/csv",
16
+ ".tsv" =>"text/tab-separated-values",
17
+ ".tab" =>"text/tab-separated-values",
18
+ ".doc" =>"application/msword",
19
+ ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
20
+ ".ods" =>"application/x-vnd.oasis.opendocument.spreadsheet",
21
+ ".odt" =>"application/vnd.oasis.opendocument.text",
22
+ ".rtf" =>"application/rtf",
23
+ ".sxw" =>"application/vnd.sun.xml.writer",
24
+ ".txt" =>"text/plain",
25
+ ".xls" =>"application/vnd.ms-excel",
26
+ ".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
27
+ ".pdf" =>"application/pdf",
28
+ ".png" =>"image/png",
29
+ ".ppt" =>"application/vnd.ms-powerpoint",
30
+ ".pps" =>"application/vnd.ms-powerpoint",
31
+ ".htm" =>"text/html",
32
+ ".html" =>"text/html",
33
+ ".zip" =>"application/zip",
34
+ ".swf" =>"application/x-shockwave-flash",
35
+ }
36
+
37
+ module_function
38
+
39
+ 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
+ return params.map(){ |k, v| CGI.escape(k.to_s()) + "=" + CGI.escape(v.to_s()) }.join("&")
46
+ end
47
+
48
+ def concat_url(url, piece)
49
+ (url_base, url_query) = url.split(/\?/, 2)
50
+ (piece_base, piece_query) = piece.split(/\?/, 2)
51
+ result_query = [url_query, piece_query].select(){ |s| s && !s.empty? }.join("&")
52
+ return (url_base || "") +
53
+ (piece_base || "") +
54
+ (result_query.empty? ? "" : "?#{result_query}")
55
+ end
56
+
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
+ def h(str)
67
+ # Should also escape "\n" to keep it in cell contents.
68
+ return CGI.escapeHTML(str.to_s()).gsub(/\n/, '&#x0a;')
69
+ end
70
+
71
+ end
72
+
73
+ end