gdocs4ruby 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +3 -0
- data/README +76 -0
- data/lib/gdocs4ruby/base_object.rb +408 -0
- data/lib/gdocs4ruby/document.rb +97 -0
- data/lib/gdocs4ruby/folder.rb +126 -0
- data/lib/gdocs4ruby/presentation.rb +83 -0
- data/lib/gdocs4ruby/service.rb +105 -0
- data/lib/gdocs4ruby/spreadsheet.rb +85 -0
- data/lib/gdocs4ruby.rb +1 -0
- data/test/unit.rb +3 -0
- metadata +72 -0
data/CHANGELOG
ADDED
data/README
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
#=GDocs4Ruby
|
2
|
+
#
|
3
|
+
#==Introduction
|
4
|
+
#GDocs4Ruby is a full featured wrapper for version 2.0 of the Google Documents API (aka DocList). GDocs4Ruby provides the ability
|
5
|
+
#to create, update and delete google documents, metadata and content. The gem also includes support for folders, modifying
|
6
|
+
#permissions for documents via ACL feeds, and much more.
|
7
|
+
#
|
8
|
+
#GDocs4Ruby uses the GData4Ruby Gem for interacting with the Google API. Check out http://cookingandcoding.com/gdata4ruby for
|
9
|
+
#other Google API Libraries based using GData4Ruby.
|
10
|
+
#
|
11
|
+
#==Author and Contact Information
|
12
|
+
#GDocs4Ruby was created and is maintained by {Mike Reich}[mailto:mike@seabourneconsulting.com]
|
13
|
+
#and is licenses under the GPL v2. Feel free to use and update, but be sure to contribute your
|
14
|
+
#code back to the project and attribute as required by the license.
|
15
|
+
#===Website
|
16
|
+
#http://cookingandcoding.com/gdocs4ruby/
|
17
|
+
#
|
18
|
+
#==Description
|
19
|
+
#GDocs4Ruby includes the following classes: Service, Folder, BaseObject, Spreadsheet, Document, Presentation.
|
20
|
+
#
|
21
|
+
#The Service object provides functionality for authenticating with the Google Documents API, grabbing a list of
|
22
|
+
#documents and a list of folders associated with the account.
|
23
|
+
#
|
24
|
+
#Interacting with objects is done by using the associated subclass of BaseObject, i.e. Document. Every object
|
25
|
+
#class supports the same inherited methods for creating, updating and deleting, in addition to changing
|
26
|
+
#ACL permissions, and adding and removing from various folders.
|
27
|
+
#
|
28
|
+
#==Examples
|
29
|
+
#Below are some common usage examples. For more examples, check the documentation. Also, check out the example code
|
30
|
+
#for integrating with Rails at http://cookingandcoding.com/gdocs4ruby/example/
|
31
|
+
#===Service
|
32
|
+
#1. Authenticate
|
33
|
+
# service = Service.new
|
34
|
+
# service.authenticate("user@gmail.com", "password")
|
35
|
+
#
|
36
|
+
#2. Get Document List
|
37
|
+
# documents = service.files
|
38
|
+
#
|
39
|
+
#3. Get Folder List
|
40
|
+
# folders = serivce.folders
|
41
|
+
#
|
42
|
+
#===Documents
|
43
|
+
#1. Create a new Document
|
44
|
+
# doc = Document.new(@service)
|
45
|
+
# doc.title = 'Test Document'
|
46
|
+
# doc.content = '<h1>Test Content HTML</h1>'
|
47
|
+
# doc.content_type = 'html'
|
48
|
+
# doc.save
|
49
|
+
#
|
50
|
+
#2. Deleting a Document
|
51
|
+
# doc = Document.find(@service, {:id => @doc_id})
|
52
|
+
# doc.delete
|
53
|
+
#
|
54
|
+
#3. Finding an existing Document by id
|
55
|
+
# doc = Document.find(@service, {:id => @doc_id})
|
56
|
+
#
|
57
|
+
#4. Full Text Query
|
58
|
+
# doc = Document.find(@service, 'content text')
|
59
|
+
#
|
60
|
+
# or
|
61
|
+
#
|
62
|
+
# doc = Document.find(@service, {:query => 'content text'})
|
63
|
+
#
|
64
|
+
#5. Finding an Existing Document by Title
|
65
|
+
# doc = Document.find(@service, nil, {'title' => 'Test Document'})
|
66
|
+
#
|
67
|
+
#6. Updating a Document with Content from a Local File
|
68
|
+
# doc = Document.find(@service, {:id => @doc_id})
|
69
|
+
# doc.title = 'New Title'
|
70
|
+
# doc.local_file = '/path/to/some/file'
|
71
|
+
# doc.save
|
72
|
+
#
|
73
|
+
#7. Retrieving an Export
|
74
|
+
# doc = Document.find(@service, {:id => @doc_id})
|
75
|
+
# doc.download_to_file('pdf', '/path/to/save/location.pdf')
|
76
|
+
|
@@ -0,0 +1,408 @@
|
|
1
|
+
# Author:: Mike Reich (mike@seabourneconsulting.com)
|
2
|
+
# Copyright:: Copyright (C) 2010 Mike Reich
|
3
|
+
# License:: GPL v2
|
4
|
+
#--
|
5
|
+
# Licensed under the General Public License (GPL), Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
#
|
15
|
+
# Feel free to use and update, but be sure to contribute your
|
16
|
+
# code back to the project and attribute as required by the license.
|
17
|
+
#++
|
18
|
+
require 'gdata4ruby/gdata_object'
|
19
|
+
require 'gdata4ruby/acl/access_rule'
|
20
|
+
|
21
|
+
module GDocs4Ruby
|
22
|
+
|
23
|
+
#The base object class that includes all major methods for interacting with Google Documents API.
|
24
|
+
#=Usage
|
25
|
+
#All usages assume you've already authenticated with the service, and have a service object called
|
26
|
+
#@service.
|
27
|
+
#*Note*: You probably don't want to instantiate a BaseObject directly, but rather use any of the subclasses
|
28
|
+
#Document, Spreadsheet, and Presentation
|
29
|
+
#1. Create a new Document
|
30
|
+
# doc = BaseObject.new(@service)
|
31
|
+
# doc.title = 'Test Document'
|
32
|
+
# doc.content = '<h1>Test Content HTML</h1>'
|
33
|
+
# doc.content_type = 'html'
|
34
|
+
# doc.save
|
35
|
+
#
|
36
|
+
#2. Deleting a Document
|
37
|
+
# doc = BaseObject.find(@service, {:id => @doc_id})
|
38
|
+
# doc.delete
|
39
|
+
#
|
40
|
+
#3. Finding an existing Document by id
|
41
|
+
# doc = BaseObject.find(@service, {:id => @doc_id})
|
42
|
+
#
|
43
|
+
#4. Full Text Query
|
44
|
+
# doc = BaseObject.find(@service, 'content text')
|
45
|
+
#
|
46
|
+
# or
|
47
|
+
#
|
48
|
+
# doc = BaseObject.find(@service, {:query => 'content text'})
|
49
|
+
#
|
50
|
+
#5. Finding an Existing Document by Title
|
51
|
+
# doc = BaseObject.find(@service, nil, 'any', {'title' => 'Test Document'})
|
52
|
+
#
|
53
|
+
#6. Updating a Document with Content from a Local File
|
54
|
+
# doc = BaseObject.find(@service, {:id => @doc_id})
|
55
|
+
# doc.title = 'New Title'
|
56
|
+
# doc.local_file = '/path/to/some/file'
|
57
|
+
# doc.save
|
58
|
+
|
59
|
+
class BaseObject < GData4Ruby::GDataObject
|
60
|
+
ENTRY_XML = '<atom:entry xmlns:atom="http://www.w3.org/2005/Atom">
|
61
|
+
<atom:title></atom:title>
|
62
|
+
</atom:entry>'
|
63
|
+
BOUNDARY = 'GDOCS4RUBY_BOUNDARY'
|
64
|
+
UPLOAD_TYPES = {'' => 'text/txt',
|
65
|
+
:csv => 'text/csv',
|
66
|
+
:tsv => 'text/tab-separated-values',
|
67
|
+
:tab => 'text/tab-separated-values',
|
68
|
+
:html => 'text/html',
|
69
|
+
:htm => 'text/html',
|
70
|
+
:doc => 'application/msword',
|
71
|
+
:docx => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
72
|
+
:ods => 'application/x-vnd.oasis.opendocument.spreadsheet',
|
73
|
+
:odt => 'application/vnd.oasis.opendocument.text',
|
74
|
+
:rtf => 'application/rtf',
|
75
|
+
:sxw => 'application/vnd.sun.xml.writer',
|
76
|
+
:txt => 'text/plain',
|
77
|
+
:xls => 'application/vnd.ms-excel',
|
78
|
+
:xlsx => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
79
|
+
:pdf => 'application/pdf',
|
80
|
+
:ppt => 'application/vnd.ms-powerpoint',
|
81
|
+
:pps => 'application/vnd.ms-powerpoint',
|
82
|
+
:pptx => 'application/vnd.ms-powerpoint'}
|
83
|
+
|
84
|
+
FEEDS = {:document => "https://docs.google.com/feeds/documents/private/full/",
|
85
|
+
:folder => "http://docs.google.com/feeds/folders/private/full/",
|
86
|
+
:spreadsheet => "https://docs.google.com/feeds/documents/private/full/",
|
87
|
+
:presentation => "https://docs.google.com/feeds/documents/private/full/",
|
88
|
+
:any => "https://docs.google.com/feeds/documents/private/full/"}
|
89
|
+
|
90
|
+
QUERY_FEEDS = {:document => "https://docs.google.com/feeds/documents/private/full/-/document",
|
91
|
+
:folder => "http://docs.google.com/feeds/folders/private/full/?showfolders=true",
|
92
|
+
:spreadsheet => "https://docs.google.com/feeds/documents/private/full/-/spreadsheet",
|
93
|
+
:presentation => "https://docs.google.com/feeds/documents/private/full/-/presentation",
|
94
|
+
:any => "https://docs.google.com/feeds/documents/private/full/"}
|
95
|
+
|
96
|
+
TYPES = ["document", "folder", "spreadsheet", "presentation", "any"]
|
97
|
+
|
98
|
+
#The raw date the document was published
|
99
|
+
attr_reader :published
|
100
|
+
|
101
|
+
#The raw date the document was last updated
|
102
|
+
attr_reader :updated
|
103
|
+
|
104
|
+
#The author/owner name
|
105
|
+
attr_reader :author_name
|
106
|
+
|
107
|
+
#The author/owner email
|
108
|
+
attr_reader :author_email
|
109
|
+
|
110
|
+
#An array of folders this object belongs to
|
111
|
+
attr_reader :folders
|
112
|
+
|
113
|
+
#Quota bytes used by the document
|
114
|
+
attr_reader :bytes_used
|
115
|
+
|
116
|
+
#The type of the object, one of TYPES
|
117
|
+
attr_reader :type
|
118
|
+
|
119
|
+
#The uri for the html editor of the object (the web editor for documents)
|
120
|
+
attr_reader :html_uri
|
121
|
+
|
122
|
+
#The content uri for exporting the object content
|
123
|
+
attr_reader :content_uri
|
124
|
+
|
125
|
+
#Flag indicating whether the document has the 'viewed' category link.
|
126
|
+
attr_reader :viewed
|
127
|
+
|
128
|
+
#A local file to upload content from
|
129
|
+
attr_accessor :local_file
|
130
|
+
|
131
|
+
#Creates a new BaseObject instance. Requires a valid GData4Ruby::Service object.
|
132
|
+
def initialize(service, attributes = {})
|
133
|
+
super(service, attributes)
|
134
|
+
@xml = ENTRY_XML
|
135
|
+
@folders = []
|
136
|
+
@content_uri = nil
|
137
|
+
@edit_content_uri = nil
|
138
|
+
@viewed = false
|
139
|
+
@content = @content_type = nil
|
140
|
+
end
|
141
|
+
|
142
|
+
public
|
143
|
+
#Loads a string containing an XML <entry> from a Google API feed.
|
144
|
+
def load(string)
|
145
|
+
super(string)
|
146
|
+
@folders = []
|
147
|
+
xml = REXML::Document.new(string)
|
148
|
+
xml.root.elements.each(){}.map do |ele|
|
149
|
+
@etag = xml.root.attributes['etag'] if xml.root.attributes['etag']
|
150
|
+
case ele.name
|
151
|
+
when 'published'
|
152
|
+
@published = ele.text
|
153
|
+
when 'updated'
|
154
|
+
@updated = ele.text
|
155
|
+
when 'content'
|
156
|
+
@content_uri = ele.attributes['src']
|
157
|
+
when 'link'
|
158
|
+
case ele.attributes['rel']
|
159
|
+
when 'edit-media'
|
160
|
+
@edit_content_uri = ele.attributes['href']
|
161
|
+
when 'alternate'
|
162
|
+
@html_uri = ele.attributes['href']
|
163
|
+
end
|
164
|
+
when 'author'
|
165
|
+
ele.elements.each('name'){}.map {|e| @author_name = e.text}
|
166
|
+
ele.elements.each('email'){}.map {|e| @author_email = e.text}
|
167
|
+
when 'quotaBytesUsed'
|
168
|
+
@bytes_used = ele.text
|
169
|
+
end
|
170
|
+
end
|
171
|
+
@categories.each do |cat|
|
172
|
+
@folders << cat[:label] if cat[:scheme] and cat[:scheme].include? "folders"
|
173
|
+
@viewed = true if cat[:label] and cat[:label] == 'viewed'
|
174
|
+
@type = cat[:label] if cat[:scheme] and cat[:scheme] == 'http://schemas.google.com/g/2005#kind'
|
175
|
+
end
|
176
|
+
return xml.root
|
177
|
+
end
|
178
|
+
|
179
|
+
#Sets content to save to the document. Content must be formatted as one of the types in UPLOAD_TYPES.
|
180
|
+
def content=(value)
|
181
|
+
@content = value
|
182
|
+
end
|
183
|
+
|
184
|
+
#Sets the content_type stored in content. content_type must be one of the keys in UPLOAD_TYPES.
|
185
|
+
def content_type=(value)
|
186
|
+
@content_type = value
|
187
|
+
end
|
188
|
+
|
189
|
+
#Saves or creates the object depending on whether it exists or not.
|
190
|
+
def save
|
191
|
+
if @exists
|
192
|
+
if (not @local_file.nil? and @local_file.is_a? String) or @content
|
193
|
+
@include_etag = false
|
194
|
+
if @local_file
|
195
|
+
ret = service.send_request(GData4Ruby::Request.new(:put, @edit_content_uri, create_multipart_message([{:type => 'application/atom+xml', :content => to_xml()}, {:type => UPLOAD_TYPES[File.extname(@local_file).gsub(".", "").to_sym], :content => get_file(@local_file).read}]), {'Content-Type' => "multipart/related; boundary=#{BOUNDARY}", 'Content-Length' => File.size(@local_file).to_s, 'Slug' => File.basename(@local_file), 'If-Match' => "*"}))
|
196
|
+
elsif @content
|
197
|
+
ret = service.send_request(GData4Ruby::Request.new(:put, @edit_content_uri, create_multipart_message([{:type => 'application/atom+xml', :content => to_xml()}, {:type => UPLOAD_TYPES[@content_type.to_sym], :content => @content}]), {'Content-Type' => "multipart/related; boundary=#{BOUNDARY}", 'Content-Length' => @content.size.to_s, 'Slug' => @title, 'If-Match' => "*"}))
|
198
|
+
end
|
199
|
+
else
|
200
|
+
ret = service.send_request(GData4Ruby::Request.new(:put, @edit_uri, to_xml()))
|
201
|
+
end
|
202
|
+
if not load(ret.read_body)
|
203
|
+
raise SaveFailed
|
204
|
+
end
|
205
|
+
return true
|
206
|
+
else
|
207
|
+
return create
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
#Retrieves an array of GData4Ruby::AccessRules representing the access rules for the object, as contained in the Google ACL.
|
212
|
+
def access_rules
|
213
|
+
rules = []
|
214
|
+
ret = service.send_request(GData4Ruby::Request.new(:get, @acl_uri))
|
215
|
+
xml = REXML::Document.new(ret.read_body).root
|
216
|
+
xml.elements.each("entry") do |e|
|
217
|
+
ele = GData4Ruby::Utils::add_namespaces(e)
|
218
|
+
rule = GData4Ruby::ACL::AccessRule.new(service, self)
|
219
|
+
puts ele.to_s if service.debug
|
220
|
+
rule.load(ele.to_s)
|
221
|
+
rules << rule
|
222
|
+
end
|
223
|
+
rules
|
224
|
+
end
|
225
|
+
|
226
|
+
#Adds a new access rule for the object. Parameters are:
|
227
|
+
#*user*:: the user (email address) to add permissions for
|
228
|
+
#*role*:: can be one of 'viewer' or 'writer' depending on whether the user should be able to edit or read only.
|
229
|
+
def add_access_rule(user, role)
|
230
|
+
a = GData4Ruby::ACL::AccessRule.new(service, self)
|
231
|
+
a.user = user
|
232
|
+
a.role = role
|
233
|
+
a.save
|
234
|
+
end
|
235
|
+
|
236
|
+
# Waiting for V3 to graduate
|
237
|
+
# def set_publicly_writable(value)
|
238
|
+
# if value
|
239
|
+
# a = GData4Ruby::ACL::AccessRule.new(service, self)
|
240
|
+
# a.role = 'writer'
|
241
|
+
# a.save
|
242
|
+
# else
|
243
|
+
# remove_access_rule('default', 'writer')
|
244
|
+
# end
|
245
|
+
# end
|
246
|
+
|
247
|
+
# Waiting for V3 to graduate
|
248
|
+
# def set_publicly_readable(value)
|
249
|
+
# if value
|
250
|
+
# a = GData4Ruby::ACL::AccessRule.new(service, self)
|
251
|
+
# a.role = 'reader'
|
252
|
+
# a.save
|
253
|
+
# else
|
254
|
+
# remove_access_rule('default', 'reader')
|
255
|
+
# end
|
256
|
+
# end
|
257
|
+
|
258
|
+
#Updates an existing access rule for the object. Parameters are:
|
259
|
+
#*user*:: the user (email address) to update permissions
|
260
|
+
#*role*:: can be one of 'viewer' or 'writer' depending on whether the user should be able to edit or read only.
|
261
|
+
def update_access_rule(user, role)
|
262
|
+
a = GData4Ruby::ACL::AccessRule.find(service, self, {:user => user})
|
263
|
+
if a
|
264
|
+
a.role = role
|
265
|
+
if a.save
|
266
|
+
return true
|
267
|
+
end
|
268
|
+
end
|
269
|
+
return false
|
270
|
+
end
|
271
|
+
|
272
|
+
#Removes an access rule for the specified user. Parameter should be a valid user Id (email address).
|
273
|
+
def remove_access_rule(user)
|
274
|
+
a = GData4Ruby::ACL::AccessRule.find(service, self, {:user => user})
|
275
|
+
if a
|
276
|
+
if a.delete
|
277
|
+
return true
|
278
|
+
end
|
279
|
+
end
|
280
|
+
return false
|
281
|
+
end
|
282
|
+
|
283
|
+
#Creates a new object instance on the Google server if the object doesn't already exist.
|
284
|
+
def create
|
285
|
+
ret = if (not @local_file.nil? and @local_file.is_a? String) or @content
|
286
|
+
if @local_file
|
287
|
+
service.send_request(GData4Ruby::Request.new(:post, DOCUMENT_LIST_FEED, create_multipart_message([{:type => 'application/atom+xml', :content => to_xml()}, {:type => UPLOAD_TYPES[File.extname(@local_file).gsub(".", "").to_sym], :content => get_file(@local_file).read}]), {'Content-Type' => "multipart/related; boundary=#{BOUNDARY}", 'Content-Length' => File.size(@local_file).to_s, 'Slug' => File.basename(@local_file)}))
|
288
|
+
elsif @content
|
289
|
+
service.send_request(GData4Ruby::Request.new(:post, DOCUMENT_LIST_FEED, create_multipart_message([{:type => 'application/atom+xml', :content => to_xml()}, {:type => UPLOAD_TYPES[@content_type.to_sym], :content => @content}]), {'Content-Type' => "multipart/related; boundary=#{BOUNDARY}", 'Content-Length' => @content.size.to_s, 'Slug' => @title}))
|
290
|
+
end
|
291
|
+
else
|
292
|
+
service.send_request(GData4Ruby::Request.new(:post, DOCUMENT_LIST_FEED, to_xml()))
|
293
|
+
end
|
294
|
+
if not load(ret.read_body)
|
295
|
+
raise SaveFailed
|
296
|
+
end
|
297
|
+
return ret
|
298
|
+
end
|
299
|
+
|
300
|
+
#Returns a simple iframe containing the html_uri link for the document.
|
301
|
+
#
|
302
|
+
#*Note:* you must either be logged in to Google
|
303
|
+
#as the owner of the document for this to work, or have appropriate read/write permissions set up on the document.
|
304
|
+
def to_iframe(options = {})
|
305
|
+
width = options[:width] || '800'
|
306
|
+
height = options[:height] || '500'
|
307
|
+
return "<iframe height='#{height}' width='#{width}' src='#{@html_uri}'></iframe>"
|
308
|
+
end
|
309
|
+
|
310
|
+
#Saves arbitrary content to the object. Parameters must be:
|
311
|
+
#*content*:: the content to upload. Content should be formatted as one of the UPLOAD_TYPES.
|
312
|
+
#*type*:: an optional paramter specifying the type, if not HTML. This value must be a mime-type enumerated in UPLOAD_TYPES.
|
313
|
+
def put_content(content, type = 'text/html')
|
314
|
+
ret = service.send_request(GData4Ruby::Request.new(:put, @edit_content_uri, content, {'Content-Type' => type,
|
315
|
+
'Content-Length' => content.length.to_s,
|
316
|
+
'If-Match' => "*"}))
|
317
|
+
load(ret.body)
|
318
|
+
end
|
319
|
+
|
320
|
+
#Finds a BaseObject based on a text query or by an id. Parameters are:
|
321
|
+
#*service*:: A valid Service object to search.
|
322
|
+
#*query*:: either a string containing a text query to search by, or a hash containing an +id+ key with an associated id to find, or a +query+ key containint a text query to search for.
|
323
|
+
#*type*:: used to limit results to a specific document type, as list in TYPES.
|
324
|
+
#*args*:: a hash containing optional additional query paramters to use. See http://code.google.com/apis/gdata/docs/2.0/reference.html#Queries for a full list of possible values. Example:
|
325
|
+
# {'max-results' => '100'}
|
326
|
+
#If an ID is specified, a single instance of the document is returned if found, otherwise false.
|
327
|
+
#If a query term is specified, and array of matching results is returned, or an empty array if nothing
|
328
|
+
#was found.
|
329
|
+
def self.find(service, query, type = 'any', args = {})
|
330
|
+
raise ArgumentError, 'query must be a hash or string' if not query.is_a? Hash and not query.is_a? String
|
331
|
+
raise ArgumentError, "type must be one of #{TYPES.join(" ")}" if not TYPES.include? type
|
332
|
+
if query.is_a? Hash and query[:id]
|
333
|
+
id = query[:id]
|
334
|
+
puts "id passed, finding event by id" if service.debug
|
335
|
+
puts "id = "+id if service.debug
|
336
|
+
d = service.send_request(GData4Ruby::Request.new(:get, FEEDS[type.to_sym]+id, {"If-Not-Match" => "*"}))
|
337
|
+
puts d.inspect if service.debug
|
338
|
+
if d
|
339
|
+
return get_instance(service, d)
|
340
|
+
end
|
341
|
+
else
|
342
|
+
results = []
|
343
|
+
term = query.is_a?(Hash) ? CGI::escape(query[:query]) : CGI::escape(query)
|
344
|
+
args["q"] = term if term and term != ''
|
345
|
+
ret = service.send_request(GData4Ruby::Request.new(:get, QUERY_FEEDS[type.to_sym], nil, nil, args))
|
346
|
+
xml = REXML::Document.new(ret.body).root
|
347
|
+
xml.elements.each("entry") do |e|
|
348
|
+
results << get_instance(service, e)
|
349
|
+
end
|
350
|
+
return results
|
351
|
+
end
|
352
|
+
return false
|
353
|
+
end
|
354
|
+
|
355
|
+
#Adds the object to the specified folder. The parameter must be a valid Folder object.
|
356
|
+
def add_to_folder(folder)
|
357
|
+
raise ArgumentError, 'folder must be a GDocs4Ruby::Folder' if not folder.is_a? Folder
|
358
|
+
@service.send_request(GData4Ruby::Request.new(:post, folder.content_uri, to_xml))
|
359
|
+
end
|
360
|
+
|
361
|
+
#Removes the object from the specified folder. The parameter must be a valid Folder object.
|
362
|
+
def remove_from_folder(folder)
|
363
|
+
raise ArgumentError, 'folder must be a GDocs4Ruby::Folder' if not folder.is_a? Folder
|
364
|
+
@service.send_request(GData4Ruby::Request.new(:delete, folder.content_uri+"/"+CGI::escape(id), nil, {"If-Match" => "*"}))
|
365
|
+
end
|
366
|
+
|
367
|
+
private
|
368
|
+
def self.get_instance(service, d)
|
369
|
+
if d.is_a? Net::HTTPOK
|
370
|
+
xml = REXML::Document.new(d.read_body).root
|
371
|
+
if xml.name == 'feed'
|
372
|
+
xml = xml.elements.each("entry"){}[0]
|
373
|
+
end
|
374
|
+
else
|
375
|
+
xml = d
|
376
|
+
end
|
377
|
+
ele = GData4Ruby::Utils::add_namespaces(xml)
|
378
|
+
obj = BaseObject.new(service)
|
379
|
+
obj.load(ele.to_s)
|
380
|
+
case obj.type
|
381
|
+
when 'document'
|
382
|
+
doc = Document.new(service)
|
383
|
+
when 'spreadsheet'
|
384
|
+
doc = Spreadsheet.new(service)
|
385
|
+
when 'folder'
|
386
|
+
doc = Folder.new(service)
|
387
|
+
when 'presentation'
|
388
|
+
doc = Presentation.new(service)
|
389
|
+
end
|
390
|
+
doc.load(ele.to_s)
|
391
|
+
doc
|
392
|
+
end
|
393
|
+
|
394
|
+
def get_file(filename)
|
395
|
+
file = File.open(filename, "rb")
|
396
|
+
raise FileNotFoundError if not file
|
397
|
+
return file
|
398
|
+
end
|
399
|
+
|
400
|
+
def create_multipart_message(parts)
|
401
|
+
ret = ''
|
402
|
+
parts.each do |p|
|
403
|
+
ret += "--#{BOUNDARY}\nContent-Type: #{p[:type]}\n\n#{p[:content]}\n\n"
|
404
|
+
end
|
405
|
+
ret += "--#{BOUNDARY}--\n"
|
406
|
+
end
|
407
|
+
end
|
408
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# Author:: Mike Reich (mike@seabourneconsulting.com)
|
2
|
+
# Copyright:: Copyright (C) 2010 Mike Reich
|
3
|
+
# License:: GPL v2
|
4
|
+
#--
|
5
|
+
# Licensed under the General Public License (GPL), Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
#
|
15
|
+
# Feel free to use and update, but be sure to contribute your
|
16
|
+
# code back to the project and attribute as required by the license.
|
17
|
+
#++
|
18
|
+
module GDocs4Ruby
|
19
|
+
#The Document class represents a Google Word Document. Also check out BaseObject, the superclass of Document.
|
20
|
+
#=Usage
|
21
|
+
#All usages assume you've already authenticated with the service, and have a service object called
|
22
|
+
#@service.
|
23
|
+
#1. Create a new Document
|
24
|
+
# doc = Document.new(@service)
|
25
|
+
# doc.title = 'Test Document'
|
26
|
+
# doc.content = '<h1>Test Content HTML</h1>'
|
27
|
+
# doc.content_type = 'html'
|
28
|
+
# doc.save
|
29
|
+
#
|
30
|
+
#2. Deleting a Document
|
31
|
+
# doc = Document.find(@service, {:id => @doc_id})
|
32
|
+
# doc.delete
|
33
|
+
#
|
34
|
+
#3. Finding an existing Document by id
|
35
|
+
# doc = Document.find(@service, {:id => @doc_id})
|
36
|
+
#
|
37
|
+
#4. Full Text Query
|
38
|
+
# doc = Document.find(@service, 'content text')
|
39
|
+
#
|
40
|
+
# or
|
41
|
+
#
|
42
|
+
# doc = Document.find(@service, {:query => 'content text'})
|
43
|
+
#
|
44
|
+
#5. Finding an Existing Document by Title
|
45
|
+
# doc = Document.find(@service, nil, {'title' => 'Test Document'})
|
46
|
+
#
|
47
|
+
#6. Updating a Document with Content from a Local File
|
48
|
+
# doc = Document.find(@service, {:id => @doc_id})
|
49
|
+
# doc.title = 'New Title'
|
50
|
+
# doc.local_file = '/path/to/some/file'
|
51
|
+
# doc.save
|
52
|
+
#
|
53
|
+
#7. Retrieving an Export
|
54
|
+
# doc = Document.find(@service, {:id => @doc_id})
|
55
|
+
# doc.download_to_file('pdf', '/path/to/save/location.pdf')
|
56
|
+
|
57
|
+
class Document < BaseObject
|
58
|
+
DOCUMENT_XML = '<?xml version="1.0" encoding="UTF-8"?>
|
59
|
+
<atom:entry xmlns:atom="http://www.w3.org/2005/Atom">
|
60
|
+
<atom:category scheme="http://schemas.google.com/g/2005#kind"
|
61
|
+
term="http://schemas.google.com/docs/2007#document" label="document"/>
|
62
|
+
<atom:title>example document</atom:title>
|
63
|
+
</atom:entry>'
|
64
|
+
DOWNLOAD_TYPES = ['doc', 'html', 'odt', 'pdf', 'png', 'rtf', 'txt', 'zip']
|
65
|
+
EXPORT_URI = 'https://docs.google.com/feeds/download/documents/Export'
|
66
|
+
|
67
|
+
#Creates a new Document instance. Requires a valid Service object.
|
68
|
+
def initialize(service, attributes = {})
|
69
|
+
super(service, attributes)
|
70
|
+
@xml = DOCUMENT_XML
|
71
|
+
end
|
72
|
+
|
73
|
+
#Retrieves an export of the Document. The parameter +type+ must be one of the DOWNLOAD_TYPES.
|
74
|
+
def get_content(type)
|
75
|
+
if !@exists
|
76
|
+
raise DocumentDoesntExist
|
77
|
+
end
|
78
|
+
if not DOWNLOAD_TYPES.include? type
|
79
|
+
raise ArgumentError
|
80
|
+
end
|
81
|
+
ret = service.send_request(GData4Ruby::Request.new(:get, EXPORT_URI, nil, nil, {"docId" => @id,"exportFormat" => type}))
|
82
|
+
ret.body
|
83
|
+
end
|
84
|
+
|
85
|
+
#Helper function limit queries to Documents. See BaseObject#find for syntax. Type is not required and assumed to be 'document'.
|
86
|
+
def self.find(service, query, args = {})
|
87
|
+
super(service, query, 'document', args)
|
88
|
+
end
|
89
|
+
|
90
|
+
#Downloads the export retrieved through get_content to a specified local file. Parameters are:
|
91
|
+
#*type*:: must be a valid type enumerated in DOWNLOAD_TYPES
|
92
|
+
#*location*:: a valid file location for the local system
|
93
|
+
def download_to_file(type, location)
|
94
|
+
File.open(location, 'wb+') {|f| f.write(get_content(type)) }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# Author:: Mike Reich (mike@seabourneconsulting.com)
|
2
|
+
# Copyright:: Copyright (C) 2010 Mike Reich
|
3
|
+
# License:: GPL v2
|
4
|
+
#--
|
5
|
+
# Licensed under the General Public License (GPL), Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
#
|
15
|
+
# Feel free to use and update, but be sure to contribute your
|
16
|
+
# code back to the project and attribute as required by the license.
|
17
|
+
#++
|
18
|
+
module GDocs4Ruby
|
19
|
+
#The Document class represents a Google Documents Folder.
|
20
|
+
#=Usage
|
21
|
+
#Assumes a valid and authenticated @service object.
|
22
|
+
#1. Retrieving a list of folders
|
23
|
+
# @service.folders
|
24
|
+
#
|
25
|
+
#2. Getting a list of files in a folder
|
26
|
+
# @folder = @service.folders.first
|
27
|
+
# @folder.files
|
28
|
+
#
|
29
|
+
#3. Getting a list of sub folders in a folder
|
30
|
+
# @folder = @service.folders.first
|
31
|
+
# @folder.sub_folders
|
32
|
+
#
|
33
|
+
class Folder < BaseObject
|
34
|
+
FOLDER_XML = '<?xml version="1.0" encoding="UTF-8"?>
|
35
|
+
<atom:entry xmlns:atom="http://www.w3.org/2005/Atom">
|
36
|
+
<atom:category scheme="http://schemas.google.com/g/2005#kind"
|
37
|
+
term="http://schemas.google.com/docs/2007#folder" label="folder"/>
|
38
|
+
<atom:title></atom:title>
|
39
|
+
</atom:entry>'
|
40
|
+
|
41
|
+
#Creates a new Folder instance. Requires a valid GData4Ruby#Service object.
|
42
|
+
def initialize(service, attributes = {})
|
43
|
+
super(service, attributes)
|
44
|
+
@xml = FOLDER_XML
|
45
|
+
end
|
46
|
+
|
47
|
+
public
|
48
|
+
#Loads the Calendar with returned data from Google Calendar feed. Returns true if successful.
|
49
|
+
def load(string)
|
50
|
+
super(string)
|
51
|
+
xml = REXML::Document.new(string)
|
52
|
+
xml.root.elements.each(){}.map do |ele|
|
53
|
+
# case ele.name
|
54
|
+
#
|
55
|
+
# end
|
56
|
+
end
|
57
|
+
|
58
|
+
@folder_feed = @id
|
59
|
+
return true
|
60
|
+
end
|
61
|
+
|
62
|
+
#Returns a list of sub folders that this folder contains.
|
63
|
+
def sub_folders
|
64
|
+
ret = service.send_request(GData4Ruby::Request.new(:get, @content_uri+"/-/folder?showfolders=true"))
|
65
|
+
folders = []
|
66
|
+
REXML::Document.new(ret.body).root.elements.each("entry"){}.map do |entry|
|
67
|
+
entry = GData4Ruby::Utils::add_namespaces(entry)
|
68
|
+
folder = Folder.new(service)
|
69
|
+
puts entry.to_s if service.debug
|
70
|
+
folder.load("<?xml version='1.0' encoding='UTF-8'?>#{entry.to_s}")
|
71
|
+
folders << folder
|
72
|
+
end
|
73
|
+
return folders
|
74
|
+
end
|
75
|
+
|
76
|
+
#Returns a list of files in the folder
|
77
|
+
def files
|
78
|
+
return nil if @content_uri == nil
|
79
|
+
contents = []
|
80
|
+
ret = @service.send_request(GData4Ruby::Request.new(:get, @content_uri))
|
81
|
+
xml = REXML::Document.new(ret.body)
|
82
|
+
xml.root.elements.each('entry'){}.map do |ele|
|
83
|
+
ele = GData4Ruby::Utils::add_namespaces(ele)
|
84
|
+
obj = BaseObject.new(@service)
|
85
|
+
obj.load(ele.to_s)
|
86
|
+
case obj.type
|
87
|
+
when 'document'
|
88
|
+
doc = Document.new(@service)
|
89
|
+
when 'spreadsheet'
|
90
|
+
doc = Spreadsheet.new(@service)
|
91
|
+
when 'presentation'
|
92
|
+
doc = Presentation.new(service)
|
93
|
+
end
|
94
|
+
doc.load(ele.to_s)
|
95
|
+
contents << doc
|
96
|
+
end
|
97
|
+
return contents
|
98
|
+
end
|
99
|
+
|
100
|
+
#Helper function limit queries to Folders. See BaseObject#find for syntax. Type is not required and assumed to be 'document'.
|
101
|
+
def self.find(service, query, args = {})
|
102
|
+
raise ArgumentError if not query.is_a? Hash and not query.is_a? String
|
103
|
+
ret = query.is_a?(String) ? [] : nil
|
104
|
+
service.folders.each do |f|
|
105
|
+
if (query.is_a? Hash and ((query[:id] and f.id == query[:id]) or (query[:query] and f.title.include? query[:query])))
|
106
|
+
return f
|
107
|
+
end
|
108
|
+
if (query.is_a? String and f.title.include? query)
|
109
|
+
ret << f
|
110
|
+
end
|
111
|
+
end
|
112
|
+
return ret
|
113
|
+
end
|
114
|
+
|
115
|
+
#A reference to the parent folder. If there is no parent folder, nil is returned.
|
116
|
+
def parent
|
117
|
+
return nil if @parent_uri == nil
|
118
|
+
ret = @service.send_request(GData4Ruby::Request.new(:get, @parent_uri))
|
119
|
+
folder = nil
|
120
|
+
puts ret.body if @service.debug
|
121
|
+
folder = Folder.new(@service)
|
122
|
+
folder.load(ret.body)
|
123
|
+
return folder
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# Author:: Mike Reich (mike@seabourneconsulting.com)
|
2
|
+
# Copyright:: Copyright (C) 2010 Mike Reich
|
3
|
+
# License:: GPL v2
|
4
|
+
#--
|
5
|
+
# Licensed under the General Public License (GPL), Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
#
|
15
|
+
# Feel free to use and update, but be sure to contribute your
|
16
|
+
# code back to the project and attribute as required by the license.
|
17
|
+
#++
|
18
|
+
module GDocs4Ruby
|
19
|
+
#The Presentation class represents a Google Presentation. Also check out Document and BaseObject, the superclass of Presentation.
|
20
|
+
#=Usage
|
21
|
+
#All usages assume you've already authenticated with the service, and have a service object called
|
22
|
+
#@service.
|
23
|
+
#1. Create a new Presentation
|
24
|
+
# p = Presentation.new(@service)
|
25
|
+
# p.title = 'Test Presentation'
|
26
|
+
# p.local_file = '/path/to/some/spreadsheet.ppt'
|
27
|
+
# p.save
|
28
|
+
#
|
29
|
+
#2. Deleting a Presentation
|
30
|
+
# p = Presentation.find(@service, {:id => @doc_id})
|
31
|
+
# p.delete
|
32
|
+
#
|
33
|
+
#3. Finding an existing Presentation by id
|
34
|
+
# p = Presentation.find(@service, {:id => @doc_id})
|
35
|
+
#
|
36
|
+
#4. Full Text Query
|
37
|
+
# p = Presentation.find(@service, 'content text')
|
38
|
+
#
|
39
|
+
# or
|
40
|
+
#
|
41
|
+
# p = Presentation.find(@service, {:query => 'content text'})
|
42
|
+
#
|
43
|
+
#5. Finding an Existing Spreadsheet by Title
|
44
|
+
# p = Presentation.find(@service, nil, {'title' => 'Test Presentation'})
|
45
|
+
#
|
46
|
+
#6. Retrieving an Export
|
47
|
+
# p = Presentation.find(@service, {:id => @doc_id})
|
48
|
+
# p.download_to_file('pdf', '/path/to/save/location.pdf')
|
49
|
+
|
50
|
+
class Presentation < Document
|
51
|
+
DOCUMENT_XML = '<?xml version="1.0" encoding="UTF-8"?>
|
52
|
+
<atom:entry xmlns:atom="http://www.w3.org/2005/Atom">
|
53
|
+
<atom:category scheme="http://schemas.google.com/g/2005#kind"
|
54
|
+
term="http://schemas.google.com/docs/2007#spreadsheet" label="presentation"/>
|
55
|
+
<atom:title></atom:title>
|
56
|
+
</atom:entry>'
|
57
|
+
DOWNLOAD_TYPES = ['pdf', 'png', 'ppt', 'swf', 'txt']
|
58
|
+
EXPORT_URI = 'http://docs.google.com/feeds/download/presentations/Export'
|
59
|
+
|
60
|
+
#Helper function limit queries to Presentations. See BaseObject::find for syntax. Type is not required and assumed to be 'presentation'.
|
61
|
+
def self.find(service, query, args = {})
|
62
|
+
BaseObject::find(service, query, 'presentation', args)
|
63
|
+
end
|
64
|
+
|
65
|
+
#Creates a new Presentation instance. Requires a valid Service object.
|
66
|
+
def initialize(service, attributes = {})
|
67
|
+
super(service, attributes)
|
68
|
+
@xml = DOCUMENT_XML
|
69
|
+
end
|
70
|
+
|
71
|
+
#Retrieves an export of the Presentation. The parameter +type+ must be one of the DOWNLOAD_TYPES
|
72
|
+
def get_content(type)
|
73
|
+
if !@exists
|
74
|
+
raise DocumentDoesntExist
|
75
|
+
end
|
76
|
+
if not DOWNLOAD_TYPES.include? type
|
77
|
+
raise ArgumentError
|
78
|
+
end
|
79
|
+
ret = service.send_request(GData4Ruby::Request.new(:get, EXPORT_URI, nil, nil, {"docID" => @id,"exportFormat" => type}))
|
80
|
+
ret.body
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# Author:: Mike Reich (mike@seabourneconsulting.com)
|
2
|
+
# Copyright:: Copyright (C) 2010 Mike Reich
|
3
|
+
# License:: GPL v2
|
4
|
+
#--
|
5
|
+
# Licensed under the General Public License (GPL), Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
#
|
15
|
+
# Feel free to use and update, but be sure to contribute your
|
16
|
+
# code back to the project and attribute as required by the license.
|
17
|
+
#++
|
18
|
+
require 'gdocs4ruby/base'
|
19
|
+
require 'gdocs4ruby/base_object'
|
20
|
+
require 'gdocs4ruby/folder'
|
21
|
+
require 'gdocs4ruby/document'
|
22
|
+
require 'gdocs4ruby/spreadsheet'
|
23
|
+
require 'gdocs4ruby/presentation'
|
24
|
+
|
25
|
+
module GDocs4Ruby
|
26
|
+
|
27
|
+
DOCUMENT_LIST_FEED = "https://docs.google.com/feeds/documents/private/full"
|
28
|
+
FOLDER_LIST_FEED = "http://docs.google.com/feeds/documents/private/full/-/folder?showfolders=true"
|
29
|
+
|
30
|
+
#The service class is the main handler for all direct interactions with the
|
31
|
+
#Google Documents API. A service represents a single user account. Each user
|
32
|
+
#account can have multiple documents and folders.
|
33
|
+
#=Usage
|
34
|
+
#
|
35
|
+
#1. Authenticate
|
36
|
+
# service = Service.new
|
37
|
+
# service.authenticate("user@gmail.com", "password")
|
38
|
+
#
|
39
|
+
#2. Get Document List
|
40
|
+
# documents = service.files
|
41
|
+
#
|
42
|
+
#3. Get Folder List
|
43
|
+
# folders = serivce.folders
|
44
|
+
#
|
45
|
+
class Service < GData4Ruby::Service
|
46
|
+
#Accepts an optional attributes hash for initialization values
|
47
|
+
def initialize(attributes = {})
|
48
|
+
super(attributes)
|
49
|
+
end
|
50
|
+
|
51
|
+
# The authenticate method passes the username and password to google servers.
|
52
|
+
# If authentication succeeds, returns true, otherwise raises the AuthenticationFailed error.
|
53
|
+
def authenticate(username, password, service='writely')
|
54
|
+
super(username, password, service)
|
55
|
+
end
|
56
|
+
|
57
|
+
#Helper function to reauthenticate to a new Google service without having to re-set credentials.
|
58
|
+
def reauthenticate(service='writely')
|
59
|
+
authenticate(@account, @password, service)
|
60
|
+
end
|
61
|
+
|
62
|
+
#Returns an array of Folder objects for each folder associated with
|
63
|
+
#the authenticated account.
|
64
|
+
def folders
|
65
|
+
if not @auth_token
|
66
|
+
raise NotAuthenticated
|
67
|
+
end
|
68
|
+
ret = send_request(GData4Ruby::Request.new(:get, FOLDER_LIST_FEED))
|
69
|
+
folders = []
|
70
|
+
REXML::Document.new(ret.body).root.elements.each("entry"){}.map do |entry|
|
71
|
+
entry = GData4Ruby::Utils::add_namespaces(entry)
|
72
|
+
folder = Folder.new(self)
|
73
|
+
puts entry.to_s if debug
|
74
|
+
folder.load("<?xml version='1.0' encoding='UTF-8'?>#{entry.to_s}")
|
75
|
+
folders << folder
|
76
|
+
end
|
77
|
+
return folders
|
78
|
+
end
|
79
|
+
|
80
|
+
#Returns an array of objects for each document in the account. Note that this
|
81
|
+
#method will return all documents for the account, including documents contained in
|
82
|
+
#subfolders.
|
83
|
+
def files
|
84
|
+
contents = []
|
85
|
+
ret = send_request(GData4Ruby::Request.new(:get, DOCUMENT_LIST_FEED))
|
86
|
+
xml = REXML::Document.new(ret.body)
|
87
|
+
xml.root.elements.each('entry'){}.map do |ele|
|
88
|
+
ele = GData4Ruby::Utils::add_namespaces(ele)
|
89
|
+
obj = BaseObject.new(self)
|
90
|
+
obj.load(ele.to_s)
|
91
|
+
case obj.type
|
92
|
+
when 'document'
|
93
|
+
doc = Document.new(self)
|
94
|
+
when 'spreadsheet'
|
95
|
+
doc = Spreadsheet.new(self)
|
96
|
+
when 'presentation'
|
97
|
+
doc = Presentation.new(self)
|
98
|
+
end
|
99
|
+
doc.load(ele.to_s)
|
100
|
+
contents << doc
|
101
|
+
end
|
102
|
+
return contents
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# Author:: Mike Reich (mike@seabourneconsulting.com)
|
2
|
+
# Copyright:: Copyright (C) 2010 Mike Reich
|
3
|
+
# License:: GPL v2
|
4
|
+
#--
|
5
|
+
# Licensed under the General Public License (GPL), Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
#
|
15
|
+
# Feel free to use and update, but be sure to contribute your
|
16
|
+
# code back to the project and attribute as required by the license.
|
17
|
+
#++
|
18
|
+
module GDocs4Ruby
|
19
|
+
#The Spreadsheet class represents a Google Spreadsheet. Also check out Document and BaseObject, the superclass of Spreadsheet.
|
20
|
+
#=Usage
|
21
|
+
#All usages assume you've already authenticated with the service, and have a service object called
|
22
|
+
#@service.
|
23
|
+
#1. Create a new Spreadsheet
|
24
|
+
# s = Spreadsheet.new(@service)
|
25
|
+
# s.title = 'Test Spreadsheet'
|
26
|
+
# s.local_file = '/path/to/some/spreadsheet.xls'
|
27
|
+
# s.save
|
28
|
+
#
|
29
|
+
#2. Deleting a Spreadsheet
|
30
|
+
# s = Spreadsheet.find(@service, {:id => @doc_id})
|
31
|
+
# s.delete
|
32
|
+
#
|
33
|
+
#3. Finding an existing Spreadsheet by id
|
34
|
+
# s = Spreadsheet.find(@service, {:id => @doc_id})
|
35
|
+
#
|
36
|
+
#4. Full Text Query
|
37
|
+
# s = Spreadsheet.find(@service, 'content text')
|
38
|
+
#
|
39
|
+
# or
|
40
|
+
#
|
41
|
+
# s = Spreadsheet.find(@service, {:query => 'content text'})
|
42
|
+
#
|
43
|
+
#5. Finding an Existing Spreadsheet by Title
|
44
|
+
# s = Spreadsheet.find(@service, nil, {'title' => 'Test Spreadsheet'})
|
45
|
+
#
|
46
|
+
#6. Retrieving an Export
|
47
|
+
# s = Spreadsheet.find(@service, {:id => @doc_id})
|
48
|
+
# s.download_to_file('pdf', '/path/to/save/location.pdf')
|
49
|
+
|
50
|
+
class Spreadsheet < Document
|
51
|
+
DOCUMENT_XML = '<?xml version="1.0" encoding="UTF-8"?>
|
52
|
+
<atom:entry xmlns:atom="http://www.w3.org/2005/Atom">
|
53
|
+
<atom:category scheme="http://schemas.google.com/g/2005#kind"
|
54
|
+
term="http://schemas.google.com/docs/2007#spreadsheet" label="spreadsheet"/>
|
55
|
+
<atom:title></atom:title>
|
56
|
+
</atom:entry>'
|
57
|
+
DOWNLOAD_TYPES = ['xls', 'csv', 'pdf', 'ods', 'tsv', 'html']
|
58
|
+
EXPORT_URI = 'http://spreadsheets.google.com/feeds/download/spreadsheets/Export'
|
59
|
+
|
60
|
+
#Helper function limit queries to Spreadsheets. See BaseObject::find for syntax. Type is not required and assumed to be 'spreadsheet'.
|
61
|
+
def self.find(service, query, args = {})
|
62
|
+
BaseObject::find(service, query, 'spreadsheet', args)
|
63
|
+
end
|
64
|
+
|
65
|
+
#Creates a new Spreadsheet instance. Requires a valid Service object.
|
66
|
+
def initialize(service, attributes = {})
|
67
|
+
super(service, attributes)
|
68
|
+
@xml = DOCUMENT_XML
|
69
|
+
end
|
70
|
+
|
71
|
+
#Retrieves an export of the Spreadsheet. The parameter +type+ must be one of the DOWNLOAD_TYPES.
|
72
|
+
def get_content(type)
|
73
|
+
if !@exists
|
74
|
+
raise DocumentDoesntExist
|
75
|
+
end
|
76
|
+
if not DOWNLOAD_TYPES.include? type
|
77
|
+
raise ArgumentError
|
78
|
+
end
|
79
|
+
service.reauthenticate('wise')
|
80
|
+
ret = service.send_request(GData4Ruby::Request.new(:get, EXPORT_URI, nil, nil, {"key" => @id.gsub(/\w.*:/, ""),"exportFormat" => type}))
|
81
|
+
service.reauthenticate()
|
82
|
+
ret.body
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/gdocs4ruby.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "gdocs4ruby/service"
|
data/test/unit.rb
ADDED
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gdocs4ruby
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mike Reich
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-03-12 00:00:00 +11:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: gdata4ruby
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.1.0
|
24
|
+
version:
|
25
|
+
description: GDocs4Ruby is a full featured wrapper for version 2.0 of the Google Documents API (aka DocList). GDocs4Ruby provides the ability to create, update and delete google documents, metadata and content. The gem also includes support for folders, modifying permissions for documents via ACL feeds, and much more.
|
26
|
+
email: mike@seabourneconsulting.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- README
|
35
|
+
- CHANGELOG
|
36
|
+
- lib/gdocs4ruby.rb
|
37
|
+
- lib/gdocs4ruby/service.rb
|
38
|
+
- lib/gdocs4ruby/folder.rb
|
39
|
+
- lib/gdocs4ruby/document.rb
|
40
|
+
- lib/gdocs4ruby/base_object.rb
|
41
|
+
- lib/gdocs4ruby/spreadsheet.rb
|
42
|
+
- lib/gdocs4ruby/presentation.rb
|
43
|
+
has_rdoc: true
|
44
|
+
homepage: http://gdocs4ruby.rubyforge.org/
|
45
|
+
licenses: []
|
46
|
+
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: "0"
|
63
|
+
version:
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
rubyforge_project: gdocs4ruby
|
67
|
+
rubygems_version: 1.3.5
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: A full featured wrapper for interacting with the Google Docs API
|
71
|
+
test_files:
|
72
|
+
- test/unit.rb
|