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,100 @@
1
+ # Author: Guy Boertje <https://github.com/guyboertje>
2
+ # Author: David R. Albrecht <https://github.com/eldavido>
3
+ # Author: Hiroshi Ichikawa <http://gimite.net/>
4
+ # Author: Phuogn Nguyen <https://github.com/phuongnd08>
5
+ # The license of this source is "New BSD Licence"
6
+
7
+ module GoogleDriveV1
8
+
9
+ # An entry of an ACL (access control list) of a spreadsheet.
10
+ #
11
+ # Use GoogleDriveV1::Acl#[] to get GoogleDriveV1::AclEntry object.
12
+ #
13
+ # This code is based on https://github.com/guyboertje/gdata-spreadsheet-ruby .
14
+ class AclEntry
15
+
16
+ include(Util)
17
+
18
+ PARAM_NAMES = [:acl, :scope_type, :scope, :with_key, :role, :title, :edit_url, :etag] #:nodoc:
19
+
20
+ # +params+ is a Hash object with keys +:scope_type+, +:scope+ and +:role+.
21
+ # See scope_type and role for the document of the fields.
22
+ def initialize(params)
23
+ @params = {:role => "reader"}
24
+ for name, value in params
25
+ if !name.is_a?(Symbol)
26
+ raise(ArgumentError, "Key must be Symbol, but is %p" % name)
27
+ elsif !PARAM_NAMES.include?(name)
28
+ raise(ArgumentError, "Invalid key: %p" % name)
29
+ end
30
+ @params[name] = value
31
+ end
32
+ end
33
+
34
+ attr_accessor(:params) #:nodoc:
35
+
36
+ PARAM_NAMES.each() do |name|
37
+ define_method(name) do
38
+ return @params[name]
39
+ end
40
+ end
41
+
42
+ def edit_url
43
+ warn(
44
+ "WARNING: GoogleDriveV1::AclEntry\#edit_url is deprecated and will be removed in the next version.")
45
+ return self.edit_url_internal
46
+ end
47
+
48
+ def edit_url_internal #:nodoc:
49
+ return @params[:edit_url]
50
+ end
51
+
52
+ # Changes the role of the scope.
53
+ #
54
+ # e.g.
55
+ # spreadsheet.acl[1].role = "writer"
56
+ def role=(role)
57
+ @params[:role] = role
58
+ @params[:acl].update_role(self)
59
+ end
60
+
61
+ def inspect
62
+ return "\#<%p scope_type=%p, scope=%p, with_key=%p, role=%p>" %
63
+ [self.class, @params[:scope_type], @params[:scope], @params[:with_key], @params[:role]]
64
+ end
65
+
66
+ def to_xml() #:nodoc:
67
+
68
+ etag_attr = self.etag ? "gd:etag='#{h(self.etag)}'" : ""
69
+ value_attr = self.scope ? "value='#{h(self.scope)}'" : ""
70
+ if self.with_key
71
+ role_tag = <<-EOS
72
+ <gAcl:withKey key='[ACL KEY]'>
73
+ <gAcl:role value='#{h(self.role)}'/>
74
+ </gAcl:withKey>
75
+ EOS
76
+ else
77
+ role_tag = <<-EOS
78
+ <gAcl:role value='#{h(self.role)}'/>
79
+ EOS
80
+ end
81
+
82
+ return <<-EOS
83
+ <entry
84
+ xmlns='http://www.w3.org/2005/Atom'
85
+ xmlns:gAcl='http://schemas.google.com/acl/2007'
86
+ xmlns:gd='http://schemas.google.com/g/2005'
87
+ #{etag_attr}>
88
+ <category scheme='http://schemas.google.com/g/2005#kind'
89
+ term='http://schemas.google.com/acl/2007#accessRule'/>
90
+ #{role_tag}
91
+ <gAcl:scope type='#{h(self.scope_type)}' #{value_attr}/>
92
+ </entry>
93
+ EOS
94
+
95
+ end
96
+
97
+ end
98
+
99
+ end
100
+
@@ -0,0 +1,47 @@
1
+ # Author: Hiroshi Ichikawa <http://gimite.net/>
2
+ # The license of this source is "New BSD Licence"
3
+
4
+ require "net/https"
5
+ require "uri"
6
+ Net::HTTP.version_1_2
7
+
8
+
9
+ module GoogleDriveV1
10
+
11
+ class ApiClientFetcher
12
+
13
+ class Response
14
+
15
+ def initialize(client_response)
16
+ @client_response = client_response
17
+ end
18
+
19
+ def code
20
+ return @client_response.status.to_s()
21
+ end
22
+
23
+ def body
24
+ return @client_response.body
25
+ end
26
+
27
+ end
28
+
29
+ def initialize(client)
30
+ @client = client
31
+ end
32
+
33
+ attr_reader(:client)
34
+
35
+ def request_raw(method, url, data, extra_header, auth)
36
+ p [method, url, data, extra_header, auth]
37
+ client_response = @client.execute(
38
+ :http_method => method,
39
+ :uri => url,
40
+ :body => data,
41
+ :headers => extra_header)
42
+ return Response.new(client_response)
43
+ end
44
+
45
+ end
46
+
47
+ end
@@ -0,0 +1,14 @@
1
+ # Author: Hiroshi Ichikawa <http://gimite.net/>
2
+ # The license of this source is "New BSD Licence"
3
+
4
+ require "google_drive_v1/error"
5
+
6
+
7
+ module GoogleDriveV1
8
+
9
+ # Raised when GoogleDriveV1.login has failed.
10
+ class AuthenticationError < GoogleDriveV1::Error
11
+
12
+ end
13
+
14
+ end
@@ -6,7 +6,7 @@ require "uri"
6
6
  Net::HTTP.version_1_2
7
7
 
8
8
 
9
- module GoogleDrive
9
+ module GoogleDriveV1
10
10
 
11
11
  class BasicFetcher #:nodoc:
12
12
 
@@ -1,10 +1,10 @@
1
1
  # Author: Hiroshi Ichikawa <http://gimite.net/>
2
2
  # The license of this source is "New BSD Licence"
3
3
 
4
- require "google_drive/basic_fetcher"
4
+ require "google_drive_v1/basic_fetcher"
5
5
 
6
6
 
7
- module GoogleDrive
7
+ module GoogleDriveV1
8
8
 
9
9
  class ClientLoginFetcher < BasicFetcher #:nodoc:
10
10
 
@@ -0,0 +1,167 @@
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/spreadsheet"
7
+
8
+
9
+ module GoogleDriveV1
10
+
11
+ # Use GoogleDriveV1::Session#root_collection, GoogleDriveV1::Collection#subcollections,
12
+ # or GoogleDriveV1::Session#collection_by_url to get GoogleDriveV1::Collection object.
13
+ class Collection < GoogleDriveV1::File
14
+
15
+ include(Util)
16
+
17
+ ROOT_URL = "#{DOCS_BASE_URL}/folder%3Aroot" #:nodoc:
18
+
19
+ alias collection_feed_url document_feed_url
20
+
21
+ def contents_url
22
+ if self.root?
23
+ # The root collection doesn't have document feed.
24
+ return concat_url(ROOT_URL, "/contents")
25
+ else
26
+ return self.document_feed_entry_internal.css(
27
+ "content[type='application/atom+xml;type=feed']")[0]["src"]
28
+ end
29
+ end
30
+
31
+ # Title of the collection.
32
+ #
33
+ # Set <tt>params[:reload]</tt> to true to force reloading the title.
34
+ def title(params = {})
35
+ if self.root?
36
+ # The root collection doesn't have document feed.
37
+ return nil
38
+ else
39
+ return super
40
+ end
41
+ end
42
+
43
+ def resource_id
44
+ return self.root? ? nil : super
45
+ end
46
+
47
+ # Adds the given GoogleDriveV1::File to the collection.
48
+ def add(file)
49
+ header = {"GData-Version" => "3.0", "Content-Type" => "application/atom+xml;charset=utf-8"}
50
+ xml = <<-"EOS"
51
+ <entry xmlns="http://www.w3.org/2005/Atom">
52
+ <id>#{h(file.document_feed_url)}</id>
53
+ </entry>
54
+ EOS
55
+ @session.request(
56
+ :post, self.contents_url, :data => xml, :header => header, :auth => :writely)
57
+ return nil
58
+ end
59
+
60
+ # Creates a sub-collection with given title. Returns GoogleDriveV1::Collection object.
61
+ def create_subcollection(title)
62
+ header = {"GData-Version" => "3.0", "Content-Type" => "application/atom+xml;charset=utf-8"}
63
+ xml = <<-EOS
64
+ <entry xmlns="http://www.w3.org/2005/Atom">
65
+ <category scheme="http://schemas.google.com/g/2005#kind"
66
+ term="http://schemas.google.com/docs/2007#folder"/>
67
+ <title>#{h(title)}</title>
68
+ </entry>
69
+ EOS
70
+ doc = @session.request(
71
+ :post, contents_url, :data => xml, :header => header, :auth => :writely)
72
+ return @session.entry_element_to_file(doc)
73
+ end
74
+
75
+ # Removes the given GoogleDriveV1::File from the collection.
76
+ def remove(file)
77
+ url = to_v3_url("#{contents_url}/#{file.resource_id}")
78
+ @session.request(:delete, url, :auth => :writely, :header => {"If-Match" => "*"})
79
+ end
80
+
81
+ # Returns true if this is a root collection
82
+ def root?
83
+ self.document_feed_url == ROOT_URL
84
+ end
85
+
86
+ # Returns all the files (including spreadsheets, documents, subcollections) in the collection.
87
+ #
88
+ # You can specify query parameters described at
89
+ # https://developers.google.com/google-apps/documents-list/#getting_a_list_of_documents_and_files
90
+ #
91
+ # e.g.
92
+ #
93
+ # # Gets all the files in collection, including subcollections.
94
+ # collection.files
95
+ #
96
+ # # Gets only files with title "hoge".
97
+ # collection.files("title" => "hoge", "title-exact" => "true")
98
+ def files(params = {})
99
+ return files_with_type(nil, params)
100
+ end
101
+
102
+ alias contents files
103
+
104
+ # Returns all the spreadsheets in the collection.
105
+ def spreadsheets(params = {})
106
+ return files_with_type("spreadsheet", params)
107
+ end
108
+
109
+ # Returns all the Google Docs documents in the collection.
110
+ def documents(params = {})
111
+ return files_with_type("document", params)
112
+ end
113
+
114
+ # Returns all its subcollections.
115
+ def subcollections(params = {})
116
+ return files_with_type("folder", params)
117
+ end
118
+
119
+ # Returns a file (can be a spreadsheet, document, subcollection or other files) in the
120
+ # collection which exactly matches +title+ as GoogleDriveV1::File.
121
+ # Returns nil if not found. If multiple collections with the +title+ are found, returns
122
+ # one of them.
123
+ #
124
+ # If given an Array, does a recursive subcollection traversal.
125
+ def file_by_title(title)
126
+ return file_by_title_with_type(title, nil)
127
+ end
128
+
129
+ # Returns its subcollection whose title exactly matches +title+ as GoogleDriveV1::Collection.
130
+ # Returns nil if not found. If multiple collections with the +title+ are found, returns
131
+ # one of them.
132
+ #
133
+ # If given an Array, does a recursive subcollection traversal.
134
+ def subcollection_by_title(title)
135
+ return file_by_title_with_type(title, "folder")
136
+ end
137
+
138
+ protected
139
+
140
+ def file_by_title_with_type(title, type)
141
+ if title.is_a?(Array)
142
+ rel_path = title
143
+ if rel_path.empty?
144
+ return self
145
+ else
146
+ parent = subcollection_by_title(rel_path[0...-1])
147
+ return parent && parent.file_by_title_with_type(rel_path[-1], type)
148
+ end
149
+ else
150
+ return files_with_type(type, "title" => title, "title-exact" => "true")[0]
151
+ end
152
+ end
153
+
154
+ private
155
+
156
+ def files_with_type(type, params = {})
157
+ contents_url = self.contents_url
158
+ contents_url = concat_url(contents_url, "/-/#{type}") if type
159
+ contents_url = concat_url(contents_url, "?" + encode_query(params))
160
+ header = {"GData-Version" => "3.0", "Content-Type" => "application/atom+xml;charset=utf-8"}
161
+ doc = @session.request(:get, contents_url, :header => header, :auth => :writely)
162
+ return doc.css("feed > entry").map(){ |e| @session.entry_element_to_file(e) }
163
+ end
164
+
165
+ end
166
+
167
+ end
@@ -0,0 +1,12 @@
1
+ # Author: Hiroshi Ichikawa <http://gimite.net/>
2
+ # The license of this source is "New BSD Licence"
3
+
4
+
5
+ module GoogleDriveV1
6
+
7
+ # Raised when spreadsheets.google.com has returned error.
8
+ class Error < RuntimeError
9
+
10
+ end
11
+
12
+ end
@@ -0,0 +1,258 @@
1
+ # Author: Hiroshi Ichikawa <http://gimite.net/>
2
+ # The license of this source is "New BSD Licence"
3
+
4
+ require "cgi"
5
+ require "stringio"
6
+
7
+ require "google_drive_v1/util"
8
+ require "google_drive_v1/acl"
9
+
10
+
11
+ module GoogleDriveV1
12
+
13
+ # A file in Google Drive, including Google Docs document/spreadsheet/presentation.
14
+ #
15
+ # Use GoogleDriveV1::Session#files or GoogleDriveV1::Session#file_by_title to
16
+ # get this object.
17
+ class File
18
+
19
+ include(Util)
20
+
21
+ def initialize(session, entry_or_url) #:nodoc:
22
+ @session = session
23
+ if !entry_or_url
24
+ # TODO Delete this after editing spreadsheet.rb.
25
+ @document_feed_entry = nil
26
+ @document_feed_url = entry_or_url
27
+ elsif entry_or_url.is_a?(String)
28
+ @document_feed_entry = nil
29
+ @document_feed_url = entry_or_url
30
+ else
31
+ @document_feed_entry = entry_or_url
32
+ # This is usually equal to the URL in <link rel="self">. But the URL in
33
+ # <link rel="self"> in collection feed is e.g.
34
+ # https://docs.google.com/feeds/default/private/full/folder%3Aroot/contents/folder%3Axxx
35
+ # and deletion of the URL doesn't delete the file itself.
36
+ # So we construct the URL here using resource ID instead.
37
+ @document_feed_url = "%s/%s?v=3" % [DOCS_BASE_URL, CGI.escape(self.resource_id)]
38
+ end
39
+ @acl = nil
40
+ end
41
+
42
+ # URL of feed used in document list feed API.
43
+ attr_reader(:document_feed_url)
44
+
45
+ # <entry> element of document list feed as Nokogiri::XML::Element.
46
+ #
47
+ # Set <tt>params[:reload]</tt> to true to force reloading the feed.
48
+ def document_feed_entry(params = {})
49
+ warn(
50
+ "WARNING: GoogleDriveV1::file\#document_feed_entry is deprecated and will be removed " +
51
+ "in the next version.")
52
+ return self.document_feed_entry_internal(params)
53
+ end
54
+
55
+ def document_feed_entry_internal(params = {}) #:nodoc:
56
+ if !@document_feed_entry || params[:reload]
57
+ @document_feed_entry =
58
+ @session.request(:get, self.document_feed_url, :auth => :writely).css("entry")[0]
59
+ end
60
+ return @document_feed_entry
61
+ end
62
+
63
+ # Resource ID.
64
+ def resource_id
65
+ return self.document_feed_entry_internal.css("gd|resourceId").text
66
+ end
67
+
68
+ # The type of resourse. e.g. "document", "spreadsheet", "folder"
69
+ def resource_type
70
+ return self.resource_id.split(/:/)[0]
71
+ end
72
+
73
+ # Title of the file.
74
+ #
75
+ # Set <tt>params[:reload]</tt> to true to force reloading the title.
76
+ def title(params = {})
77
+ return document_feed_entry_internal(params).css("title").text
78
+ end
79
+
80
+ # URL to view/edit the file in a Web browser.
81
+ #
82
+ # e.g. "https://docs.google.com/file/d/xxxx/edit"
83
+ def human_url
84
+ return self.document_feed_entry_internal.css("link[rel='alternate']")[0]["href"]
85
+ end
86
+
87
+ # ACL feed URL of the file.
88
+ def acl_feed_url
89
+ orig_acl_feed_url = self.document_feed_entry_internal.css(
90
+ "gd|feedLink[rel='http://schemas.google.com/acl/2007#accessControlList']")[0]["href"]
91
+ case orig_acl_feed_url
92
+ when %r{^https?://docs.google.com/feeds/default/private/full/.*/acl(\?.*)?$}
93
+ return orig_acl_feed_url
94
+ when %r{^https?://docs.google.com/feeds/acl/private/full/([^\?]*)(\?.*)?$}
95
+ # URL of old API version. Converts to v3 URL.
96
+ return "#{DOCS_BASE_URL}/#{$1}/acl"
97
+ else
98
+ raise(GoogleDriveV1::Error,
99
+ "ACL feed URL is in unknown format: #{orig_acl_feed_url}")
100
+ end
101
+ end
102
+
103
+ # Content types you can specify in methods download_to_file, download_to_string,
104
+ # download_to_io .
105
+ def available_content_types
106
+ return self.document_feed_entry_internal.css("content").map(){ |c| c["type"] }
107
+ end
108
+
109
+ # Downloads the file to a local file.
110
+ #
111
+ # e.g.
112
+ # file.download_to_file("/path/to/hoge.txt")
113
+ # file.download_to_file("/path/to/hoge", :content_type => "text/plain")
114
+ def download_to_file(path, params = {})
115
+ params = params.dup()
116
+ if !params[:content_type]
117
+ params[:content_type] = EXT_TO_CONTENT_TYPE[::File.extname(path).downcase]
118
+ params[:content_type_is_hint] = true
119
+ end
120
+ open(path, "wb") do |f|
121
+ download_to_io(f, params)
122
+ end
123
+ end
124
+
125
+ # Downloads the file and returns as a String.
126
+ #
127
+ # e.g.
128
+ # file.download_to_string() #=> "Hello world."
129
+ # file.download_to_string(:content_type => "text/plain") #=> "Hello world."
130
+ def download_to_string(params = {})
131
+ sio = StringIO.new()
132
+ download_to_io(sio, params)
133
+ return sio.string
134
+ end
135
+
136
+ # Downloads the file and writes it to +io+.
137
+ def download_to_io(io, params = {})
138
+ all_contents = self.document_feed_entry_internal.css("content")
139
+ if params[:content_type] && (!params[:content_type_is_hint] || all_contents.size > 1)
140
+ contents = all_contents.select(){ |c| c["type"] == params[:content_type] }
141
+ else
142
+ contents = all_contents
143
+ end
144
+ if contents.size == 1
145
+ url = contents[0]["src"]
146
+ else
147
+ if contents.empty?
148
+ raise(GoogleDriveV1::Error,
149
+ ("Downloading with content type %p not supported for this file. " +
150
+ "Specify one of these to content_type: %p") %
151
+ [params[:content_type], self.available_content_types])
152
+ else
153
+ raise(GoogleDriveV1::Error,
154
+ ("Multiple content types are available for this file. " +
155
+ "Specify one of these to content_type: %p") %
156
+ [self.available_content_types])
157
+ end
158
+ end
159
+ # TODO Use streaming if possible.
160
+ body = @session.request(:get, url, :response_type => :raw, :auth => :writely)
161
+ io.write(body)
162
+ end
163
+
164
+ # Updates the file with the content of the local file.
165
+ #
166
+ # e.g.
167
+ # file.update_from_file("/path/to/hoge.txt")
168
+ def update_from_file(path, params = {})
169
+ params = {:file_name => ::File.basename(path)}.merge(params)
170
+ open(path, "rb") do |f|
171
+ update_from_io(f, params)
172
+ end
173
+ end
174
+
175
+ # Updates the file with +content+.
176
+ #
177
+ # e.g.
178
+ # file.update_from_string("Good bye, world.")
179
+ def update_from_string(content, params = {})
180
+ update_from_io(StringIO.new(content), params)
181
+ end
182
+
183
+ # Reads content from +io+ and updates the file with the content.
184
+ def update_from_io(io, params = {})
185
+ params = {:header => {"If-Match" => "*"}}.merge(params)
186
+ initial_url = self.document_feed_entry_internal.css(
187
+ "link[rel='http://schemas.google.com/g/2005#resumable-edit-media']")[0]["href"]
188
+ @document_feed_entry = @session.upload_raw(
189
+ :put, initial_url, io, self.title, params)
190
+ end
191
+
192
+ # If +permanent+ is +false+, moves the file to the trash.
193
+ # If +permanent+ is +true+, deletes the file permanently.
194
+ def delete(permanent = false)
195
+ url = to_v3_url(self.document_feed_url)
196
+ url = concat_url(url, "?delete=true") if permanent
197
+ @session.request(:delete, url,
198
+ :auth => :writely, :header => {"If-Match" => "*"})
199
+ end
200
+
201
+ # Renames title of the file.
202
+ def rename(title)
203
+ edit_url = self.document_feed_entry_internal.css("link[rel='edit']").first["href"]
204
+ xml = <<-"EOS"
205
+ <atom:entry
206
+ xmlns:atom="http://www.w3.org/2005/Atom"
207
+ xmlns:docs="http://schemas.google.com/docs/2007">
208
+ <atom:title>#{h(title)}</atom:title>
209
+ </atom:entry>
210
+ EOS
211
+ header = {"Content-Type" => "application/atom+xml;charset=utf-8", "If-Match" => "*"}
212
+ @session.request(:put, edit_url, :data => xml, :auth => :writely, :header => header)
213
+ end
214
+
215
+ alias title= rename
216
+
217
+ # Returns GoogleDriveV1::Acl object for the file.
218
+ #
219
+ # With the object, you can see and modify people who can access the file.
220
+ # Modifications take effect immediately.
221
+ #
222
+ # Set <tt>params[:reload]</tt> to true to force reloading the data.
223
+ #
224
+ # e.g.
225
+ # # Dumps people who have access:
226
+ # for entry in file.acl
227
+ # p [entry.scope_type, entry.scope, entry.role]
228
+ # # => e.g. ["user", "example1@gmail.com", "owner"]
229
+ # end
230
+ #
231
+ # # Shares the file with new people:
232
+ # # NOTE: This sends email to the new people.
233
+ # file.acl.push(
234
+ # {:scope_type => "user", :scope => "example2@gmail.com", :role => "reader"})
235
+ # file.acl.push(
236
+ # {:scope_type => "user", :scope => "example3@gmail.com", :role => "writer"})
237
+ #
238
+ # # Changes the role of a person:
239
+ # file.acl[1].role = "writer"
240
+ #
241
+ # # Deletes an ACL entry:
242
+ # file.acl.delete(file.acl[1])
243
+ def acl(params = {})
244
+ if !@acl || params[:reload]
245
+ @acl = Acl.new(@session, self.acl_feed_url)
246
+ end
247
+ return @acl
248
+ end
249
+
250
+ def inspect
251
+ fields = {:document_feed_url => self.document_feed_url}
252
+ fields[:title] = self.title if @document_feed_entry
253
+ return "\#<%p %s>" % [self.class, fields.map(){ |k, v| "%s=%p" % [k, v] }.join(", ")]
254
+ end
255
+
256
+ end
257
+
258
+ end