rscribd 1.0.3 → 1.0.4

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.
@@ -0,0 +1,5 @@
1
+ doc
2
+ *.gemspec
3
+ pkg
4
+ .idea
5
+ .DS_Store
@@ -1,3 +1,8 @@
1
+ === 1.0.4 / 2009-7-24
2
+
3
+ * Offset and limit parameters can now be used when fetching user documents.
4
+ * Minor bug fixes.
5
+
1
6
  === 1.0.3 / 2009-7-13
2
7
 
3
8
  * Removed unnecessary post parameters from API calls.
data/Rakefile CHANGED
@@ -1,29 +1,25 @@
1
1
  require 'rubygems'
2
- require 'hoe'
3
2
  require 'spec/rake/spectask'
4
3
 
5
- Hoe.spec('rscribd') do |p|
6
- p.version = '1.0.3'
7
- p.rubyforge_name = 'rscribd'
8
- p.author = 'Jared Friedman, Tim Morgan'
9
- p.email = 'api@scribd.com'
10
- p.summary = 'Ruby client library for the Scribd API'
11
- p.description = p.paragraphs_of('README.txt', 3).join("\n\n")
12
- p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
13
- p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
14
- p.extra_deps << [ 'mime-types', '>0.0.0' ]
15
- p.remote_rdoc_dir = ''
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gemspec|
7
+ gemspec.name = "rscribd"
8
+ gemspec.summary = "Ruby client library for the Scribd API"
9
+ gemspec.description = "The official Ruby gem for the Scribd API. Scribd is a document-sharing website allowing people to upload and view documents online."
10
+ gemspec.email = "api@scribd.com"
11
+ gemspec.homepage = "http://www.scribd.com/developers"
12
+ gemspec.authors = [ "Tim Morgan", "Jared Friedman", "Mike Watts" ]
13
+
14
+ gemspec.add_dependency 'mime-types'
15
+ gemspec.add_development_dependency "rspec"
16
+ end
17
+ rescue LoadError
18
+ puts "Jeweler not available. Install it with: gem install jeweler"
16
19
  end
17
20
 
18
- # desc "Verify gem specs"
19
- # Spec::Rake::SpecTask.new do |t|
20
- # t.spec_files = FileList['spec/*.rb']
21
- # t.spec_opts = [ '-cfs' ]
22
- # end
23
-
24
- namespace :github do
25
- desc "Prepare for GitHub gem packaging"
26
- task :prepare do
27
- `rake debug_gem > rscribd.gemspec`
28
- end
29
- end
21
+ desc "Verify gem specs"
22
+ Spec::Rake::SpecTask.new do |t|
23
+ t.spec_files = FileList['spec/*.rb']
24
+ t.spec_opts = [ '-cfs' ]
25
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.4
@@ -91,15 +91,16 @@ module Scribd
91
91
  def save
92
92
  if not created? and @attributes[:file].nil? then
93
93
  raise "'file' attribute must be specified for new documents"
94
- return false
95
94
  end
96
95
 
97
96
  if created? and @attributes[:file] and (@attributes[:owner].nil? or @attributes[:owner].session_key.nil?) then
98
97
  raise PrivilegeError, "The current API user is not the owner of this document"
99
98
  end
100
-
99
+
101
100
  # Make a request form
101
+ response = nil
102
102
  fields = @attributes.dup
103
+ fields[:session_key] = fields.delete(:owner).session_key if fields[:owner]
103
104
  if file = @attributes[:file] then
104
105
  fields.delete :file
105
106
  is_file_object = file.is_a?(File)
@@ -110,12 +111,7 @@ module Scribd
110
111
  fields[:doc_type] ||= ext
111
112
  fields[:doc_type].downcase! if fields[:doc_type]
112
113
  fields[:rev_id] = fields.delete(:doc_id)
113
- end
114
- fields[:session_key] = fields.delete(:owner).session_key if fields[:owner]
115
- response = nil
116
-
117
- if @attributes[:file] then
118
- uri = nil
114
+
119
115
  begin
120
116
  uri = URI.parse @attributes[:file]
121
117
  rescue URI::InvalidURIError
@@ -141,9 +137,9 @@ module Scribd
141
137
  @created = true
142
138
  end
143
139
 
140
+ fields.delete :access if fields[:file] # when uploading a doc, don't send access twice
144
141
  fields.delete :file
145
142
  fields.delete :type
146
- fields.delete :access
147
143
  fields.delete :conversion_status
148
144
 
149
145
  changed_attributes = fields.dup # changed_attributes is what we will stick into @attributes once we update remotely
@@ -207,7 +203,7 @@ module Scribd
207
203
  # this manner.
208
204
 
209
205
  def self.find(scope, options={})
210
- doc_id = scope if scope.kind_of?(Integer)
206
+ doc_id = scope.kind_of?(Integer) ? scope : nil
211
207
  raise ArgumentError, "You must specify a query or document ID" unless options[:query] or doc_id
212
208
 
213
209
  if doc_id then
@@ -247,7 +243,18 @@ module Scribd
247
243
  response = API.instance.send_request('docs.getConversionStatus', :doc_id => self.id)
248
244
  response.elements['/rsp/conversion_status'].text
249
245
  end
250
-
246
+
247
+ # Returns the document read count. This is only retrieved from the server the first time it's queried.
248
+ # To force re-retrieval on subsequent calls include :force => true in the options parameter.
249
+
250
+ def reads(options = {})
251
+ if @reads.nil? || options[:force]
252
+ response = API.instance.send_request('docs.getStats', :doc_id => self.id)
253
+ @reads = response.elements['/rsp/reads'].text
254
+ end
255
+ @reads
256
+ end
257
+
251
258
  # Deletes a document. Returns true if successful.
252
259
 
253
260
  def destroy
@@ -12,14 +12,14 @@ module Net #:nodoc:all
12
12
  boundary_token = [Array.new(8) {rand(256)}].join
13
13
  self.content_type = "multipart/form-data; boundary=#{boundary_token}"
14
14
  boundary_marker = "--#{boundary_token}\r\n"
15
- self.body = param_hash.map { |param_name, param_value|
15
+ self.body = param_hash.map do |param_name, param_value|
16
16
  boundary_marker + case param_value
17
17
  when File
18
18
  file_to_multipart(param_name, param_value)
19
19
  else
20
20
  text_to_multipart(param_name, param_value.to_s)
21
21
  end
22
- }.join('') + "--#{boundary_token}--\r\n"
22
+ end.join('') + "--#{boundary_token}--\r\n"
23
23
  end
24
24
 
25
25
  protected
@@ -56,7 +56,9 @@ module Scribd
56
56
  end
57
57
  end
58
58
 
59
- # Returns a list of all documents owned by this user. This list is _not_
59
+ # Returns a list of documents owned by this user. By default, the size of the returned
60
+ # list is capped at 1000. Use the :limit and :offset parameters to page through this
61
+ # user's documents, however :limit cannot be greater than 1000. This list is _not_
60
62
  # backed by the server, so if you add or remove items from it, it will not
61
63
  # make those changes server-side. This also has some tricky consequences
62
64
  # when modifying a list of documents while iterating over it:
@@ -71,8 +73,8 @@ module Scribd
71
73
  # additional attributes are documented online at
72
74
  # http://www.scribd.com/publisher/api?method_name=docs.getSettings
73
75
 
74
- def documents
75
- response = API.instance.send_request('docs.getList', { :session_key => @attributes[:session_key] })
76
+ def documents(options = {})
77
+ response = API.instance.send_request('docs.getList', options.merge(:session_key => @attributes[:session_key]))
76
78
  documents = Array.new
77
79
  response.elements['/rsp/resultset'].elements.each do |doc|
78
80
  documents << Document.new(:xml => doc, :owner => self)
@@ -0,0 +1,131 @@
1
+ old_dir = Dir.getwd
2
+ Dir.chdir(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'rscribd'
4
+
5
+ describe Scribd::API do
6
+ it "should be a singleton" do
7
+ Scribd::API.instance.should be_kind_of(Scribd::API)
8
+ lambda { Scribd::API.new }.should raise_error(NoMethodError)
9
+ end
10
+
11
+ describe "with the API key and secret in ENV" do
12
+ before :each do
13
+ ENV['SCRIBD_API_KEY'] = 'env key'
14
+ ENV['SCRIBD_API_SECRET'] = 'env sec'
15
+ @api = Scribd::API.send(:new)
16
+ end
17
+
18
+ it "should set the API key and secret accordingly" do
19
+ @api.key.should eql('env key')
20
+ @api.secret.should eql('env sec')
21
+ end
22
+
23
+ it "should favor local API key and secret settings" do
24
+ @api.key = 'test key'
25
+ @api.secret = 'test sec'
26
+ @api.key.should eql('test key')
27
+ @api.secret.should eql('test sec')
28
+ end
29
+ end
30
+
31
+ describe "freshly reset" do
32
+ before :each do
33
+ ENV['SCRIBD_API_KEY'] = nil
34
+ ENV['SCRIBD_API_SECRET'] = nil
35
+ # reset the singleton; total hack
36
+ @api = Scribd::API.send(:new)
37
+ end
38
+
39
+ it "should raise NotReadyError when send_request is called" do
40
+ lambda { @api.send_request('blah', {}) }.should raise_error(Scribd::NotReadyError)
41
+ end
42
+
43
+ describe "with a key and secret set" do
44
+ before :each do
45
+ @api.key = 'test key'
46
+ @api.secret = 'test sec'
47
+ end
48
+
49
+ it "should have the correct API key and secret" do
50
+ @api.key.should eql('test key')
51
+ @api.secret.should eql('test sec')
52
+ end
53
+
54
+ it "should raise ArgumentError if the method is empty" do
55
+ lambda { @api.send_request(nil, {}) }.should raise_error(ArgumentError)
56
+ lambda { @api.send_request('', {}) }.should raise_error(ArgumentError)
57
+ end
58
+
59
+ describe "with a mocked Net::HTTP" do
60
+ before :each do
61
+ @response = mock('Net::HTTP::Response @response')
62
+ @response.stub!(:body).and_return("<rsp stat='ok'/>")
63
+
64
+ @http = Net::HTTP.new('http://www.example.com', 80)
65
+ @http.stub!(:request).and_return(@response)
66
+ Net::HTTP.stub!(:new).and_return(@http)
67
+
68
+ @request = Net::HTTP::Post.new('/test')
69
+ Net::HTTP::Post.stub!(:new).and_return(@request)
70
+ end
71
+
72
+ it "should set a nice, long read timeout" do
73
+ @api.send_request('test', {})
74
+ @http.read_timeout.should >= 60
75
+ end
76
+
77
+ it "should set the multipart parameters to the given fields" do
78
+ fields = { :field1 => 1, :field2 => 'hi' }
79
+ @api.send_request('test', fields)
80
+ body = @request.body
81
+ fields.each do |key, value|
82
+ serial_str = <<-EOF
83
+ Content-Disposition: form-data; name=#{key.to_s.inspect}
84
+
85
+ #{value.to_s}
86
+ EOF
87
+ body.should include(serial_str.gsub(/\n/, "\r\n"))
88
+ end
89
+ end
90
+
91
+ # it "should attempt to make the request 3 times" do
92
+ # @http.stub!(:request).and_raise Exception
93
+ # @http.should_receive(:request).exactly(3).times
94
+ # lambda { @api.send_request('test', {}) }.should raise_error
95
+ # end
96
+
97
+ it "should raise MalformedResponseError if the response doesn't have an rsp tag as its root" do
98
+ @response.stub!(:body).and_return("<invalid/>")
99
+ lambda { @api.send_request('test', {}) }.should raise_error(Scribd::MalformedResponseError)
100
+ end
101
+
102
+ it "should raise a ResponseError for error responses" do
103
+ @response.stub!(:body).and_return("<rsp stat='fail'><error code='123' message='testmsg' /></rsp>")
104
+ lambda { @api.send_request('testmeth', {}) }.should raise_error(Scribd::ResponseError) { |error|
105
+ error.code.should eql("123")
106
+ error.message.should eql('Method: testmeth Response: code=123 message=testmsg')
107
+ }
108
+ end
109
+
110
+ it "should return the REXML doc for successful responses" do
111
+ @response.stub!(:body).and_return("<rsp stat='ok'><element attr='val'><otherelem>val2</otherelem></element></rsp>")
112
+ @api.send_request('testmeth', {}).should be_kind_of(REXML::Document)
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ it "should not be asynchronous by default" do
119
+ Scribd::API.instance.asynchronous.should_not be_true
120
+ end
121
+
122
+ it "should not be in debug mode by default" do
123
+ Scribd::API.instance.instance_variable_get(:@debug).should_not be_true
124
+ end
125
+
126
+ it "should have a user by default" do
127
+ Scribd::API.instance.user.should_not be_nil
128
+ end
129
+ end
130
+
131
+ Dir.chdir old_dir
@@ -0,0 +1,557 @@
1
+ old_dir = Dir.getwd
2
+ Dir.chdir(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'rscribd'
4
+
5
+ describe Scribd::Document do
6
+ before :each do
7
+ Scribd::API.instance.key = 'test key'
8
+ Scribd::API.instance.secret = 'test sec'
9
+ end
10
+
11
+ describe "initialized from attributes" do
12
+ before :each do
13
+ @document = Scribd::Document.new(:access => 'private', :title => 'mytitle')
14
+ end
15
+
16
+ it "should have its attributes set appropriately" do
17
+ @document.access.should eql('private')
18
+ @document.title.should eql('mytitle')
19
+ end
20
+
21
+ it "should be unsaved" do
22
+ @document.should_not be_saved
23
+ end
24
+
25
+ it "should be uncreated" do
26
+ @document.should_not be_created
27
+ end
28
+ end
29
+
30
+ describe "initialized from XML" do
31
+ before :each do
32
+ @owner = mock('Scribd::User @owner')
33
+ @document = Scribd::Document.new(:xml => REXML::Document.new("<rsp stat='ok'><attr1>val1</attr1><attr2>val2</attr2></rsp>").root, :owner => @owner)
34
+ end
35
+
36
+ it "should have its attributes set appropriately" do
37
+ @document.attr1.should eql('val1')
38
+ @document.attr2.should eql('val2')
39
+ end
40
+
41
+ it "should be saved" do
42
+ @document.should be_saved
43
+ end
44
+
45
+ it "should be created" do
46
+ @document.should be_created
47
+ end
48
+
49
+ it "should have its owner set appropriately" do
50
+ @document.owner.should eql(@owner)
51
+ end
52
+ end
53
+
54
+ describe "not yet created" do
55
+ before :each do
56
+ @document = Scribd::Document.new(:access => 'private', :title => 'mytitle')
57
+ end
58
+
59
+ it "should raise an exception if saved without a file" do
60
+ lambda { @document.save }.should raise_error
61
+ end
62
+ end
63
+
64
+ describe "created" do
65
+ before :each do
66
+ @http = mock('Net::HTTP @http')
67
+ @http.stub! :read_timeout=
68
+ @response = mock('Net::HTTPResponse @response')
69
+ @response.stub!(:body).and_return "<rsp stat='ok'></rsp>"
70
+ @http.stub!(:request).and_return(@response)
71
+ Net::HTTP.stub!(:new).and_return(@http)
72
+ end
73
+
74
+ it "should not raise an exception if saved" do
75
+ @document = Scribd::Document.new(:xml => REXML::Document.new("<rsp stat='ok'><attr1>val1</attr1><attr2>val2</attr2></rsp>").root)
76
+ lambda { @document.save }.should_not raise_error
77
+ end
78
+
79
+ describe "that we own" do
80
+ before :each do
81
+ @owner = mock('Scribd::User @owner')
82
+ @owner.stub!(:session_key).and_return('test session key')
83
+ @document = Scribd::Document.new(:xml => REXML::Document.new("<rsp stat='ok'><attr1>val1</attr1><attr2>val2</attr2></rsp>").root, :owner => @owner)
84
+ end
85
+ end
86
+
87
+ describe "that we don't own" do
88
+ before :each do
89
+ @owner = mock('Scribd::User @owner')
90
+ @owner.stub!(:session_key)
91
+ @document = Scribd::Document.new(:xml => REXML::Document.new("<rsp stat='ok'><attr1>val1</attr1><attr2>val2</attr2></rsp>").root, :owner => @owner)
92
+ end
93
+
94
+ it "should raise PrivilegeError when trying to change the file" do
95
+ @document.file = 'sample/test.txt'
96
+ lambda { @document.save }.should raise_error(Scribd::PrivilegeError)
97
+ end
98
+ end
99
+
100
+ describe "with no owner" do
101
+ before :each do
102
+ @document = Scribd::Document.new(:xml => REXML::Document.new("<rsp stat='ok'><attr1>val1</attr1><attr2>val2</attr2></rsp>").root)
103
+ end
104
+
105
+ it "should raise PrivilegeError when trying to change the file" do
106
+ @document.file = 'sample/test.txt'
107
+ lambda { @document.save }.should raise_error(Scribd::PrivilegeError)
108
+ end
109
+ end
110
+ end
111
+
112
+ describe "to be uploaded from file" do
113
+ before :each do
114
+ @document = Scribd::Document.new(:file => 'sample/test.txt')
115
+ end
116
+
117
+ it "should make a call to docs.upload" do
118
+ Scribd::API.instance.should_receive(:send_request).with('docs.upload', hash_including(:file => an_instance_of(File)))
119
+ Scribd::API.instance.should_receive(:send_request).any_number_of_times
120
+ @document.save
121
+ end
122
+ end
123
+
124
+ describe "to be uploaded from URL" do
125
+ before :each do
126
+ @document = Scribd::Document.new(:file => 'http://www.example.com/file.txt')
127
+ end
128
+
129
+ it "should make a call to docs.uploadFromUrl" do
130
+ Scribd::API.instance.should_receive(:send_request).with('docs.uploadFromUrl', hash_including(:url => 'http://www.example.com/file.txt'))
131
+ Scribd::API.instance.should_receive(:send_request).any_number_of_times
132
+ @document.save
133
+ end
134
+
135
+ it "should recognize HTTPS URLs" do
136
+ @document.file.gsub!(/http/, 'https')
137
+ Scribd::API.instance.should_receive(:send_request).with('docs.uploadFromUrl', hash_including(:url => 'https://www.example.com/file.txt'))
138
+ Scribd::API.instance.should_receive(:send_request).any_number_of_times
139
+ @document.save
140
+ end
141
+
142
+ it "should recognize FTP URLs" do
143
+ @document.file.gsub!(/http/, 'ftp')
144
+ Scribd::API.instance.should_receive(:send_request).with('docs.uploadFromUrl', hash_including(:url => 'ftp://www.example.com/file.txt'))
145
+ Scribd::API.instance.should_receive(:send_request).any_number_of_times
146
+ @document.save
147
+ end
148
+ end
149
+
150
+ describe "to be uploaded" do
151
+ describe "given a file path" do
152
+ before :each do
153
+ @document = Scribd::Document.new(:file => 'sample/test.txt')
154
+ end
155
+
156
+ it "should set the doc_type attribute to the file's extension" do
157
+ Scribd::API.instance.should_receive(:send_request).with('docs.upload', hash_including(:doc_type => 'txt'))
158
+ Scribd::API.instance.should_receive(:send_request).any_number_of_times
159
+ @document.save
160
+ end
161
+
162
+ it "should prefer a doc_type set in the type attribute" do
163
+ @document.type = 'pdf'
164
+ Scribd::API.instance.should_receive(:send_request).with('docs.upload', hash_including(:doc_type => 'pdf'))
165
+ Scribd::API.instance.should_receive(:send_request).any_number_of_times
166
+ @document.save
167
+ end
168
+
169
+ it "should not raise an exception if the document does not have an extension" do
170
+ @document.file = 'Rakefile'
171
+ Scribd::API.instance.should_receive(:send_request).with('docs.upload', hash_including(:doc_type => nil))
172
+ Scribd::API.instance.should_receive(:send_request).any_number_of_times
173
+ lambda { @document.save }.should_not raise_error
174
+ end
175
+
176
+ it "should downcase filename extensions" do
177
+ @document.file = 'sample/test.TXT'
178
+ Scribd::API.instance.should_receive(:send_request).with('docs.upload', hash_including(:doc_type => 'txt'))
179
+ Scribd::API.instance.should_receive(:send_request).any_number_of_times
180
+ lambda { @document.save }.should_not raise_error
181
+ end
182
+
183
+ it "should downcase attributed file extensions" do
184
+ @document.type = 'PDF'
185
+ Scribd::API.instance.should_receive(:send_request).with('docs.upload', hash_including(:doc_type => 'pdf'))
186
+ Scribd::API.instance.should_receive(:send_request).any_number_of_times
187
+ @document.save
188
+ end
189
+ end
190
+
191
+ describe "given a file object" do
192
+ before :each do
193
+ @document = Scribd::Document.new(:file => File.new('sample/test.txt'))
194
+ end
195
+
196
+ it "should set the doc_type attribute to the file's extension" do
197
+ Scribd::API.instance.should_receive(:send_request).with('docs.upload', hash_including(:doc_type => 'txt'))
198
+ Scribd::API.instance.should_receive(:send_request).any_number_of_times
199
+ @document.save
200
+ end
201
+
202
+ it "should prefer a doc_type set in the type attribute" do
203
+ @document.type = 'pdf'
204
+ Scribd::API.instance.should_receive(:send_request).with('docs.upload', hash_including(:doc_type => 'pdf'))
205
+ Scribd::API.instance.should_receive(:send_request).any_number_of_times
206
+ @document.save
207
+ end
208
+
209
+ it "should not raise an exception if the document does not have an extension" do
210
+ @document.file = File.open('Rakefile')
211
+ Scribd::API.instance.should_receive(:send_request).with('docs.upload', hash_including(:doc_type => nil))
212
+ Scribd::API.instance.should_receive(:send_request).any_number_of_times
213
+ lambda { @document.save }.should_not raise_error
214
+ end
215
+
216
+ it "should downcase filename extensions" do
217
+ @document.file = File.open('sample/test.TXT')
218
+ Scribd::API.instance.should_receive(:send_request).with('docs.upload', hash_including(:doc_type => 'txt'))
219
+ Scribd::API.instance.should_receive(:send_request).any_number_of_times
220
+ lambda { @document.save }.should_not raise_error
221
+ end
222
+
223
+ it "should downcase attributed file extensions" do
224
+ @document.type = 'PDF'
225
+ Scribd::API.instance.should_receive(:send_request).with('docs.upload', hash_including(:doc_type => 'pdf'))
226
+ Scribd::API.instance.should_receive(:send_request).any_number_of_times
227
+ @document.save
228
+ end
229
+ end
230
+
231
+ describe "given a file to upload" do
232
+ before :each do
233
+ @document = Scribd::Document.new(:file => 'sample/test.txt')
234
+ end
235
+
236
+ it "should set the rev_id field to the doc_id attribute" do
237
+ @document.doc_id = 123
238
+ Scribd::API.instance.should_receive(:send_request).with('docs.upload', hash_including(:rev_id => 123))
239
+ Scribd::API.instance.should_receive(:send_request).any_number_of_times
240
+ @document.save
241
+ end
242
+
243
+ it "should set the access field to the access attribute" do
244
+ @document.access = 'private'
245
+ Scribd::API.instance.should_receive(:send_request).with('docs.upload', hash_including(:access => 'private'))
246
+ Scribd::API.instance.should_receive(:send_request).any_number_of_times
247
+ @document.save
248
+ end
249
+
250
+ it "should set the session_key field to the owner's session key" do
251
+ owner = mock('Scribd::User owner')
252
+ owner.stub!(:session_key).and_return('his key')
253
+ @document.owner = owner
254
+ Scribd::API.instance.should_receive(:send_request).with('docs.upload', hash_including(:session_key => 'his key'))
255
+ Scribd::API.instance.should_receive(:send_request).any_number_of_times
256
+ @document.save
257
+ end
258
+
259
+ it "should pass through any other attributes to the docs.upload call" do
260
+ @document.hello = 'there'
261
+ Scribd::API.instance.should_receive(:send_request).with('docs.upload', hash_including(:hello => 'there'))
262
+ Scribd::API.instance.should_receive(:send_request).any_number_of_times
263
+ @document.save
264
+ end
265
+
266
+ describe "successfully" do
267
+ before :each do
268
+ @document.stub!(:id).and_return(3)
269
+ @xml = REXML::Document.new("<rsp stat='ok'><access_key>abc123</access_key></rsp>")
270
+ Scribd::API.instance.should_receive(:send_request).with('docs.upload', an_instance_of(Hash)).and_return(@xml)
271
+ end
272
+
273
+ describe "without testing changeSettings" do
274
+ before :each do
275
+ Scribd::API.instance.should_receive(:send_request).with('docs.changeSettings', an_instance_of(Hash))
276
+ end
277
+
278
+ it "should load attributes from the response" do
279
+ @document.save
280
+ @document.access_key.should eql('abc123')
281
+ end
282
+
283
+ it "should set created to true" do
284
+ @document.save
285
+ @document.should be_created
286
+ end
287
+
288
+ it "should set saved to true" do
289
+ @document.save
290
+ @document.should be_saved
291
+ end
292
+
293
+ it "should return true" do
294
+ @document.save.should be_true
295
+ end
296
+ end
297
+
298
+ it "should not send the file, type, or access parameters to the changeSettings call" do
299
+ @document.type = 'pdf'
300
+ @document.access = 'private'
301
+ Scribd::API.instance.should_not_receive(:send_request).with('docs.changeSettings', hash_including(:file => 'sample/text.txt'))
302
+ Scribd::API.instance.should_not_receive(:send_request).with('docs.changeSettings', hash_including(:type => 'pdf'))
303
+ Scribd::API.instance.should_not_receive(:send_request).with('docs.changeSettings', hash_including(:access => 'private'))
304
+ @document.save
305
+ end
306
+
307
+ it "should pass all other attributes to the changeSettings call" do
308
+ @document.attr1 = 'val1'
309
+ Scribd::API.instance.should_receive(:send_request).with('docs.changeSettings', hash_including(:attr1 => 'val1'))
310
+ @document.save
311
+ end
312
+
313
+ it "should pass the owner's session key to changeSettings" do
314
+ owner = mock('Scribd::User owner')
315
+ owner.stub!(:session_key).and_return('his key')
316
+ @document.owner = owner
317
+ Scribd::API.instance.should_receive(:send_request).with('docs.changeSettings', hash_including(:session_key => 'his key'))
318
+ @document.save
319
+ end
320
+
321
+ it "should pass the document's ID to changeSettings" do
322
+ Scribd::API.instance.should_receive(:send_request).with('docs.changeSettings', hash_including(:doc_ids => 3))
323
+ @document.save
324
+ end
325
+ end
326
+ end
327
+ end
328
+
329
+ describe ".update_all" do
330
+ before :each do
331
+ @owner1 = mock('Scribd::User @owner1')
332
+ @owner1.stub!(:session_key).and_return 'session1'
333
+ @docs = [
334
+ Scribd::Document.new(:owner => @owner1, :doc_id => 1),
335
+ Scribd::Document.new(:owner => @owner1, :doc_id => 2)
336
+ ]
337
+ end
338
+
339
+ it "should raise ArgumentError if an array of docs is not provided" do
340
+ lambda { Scribd::Document.update_all 'string', {} }.should raise_error(ArgumentError)
341
+ end
342
+
343
+ it "should raise ArgumentError unless all array elements are Scribd::Documents" do
344
+ @docs << 'string'
345
+ lambda { Scribd::Document.update_all @docs, {} }.should raise_error(ArgumentError)
346
+ end
347
+
348
+ it "should raise ArgumentError unless all documents have session keys" do
349
+ @docs << Scribd::Document.new
350
+ lambda { Scribd::Document.update_all @docs, {} }.should raise_error(ArgumentError)
351
+ end
352
+
353
+ it "should raise ArgumentError unless options is a hash" do
354
+ lambda { Scribd::Document.update_all @docs, 'string' }.should raise_error(ArgumentError)
355
+ end
356
+
357
+ it "should call changeSettings once for each session key" do
358
+ @owner2 = mock('Scribd::User @owner2')
359
+ @owner2.stub!(:session_key).and_return 'session2'
360
+ @docs << Scribd::Document.new(:owner => @owner2, :doc_id => 3)
361
+ Scribd::API.instance.should_receive(:send_request).once.with('docs.changeSettings', hash_including(:session_key => 'session1'))
362
+ Scribd::API.instance.should_receive(:send_request).once.with('docs.changeSettings', hash_including(:session_key => 'session2'))
363
+ Scribd::Document.update_all @docs, { :access => 'private' }
364
+ end
365
+
366
+ it "should set the doc_ids field to a comma-delimited list of document IDs" do
367
+ Scribd::API.instance.should_receive(:send_request).once.with('docs.changeSettings', hash_including(:doc_ids => '1,2'))
368
+ Scribd::Document.update_all @docs, { :access => 'private' }
369
+ end
370
+
371
+ it "should pass all options to the changeSettings call" do
372
+ Scribd::API.instance.should_receive(:send_request).once.with('docs.changeSettings', hash_including(:access => 'private', :bogus => 'test'))
373
+ Scribd::Document.update_all @docs, { :access => 'private', :bogus => 'test' }
374
+ end
375
+ end
376
+
377
+ describe ".find" do
378
+ it "should raise an ArgumentError if an invalid doc ID is provided" do
379
+ lambda { Scribd::Document.find('oh hai') }.should raise_error(ArgumentError)
380
+ end
381
+
382
+ it "should raise an ArgumentError if a query is not provided for scoped lookups" do
383
+ lambda { Scribd::Document.find(:all, :title => 'hi') }.should raise_error(ArgumentError)
384
+ end
385
+
386
+ describe "by ID" do
387
+ before :each do
388
+ @xml = REXML::Document.new("<rsp stat='ok'><access_key>abc123</access_key></rsp>")
389
+ end
390
+
391
+ it "should call getSettings with the doc ID" do
392
+ Scribd::API.instance.should_receive(:send_request).once.with('docs.getSettings', hash_including(:doc_id => 123)).and_return(@xml)
393
+ Scribd::Document.find 123
394
+ end
395
+
396
+ it "should pass other options to the getSettings call" do
397
+ Scribd::API.instance.should_receive(:send_request).once.with('docs.getSettings', hash_including(:arg => 'val')).and_return(@xml)
398
+ Scribd::Document.find 123, :arg => 'val'
399
+ end
400
+
401
+ it "should return a Document created from the resulting XML" do
402
+ Scribd::API.instance.stub!(:send_request).and_return(@xml)
403
+ doc = Scribd::Document.find(123)
404
+ doc.should be_kind_of(Scribd::Document)
405
+ doc.access_key.should eql('abc123')
406
+ end
407
+ end
408
+
409
+ describe "by query" do
410
+ before :each do
411
+ @xml = REXML::Document.new("<rsp stat='ok'><result_set><result><access_key>abc123</access_key></result><result><access_key>abc321</access_key></result></result_set></rsp>")
412
+ end
413
+
414
+ it "should set the scope field according to the parameter" do
415
+ Scribd::API.instance.should_receive(:send_request).with('docs.search', hash_including(:scope => 'all')).and_return(@xml)
416
+ Scribd::Document.find(:all, :query => 'test')
417
+ end
418
+
419
+ it "should return an ordered array of Document results" do
420
+ Scribd::API.instance.stub!(:send_request).and_return(@xml)
421
+ docs = Scribd::Document.find(:all, :query => 'test')
422
+ docs.should have(2).items
423
+ docs.first.access_key.should eql('abc123')
424
+ docs.last.access_key.should eql('abc321')
425
+ end
426
+
427
+ it "should set the scope to 'all' and return the first result if :first is provided" do
428
+ Scribd::API.instance.should_receive(:send_request).with('docs.search', hash_including(:scope => 'all')).and_return(@xml)
429
+ docs = Scribd::Document.find(:first, :query => 'test')
430
+ docs.should be_kind_of(Scribd::Document)
431
+ docs.access_key.should eql('abc123')
432
+ end
433
+
434
+ it "should set the num_results field to the limit option" do
435
+ Scribd::API.instance.should_receive(:send_request).with('docs.search', hash_including(:num_results => 10)).and_return(@xml)
436
+ docs = Scribd::Document.find(:all, :query => 'test', :limit => 10)
437
+ end
438
+
439
+ it "should set the num_start field to the offset option" do
440
+ Scribd::API.instance.should_receive(:send_request).with('docs.search', hash_including(:num_start => 10)).and_return(@xml)
441
+ docs = Scribd::Document.find(:all, :query => 'test', :offset => 10)
442
+ end
443
+ end
444
+ end
445
+
446
+ it "should have an upload synonym for the create method"
447
+
448
+ describe ".conversion_status" do
449
+ before :each do
450
+ @document = Scribd::Document.new(:xml => REXML::Document.new("<doc_id type='integer'>123</doc_id>"))
451
+ @xml = REXML::Document.new("<rsp stat='ok'><conversion_status>EXAMPLE</conversion_status></rsp>")
452
+ end
453
+
454
+ it "should call getConversionStatus with the correct doc_id" do
455
+ Scribd::API.instance.should_receive(:send_request).once.with('docs.getConversionStatus', :doc_id => 123).and_return(@xml)
456
+ @document.conversion_status
457
+ end
458
+
459
+ it "should return the conversion status" do
460
+ Scribd::API.instance.stub!(:send_request).and_return(@xml)
461
+ @document.conversion_status.should eql('EXAMPLE')
462
+ end
463
+ end
464
+
465
+ describe ".reads" do
466
+ before :each do
467
+ @document = Scribd::Document.new(:xml => REXML::Document.new("<doc_id type='integer'>123</doc_id>"))
468
+ @xml = REXML::Document.new("<rsp stat='ok'><reads>12321</reads></rsp>")
469
+ end
470
+
471
+ it "should call getStats with the correct doc_id" do
472
+ Scribd::API.instance.should_receive(:send_request).once.with('docs.getStats', :doc_id => 123).and_return(@xml)
473
+ @document.reads
474
+ end
475
+
476
+ it "should return the read count" do
477
+ Scribd::API.instance.stub!(:send_request).and_return(@xml)
478
+ @document.reads.should eql('12321')
479
+ end
480
+
481
+ it "should call getStats only once when read call made more than once" do
482
+ Scribd::API.instance.should_receive(:send_request).once.with('docs.getStats', :doc_id => 123).and_return(@xml)
483
+ @document.reads
484
+ @document.reads
485
+ end
486
+
487
+ it "should call getStats everytime when read call made with :force => true" do
488
+ Scribd::API.instance.should_receive(:send_request).twice.with('docs.getStats', :doc_id => 123).and_return(@xml)
489
+ @document.reads
490
+ @document.reads(:force => true)
491
+ end
492
+ end
493
+
494
+ describe ".destroy" do
495
+ before :each do
496
+ @document = Scribd::Document.new(:xml => REXML::Document.new("<doc_id type='integer'>123</doc_id>"))
497
+ @success = REXML::Document.new("<rsp stat='ok' />")
498
+ @fail = REXML::Document.new("<rsp stat='fail' />")
499
+ end
500
+
501
+ it "should call delete with the correct doc_id" do
502
+ Scribd::API.instance.should_receive(:send_request).once.with('docs.delete', :doc_id => 123).and_return(@success)
503
+ @document.destroy
504
+ end
505
+
506
+ it "should return true if successful" do
507
+ Scribd::API.instance.stub!(:send_request).and_return(@success)
508
+ @document.destroy.should be_true
509
+ end
510
+
511
+ it "should return false if unsuccessful" do
512
+ Scribd::API.instance.stub!(:send_request).and_return(@fail)
513
+ @document.destroy.should be_false
514
+ end
515
+ end
516
+
517
+ it "should have an id attribute that aliases doc_id" do
518
+ document = Scribd::Document.new(:xml => REXML::Document.new("<doc_id type='integer'>123</doc_id>"))
519
+ document.id.should eql(123)
520
+ end
521
+
522
+ describe ".owner=" do
523
+ it "should raise NotImplementedError for saved docs" do
524
+ document = Scribd::Document.new(:xml => REXML::Document.new("<doc_id type='integer'>123</doc_id>"))
525
+ lambda { document.owner = Scribd::User.new }.should raise_error(NotImplementedError)
526
+ end
527
+ end
528
+
529
+ describe ".download_url" do
530
+ before :each do
531
+ @document = Scribd::Document.new(:xml => REXML::Document.new("<doc_id type='integer'>123</doc_id>"))
532
+ @xml = REXML::Document.new("<rsp stat='ok'><download_link><![CDATA[http://www.example.com/doc.pdf]]></download_link></rsp>")
533
+ end
534
+
535
+ it "should call docs.getDownloadUrl with the correct doc_id" do
536
+ Scribd::API.instance.should_receive(:send_request).once.with('docs.getDownloadUrl', hash_including(:doc_id => 123)).and_return(@xml)
537
+ @document.download_url
538
+ end
539
+
540
+ it "should default to the original file format" do
541
+ Scribd::API.instance.should_receive(:send_request).once.with('docs.getDownloadUrl', hash_including(:doc_type => 'original')).and_return(@xml)
542
+ @document.download_url
543
+ end
544
+
545
+ it "should allow custom file formats" do
546
+ Scribd::API.instance.should_receive(:send_request).once.with('docs.getDownloadUrl', hash_including(:doc_type => 'pdf')).and_return(@xml)
547
+ @document.download_url('pdf')
548
+ end
549
+
550
+ it "should return the download link" do
551
+ Scribd::API.instance.stub!(:send_request).and_return(@xml)
552
+ @document.download_url.should eql("http://www.example.com/doc.pdf")
553
+ end
554
+ end
555
+ end
556
+
557
+ Dir.chdir old_dir