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
@@ -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