dropbox 1.2.2 → 1.2.3

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.
data/ChangeLog CHANGED
@@ -1,3 +1,10 @@
1
+ 1.2.3 (2011-01-14)
2
+
3
+ * Now supports caching metadata calls
4
+ * Large uploads can use custom timeouts
5
+ * Fix for updated multipart-post gem
6
+ * SSL upload fix
7
+
1
8
  1.2.2 (2010-11-27)
2
9
 
3
10
  * Fixed dependency bug.
@@ -3,25 +3,25 @@ GEM
3
3
  specs:
4
4
  diff-lcs (1.1.2)
5
5
  git (1.2.5)
6
- jeweler (1.5.1)
6
+ jeweler (1.5.2)
7
7
  bundler (~> 1.0.0)
8
8
  git (>= 1.2.5)
9
9
  rake
10
10
  json (1.4.6)
11
11
  mechanize (1.0.0)
12
12
  nokogiri (>= 1.2.1)
13
- multipart-post (1.0.1)
13
+ multipart-post (1.1.0)
14
14
  nokogiri (1.4.4)
15
15
  oauth (0.4.4)
16
16
  rake (0.8.7)
17
- rspec (2.1.0)
18
- rspec-core (~> 2.1.0)
19
- rspec-expectations (~> 2.1.0)
20
- rspec-mocks (~> 2.1.0)
21
- rspec-core (2.1.0)
22
- rspec-expectations (2.1.0)
17
+ rspec (2.4.0)
18
+ rspec-core (~> 2.4.0)
19
+ rspec-expectations (~> 2.4.0)
20
+ rspec-mocks (~> 2.4.0)
21
+ rspec-core (2.4.0)
22
+ rspec-expectations (2.4.0)
23
23
  diff-lcs (~> 1.1.2)
24
- rspec-mocks (2.1.0)
24
+ rspec-mocks (2.4.0)
25
25
 
26
26
  PLATFORMS
27
27
  ruby
@@ -13,13 +13,14 @@ http://developers.dropbox.com
13
13
 
14
14
  # STEP 1: Authorize the user
15
15
  session = Dropbox::Session.new('your_consumer_key', 'your_consumer_secret')
16
+ session.mode = :sandbox # might need to set this to :dropbox; consult your API account page
16
17
  puts "Visit #{session.authorize_url} to log in to Dropbox. Hit enter when you have done this."
17
18
  gets
18
19
  session.authorize
19
20
 
20
21
  # STEP 2: Play!
21
22
  session.upload('testfile.txt')
22
- uploaded_file = session.file('testfile.txt')
23
+ uploaded_file = session.file('testfile.txt', '/')
23
24
  puts uploaded_file.metadata.size
24
25
 
25
26
  uploaded_file.move 'new_name.txt'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.2
1
+ 1.2.3
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{dropbox}
8
- s.version = "1.2.2"
8
+ s.version = "1.2.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Tim Morgan"]
12
- s.date = %q{2010-11-27}
12
+ s.date = %q{2011-01-14}
13
13
  s.description = %q{An easy-to-use client library for the official Dropbox API.}
14
14
  s.email = %q{dropbox@timothymorgan.info}
15
15
  s.extra_rdoc_files = [
@@ -28,6 +28,7 @@ Gem::Specification.new do |s|
28
28
  "Rakefile",
29
29
  "VERSION",
30
30
  "dropbox.gemspec",
31
+ "examples/upload_and_delete.rb",
31
32
  "keys.json.example",
32
33
  "lib/dropbox.rb",
33
34
  "lib/dropbox/api.rb",
@@ -55,6 +56,7 @@ Gem::Specification.new do |s|
55
56
  s.rubygems_version = %q{1.3.7}
56
57
  s.summary = %q{Ruby client library for the official Dropbox API}
57
58
  s.test_files = [
59
+ "examples/upload_and_delete.rb",
58
60
  "spec/dropbox/api_spec.rb",
59
61
  "spec/dropbox/entry_spec.rb",
60
62
  "spec/dropbox/event_spec.rb",
@@ -0,0 +1,24 @@
1
+ require 'dropbox'
2
+
3
+ unless File.exist?('keys.json')
4
+ raise "Create a keys.json file with your Dropbox API credentials. See keys.json.example to get started."
5
+ end
6
+
7
+ settings = JSON.parse(File.read('keys.json'))
8
+
9
+ session = Dropbox::Session.new(settings['key'], settings['secret'])
10
+ session.mode = :sandbox
11
+ puts "Visit #{session.authorize_url} to log in to Dropbox. Hit enter when you have done this."
12
+ gets
13
+ session.authorize
14
+
15
+ # upload a file
16
+ puts "Uploading ChangeLog..."
17
+ session.upload 'ChangeLog', '/'
18
+ uploaded_file = session.file('ChangeLog')
19
+ puts "Done! #{uploaded_file.inspect}"
20
+ puts uploaded_file.metadata.size
21
+
22
+ puts "Deleting file..."
23
+ uploaded_file.delete
24
+ puts "Done!"
@@ -147,6 +147,9 @@ module Dropbox
147
147
  # +mode+:: Temporarily changes the API mode. See the MODES array.
148
148
  # +as+:: Specify a custom name for the uploaded file (required when
149
149
  # uploading from a +StringIO+ stream).
150
+ # +timeout+:: The amount of time to wait for a response from the Dropbox
151
+ # server (in seconds). By default it's 60; set this higher when
152
+ # uploading large files.
150
153
  #
151
154
  # Examples:
152
155
  #
@@ -168,11 +171,17 @@ module Dropbox
168
171
  raise(ArgumentError, "Must specify the :as option when uploading from StringIO") unless options[:as]
169
172
  file = local_file
170
173
  local_path = options[:as]
174
+
175
+ # hack for bug in UploadIO
176
+ class << file
177
+ attr_accessor :path
178
+ end
179
+ file.path = local_path
171
180
  else
172
181
  raise ArgumentError, "local_file must be a File, StringIO, or file path"
173
182
  end
174
183
 
175
- name = options.delete(:as).to_s if options[:as]
184
+ name = File.basename(options.delete(:as)) if options[:as]
176
185
 
177
186
  remote_path = remote_path.sub(/^\//, '')
178
187
  remote_path = Dropbox.check_path(remote_path).split('/')
@@ -189,15 +198,18 @@ module Dropbox
189
198
  oauth_signature = oauth_request.to_hash['authorization']
190
199
 
191
200
  request = Net::HTTP::Post::Multipart.new(uri.path,
192
- 'file' => UploadIO.convert!(
201
+ 'file' => UploadIO.new(
193
202
  file,
194
203
  'application/octet-stream',
195
- name,
196
- local_path))
204
+ name))
197
205
  request['authorization'] = oauth_signature.join(', ')
198
206
 
199
207
  proxy = URI.parse(@proxy || "")
200
- response = Net::HTTP::Proxy(proxy.host, proxy.port).new(uri.host, uri.port).request(request)
208
+ http = Net::HTTP::Proxy(proxy.host, proxy.port).new(uri.host, uri.port)
209
+ http.use_ssl = @ssl
210
+ http.read_timeout = options[:timeout] if options[:timeout]
211
+ response = http.request(request)
212
+
201
213
  if response.kind_of?(Net::HTTPSuccess) then
202
214
  begin
203
215
  return JSON.parse(response.body).symbolize_keys_recursively.to_struct_recursively
@@ -380,9 +392,12 @@ module Dropbox
380
392
  # +limit+:: Set this value to limit the number of entries returned when
381
393
  # listing a directory. If the result has more than this number of
382
394
  # entries, a TooManyEntriesError will be raised.
395
+ # +prior_response+:: The response from a prior call to metadata for the same
396
+ # path. If the metadata has not changed since the prior
397
+ # call, the entire metadata will not be re-downloaded.
398
+ # Operation is undefined if the given value was for a
399
+ # call to metadata with a different path.
383
400
  # +mode+:: Temporarily changes the API mode. See the MODES array.
384
- #
385
- # TODO hash option seems to return HTTPBadRequest for now
386
401
 
387
402
  def metadata(path, options={})
388
403
  path = path.sub(/^\//, '')
@@ -393,7 +408,7 @@ module Dropbox
393
408
  args += Dropbox.check_path(path).split('/')
394
409
  args << Hash.new
395
410
  args.last[:file_limit] = options[:limit] if options[:limit]
396
- #args.last[:hash] = options[:hash] if options[:hash]
411
+ args.last[:hash] = options[:prior_response].hash if options[:prior_response] and options[:prior_response].hash
397
412
  args.last[:list] = !(options[:suppress_list].to_bool)
398
413
  args.last[:ssl] = @ssl
399
414
 
@@ -402,7 +417,7 @@ module Dropbox
402
417
  rescue UnsuccessfulResponseError => error
403
418
  raise TooManyEntriesError.new(path) if error.response.kind_of?(Net::HTTPNotAcceptable)
404
419
  raise FileNotFoundError.new(path) if error.response.kind_of?(Net::HTTPNotFound)
405
- #return :not_modified if error.kind_of?(Net::HTTPNotModified)
420
+ return options[:prior_response] if error.response.kind_of?(Net::HTTPNotModified)
406
421
  raise error
407
422
  end
408
423
  end
@@ -31,10 +31,16 @@ module Dropbox
31
31
  @path = path
32
32
  end
33
33
 
34
- # Delegates to Dropbox::API#metadata.
34
+ # Delegates to Dropbox::API#metadata. Additional options:
35
+ #
36
+ # +force+:: Normally, subsequent calls to this method will use cached
37
+ # results if the file hasn't been changed. To download the full
38
+ # metadata even if the file has not been changed, set this to
39
+ # +true+.
35
40
 
36
41
  def metadata(options={})
37
- @session.metadata path, options
42
+ @previous_metadata = nil if options.delete(:force)
43
+ @previous_metadata = @session.metadata path, (@previous_metadata ? options.merge(:prior_response => @previous_metadata) : options)
38
44
  end
39
45
  alias :info :metadata
40
46
 
@@ -189,7 +189,7 @@ module Dropbox
189
189
  session = dup
190
190
  consumer = OAuth::Consumer.new(@consumer.key, @consumer.secret, :site => host, :proxy => @proxy)
191
191
  session.instance_variable_set :@consumer, consumer
192
- session.instance_variable_set :@access_token, OAuth::AccessToken.new(consumer, @access_token.token, @access_token.secret)
192
+ session.instance_variable_set :@access_token, OAuth::AccessToken.new(consumer, @access_token.token, @access_token.secret) if @access_token
193
193
  return session
194
194
  end
195
195
  end
@@ -30,7 +30,7 @@ def stub_for_upload_testing
30
30
  @response.stub!(:kind_of?).with(Net::HTTPSuccess).and_return(true)
31
31
  @response.stub!(:body).and_return('{"test":"val"}')
32
32
 
33
- @http = mock('Net::HTTP', :request => @response)
33
+ @http = mock('Net::HTTP', :request => @response, :use_ssl= => nil)
34
34
  Net::HTTP.stub!(:new).and_return(@http)
35
35
  end
36
36
 
@@ -502,6 +502,19 @@ describe Dropbox::API do
502
502
  response.directory?.should be_true
503
503
  response.hsh.directory?.should be_false
504
504
  end
505
+
506
+ it "should add a hash option when prior_response is set" do
507
+ should_receive_api_method_with_arguments @token_mock, :get, 'metadata', { :list => 'true', :hash => '123abc' }, @response, 'some/file', 'sandbox'
508
+ @session.metadata 'some/file', :prior_response => mock('metadata response', :hash => '123abc')
509
+ end
510
+
511
+ it "should return the prior_response when the response code is 304" do
512
+ response_acts_as Net::HTTPNotModified
513
+ @token_mock.stub!(:get).and_return(@response)
514
+ prior = mock('metadata response', :hash => '123abc')
515
+
516
+ @session.metadata('path', :prior_response => prior).should eql(prior)
517
+ end
505
518
  end
506
519
 
507
520
  describe "#list" do
@@ -546,12 +559,12 @@ describe Dropbox::API do
546
559
  end
547
560
 
548
561
  it "should use the File object as the stream" do
549
- UploadIO.should_receive(:convert!).once.with(@file, anything, File.basename(__FILE__), __FILE__)
562
+ UploadIO.should_receive(:new).once.with(@file, anything, File.basename(__FILE__))
550
563
  @session.upload @file, 'remote/'
551
564
  end
552
565
 
553
566
  it "should accept a custom file name via the :as parameter" do
554
- UploadIO.should_receive(:convert!).once.with(@file, anything, 'myfile.txt', __FILE__)
567
+ UploadIO.should_receive(:new).once.with(@file, anything, 'myfile.txt')
555
568
  @session.upload @file, 'remote/', :as => 'myfile.txt'
556
569
  end
557
570
  end
@@ -564,12 +577,12 @@ describe Dropbox::API do
564
577
  end
565
578
 
566
579
  it "should use the file at that path as the stream" do
567
- UploadIO.should_receive(:convert!).once.with(@file, anything, File.basename(__FILE__), __FILE__)
580
+ UploadIO.should_receive(:new).once.with(@file, anything, File.basename(__FILE__))
568
581
  @session.upload @string, 'remote/'
569
582
  end
570
583
 
571
584
  it "should accept a custom file name via the :as parameter" do
572
- UploadIO.should_receive(:convert!).once.with(@file, anything, 'myfile.txt', __FILE__)
585
+ UploadIO.should_receive(:new).once.with(@file, anything, 'myfile.txt')
573
586
  @session.upload @string, 'remote/', :as => 'myfile.txt'
574
587
  end
575
588
  end
@@ -585,7 +598,7 @@ describe Dropbox::API do
585
598
  end
586
599
 
587
600
  it "should use the StringIO as the stream and take filename from the options" do
588
- UploadIO.should_receive(:convert!).once.with(@string_io, anything, @filename, @filename)
601
+ UploadIO.should_receive(:new).once.with(@string_io, anything, @filename)
589
602
  @session.upload @string_io, 'remote/', :as => @filename
590
603
  end
591
604
 
@@ -593,6 +606,11 @@ describe Dropbox::API do
593
606
  lambda { @session.upload @string_io, 'remote/' }.should raise_error(ArgumentError)
594
607
  end
595
608
  end
609
+
610
+ it "should accept a custom read timeout" do
611
+ @http.should_receive(:read_timeout=).once.with(10)
612
+ @session.upload StringIO.new('test123'), 'remote/', :as => 'name.txt', :timeout => 10
613
+ end
596
614
  end
597
615
 
598
616
  describe "request" do
@@ -636,14 +654,14 @@ describe Dropbox::API do
636
654
  end
637
655
 
638
656
  it "should create a multipart POST request with the 'file' parameter set to the file of type application/octet-stream" do
639
- Net::HTTP::Post::Multipart.should_receive(:new).once.with("/#{Dropbox::VERSION}/files/sandbox/hello", hash_including('file' => an_instance_of(File))).and_return(@request)
657
+ Net::HTTP::Post::Multipart.should_receive(:new).once.with("/#{Dropbox::VERSION}/files/sandbox/hello", hash_including('file' => an_instance_of(UploadIO))).and_return(@request)
640
658
 
641
659
  @session.upload __FILE__, 'hello'
642
660
  end
643
661
 
644
662
  it "should send the request" do
645
663
  uri = URI.parse(Dropbox::ALTERNATE_HOSTS['files'])
646
- @http = mock('Net::HTTP', :request => @response)
664
+ @http = mock('Net::HTTP', :request => @response, :use_ssl= => nil)
647
665
  Net::HTTP.stub!(:new).and_return(@http)
648
666
 
649
667
  @session.upload __FILE__, 'test'
@@ -654,7 +672,7 @@ describe Dropbox::API do
654
672
  @session.authorize
655
673
 
656
674
  uri = URI.parse(Dropbox::ALTERNATE_SSL_HOSTS['files'])
657
- @http = mock('Net::HTTP', :request => @response)
675
+ @http = mock('Net::HTTP', :request => @response, :use_ssl= => nil)
658
676
  Net::HTTP.stub!(:new).and_return(@http)
659
677
 
660
678
  @session.upload __FILE__, 'test'
@@ -22,6 +22,26 @@ describe Dropbox::Entry do
22
22
 
23
23
  @entry.metadata(:sandbox => true)
24
24
  end
25
+
26
+ it "should record prior responses and use them automatically" do
27
+ result = mock('result')
28
+
29
+ @session.should_receive(:metadata).once.with(@path, {}).and_return(result)
30
+ @entry.metadata.should eql(result)
31
+
32
+ @session.should_receive(:metadata).once.with(@path, { :prior_response => result }).and_return(result)
33
+ @entry.metadata.should eql(result)
34
+ end
35
+
36
+ it "... unless :force is set to true" do
37
+ result = mock('result')
38
+
39
+ @session.should_receive(:metadata).once.with(@path, {}).and_return(result)
40
+ @entry.metadata
41
+
42
+ @session.should_receive(:metadata).once.with(@path, {}).and_return(result)
43
+ @entry.metadata(:force => true)
44
+ end
25
45
  end
26
46
 
27
47
  describe "#move" do
@@ -133,6 +133,10 @@ describe Dropbox::Revision do
133
133
  end
134
134
 
135
135
  describe "#content_loaded?" do
136
+ before :each do
137
+ @session = mock('Dropbox::Session')
138
+ end
139
+
136
140
  it "should return true if the content is loaded" do
137
141
  pretend_content_and_metadata_is_loaded @revision, @session
138
142
  @revision.should be_content_loaded
@@ -140,6 +144,10 @@ describe Dropbox::Revision do
140
144
  end
141
145
 
142
146
  describe "#metadata_loaded?" do
147
+ before :each do
148
+ @session = mock('Dropbox::Session')
149
+ end
150
+
143
151
  it "should return true if the metadata is loaded" do
144
152
  pretend_content_and_metadata_is_loaded @revision, @session
145
153
  @revision.should be_metadata_loaded
@@ -147,6 +155,10 @@ describe Dropbox::Revision do
147
155
  end
148
156
 
149
157
  describe "#latest?" do
158
+ before :each do
159
+ @session = mock('Dropbox::Session')
160
+ end
161
+
150
162
  it "should raise an exception if the metadata is not yet loaded" do
151
163
  lambda { @revision.latest? }.should raise_error(Dropbox::NotLoadedError)
152
164
  end
@@ -163,6 +175,10 @@ describe Dropbox::Revision do
163
175
  end
164
176
 
165
177
  describe "#directory?" do
178
+ before :each do
179
+ @session = mock('Dropbox::Session')
180
+ end
181
+
166
182
  it "should raise an exception if the metadata is not yet loaded" do
167
183
  lambda { @revision.directory? }.should raise_error(Dropbox::NotLoadedError)
168
184
  end
@@ -179,6 +195,10 @@ describe Dropbox::Revision do
179
195
  end
180
196
 
181
197
  describe "#modified" do
198
+ before :each do
199
+ @session = mock('Dropbox::Session')
200
+ end
201
+
182
202
  it "should raise an exception if the metadata is not yet loaded" do
183
203
  lambda { @revision.modified }.should raise_error(Dropbox::NotLoadedError)
184
204
  end
@@ -190,6 +210,10 @@ describe Dropbox::Revision do
190
210
  end
191
211
 
192
212
  describe "#error?" do
213
+ before :each do
214
+ @session = mock('Dropbox::Session')
215
+ end
216
+
193
217
  it "should return true if there was an error" do
194
218
  pretend_error_occurred @revision
195
219
  @revision.should be_error
@@ -202,6 +226,10 @@ describe Dropbox::Revision do
202
226
  end
203
227
 
204
228
  describe "#deleted?" do
229
+ before :each do
230
+ @session = mock('Dropbox::Session')
231
+ end
232
+
205
233
  it "should raise an exception if the metadata is not yet loaded" do
206
234
  lambda { @revision.deleted? }.should raise_error(Dropbox::NotLoadedError)
207
235
  end
@@ -222,6 +250,10 @@ describe Dropbox::Revision do
222
250
  end
223
251
 
224
252
  describe "#content" do
253
+ before :each do
254
+ @session = mock('Dropbox::Session')
255
+ end
256
+
225
257
  it "should raise an exception if the content is not yet loaded" do
226
258
  lambda { @revision.content }.should raise_error(Dropbox::NotLoadedError)
227
259
  end
@@ -234,6 +266,7 @@ describe Dropbox::Revision do
234
266
 
235
267
  describe "#method_missing" do
236
268
  before :each do
269
+ @session = mock('Dropbox::Session')
237
270
  pretend_content_and_metadata_is_loaded @revision, @session, :size => 123
238
271
  end
239
272
 
@@ -251,6 +284,10 @@ describe Dropbox::Revision do
251
284
  end
252
285
 
253
286
  describe "#metadata_for_latest_revision" do
287
+ before :each do
288
+ @session = mock('Dropbox::Session')
289
+ end
290
+
254
291
  it "should raise an error if metadata has not yet been loaded" do
255
292
  lambda { @revision.metadata_for_latest_revision @session }.should raise_error(Dropbox::NotLoadedError)
256
293
  end
@@ -272,6 +309,7 @@ describe Dropbox::Revision do
272
309
  describe "with an error" do
273
310
  before :each do
274
311
  @metadata = { :error => 403 }
312
+ @session = mock('Dropbox::Session')
275
313
  end
276
314
 
277
315
  it "should set the error attribute" do
@@ -301,6 +339,7 @@ describe Dropbox::Revision do
301
339
  :mtime => (Time.now.to_i - rand(60*60*24*30)),
302
340
  :latest => (rand(2) == 0)
303
341
  }
342
+ @session = mock('Dropbox::Session')
304
343
  end
305
344
 
306
345
  it "should clear the error attribute" do
@@ -169,7 +169,7 @@ describe Dropbox::Session do
169
169
  end
170
170
  end
171
171
 
172
- describe "with Dropbox keys " do
172
+ describe "with Dropbox keys" do
173
173
  before(:all) do
174
174
  @keys = read_keys_file
175
175
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 2
8
- - 2
9
- version: 1.2.2
8
+ - 3
9
+ version: 1.2.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Tim Morgan
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-11-27 00:00:00 -08:00
17
+ date: 2011-01-14 00:00:00 -08:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -124,6 +124,7 @@ files:
124
124
  - Rakefile
125
125
  - VERSION
126
126
  - dropbox.gemspec
127
+ - examples/upload_and_delete.rb
127
128
  - keys.json.example
128
129
  - lib/dropbox.rb
129
130
  - lib/dropbox/api.rb
@@ -159,7 +160,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
159
160
  requirements:
160
161
  - - ">="
161
162
  - !ruby/object:Gem::Version
162
- hash: 4053087587025660672
163
+ hash: -350803918686472919
163
164
  segments:
164
165
  - 0
165
166
  version: "0"
@@ -179,6 +180,7 @@ signing_key:
179
180
  specification_version: 3
180
181
  summary: Ruby client library for the official Dropbox API
181
182
  test_files:
183
+ - examples/upload_and_delete.rb
182
184
  - spec/dropbox/api_spec.rb
183
185
  - spec/dropbox/entry_spec.rb
184
186
  - spec/dropbox/event_spec.rb