dropbox 1.2.2 → 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
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