dropbox-sdk 1.0.beta → 1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/CHANGELOG +6 -0
  2. data/cli_example.rb +5 -5
  3. data/lib/dropbox_sdk.rb +198 -115
  4. metadata +10 -27
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ 1.1 (2011-10-17)
2
+ * Various bug fixes found during beta period
3
+ * Improved documentation
4
+ * Improved module structure
5
+ * Removed dependency on the oauth module, using plaintext authentication over https
6
+
1
7
  1.0 (2011-8-16)
2
8
  * Backwards compatibility broken
3
9
  - Changed interface
@@ -10,8 +10,8 @@ require 'pp'
10
10
 
11
11
  # You must use your Dropbox App key and secret to use the API.
12
12
  # Find this at https://www.dropbox.com/developers
13
- APP_KEY = ""
14
- APP_SECRET = ""
13
+ APP_KEY = ''
14
+ APP_SECRET = ''
15
15
  ACCESS_TYPE = :app_folder #The two valid values here are :app_folder and :dropbox
16
16
  #The default is :app_folder, but your application might be
17
17
  #set to have full :dropbox access. Check your app at
@@ -46,7 +46,7 @@ class DropboxCLI
46
46
  @session.get_request_token
47
47
 
48
48
  authorize_url = @session.get_authorize_url
49
- puts "Got a request token. Your request token key is #{@session.token} and your token secret is #{@session.secret}"
49
+ puts "Got a request token. Your request token key is #{@session.request_token.key} and your token secret is #{@session.request_token.secret}"
50
50
 
51
51
  # make the user log in and authorize this token
52
52
  puts "AUTHORIZING", authorize_url, "Please visit that web page and hit 'Allow', then hit Enter here."
@@ -56,7 +56,7 @@ class DropboxCLI
56
56
  @session.get_access_token
57
57
 
58
58
  end
59
- puts "You are logged in. Your access token key is #{@session.token} your secret is #{@session.secret}"
59
+ puts "You are logged in. Your access token key is #{@session.access_token.key} your secret is #{@session.access_token.secret}"
60
60
  @client = DropboxClient.new(@session, ACCESS_TYPE)
61
61
  end
62
62
 
@@ -95,7 +95,7 @@ class DropboxCLI
95
95
  end
96
96
  end
97
97
 
98
- def logout
98
+ def logout(command)
99
99
  @session.clear_access_token
100
100
  puts "You are logged out."
101
101
  @client = nil
@@ -1,56 +1,142 @@
1
1
  require 'rubygems'
2
- require 'oauth'
3
- require 'json'
4
2
  require 'uri'
3
+ require 'net/https'
4
+ require 'cgi'
5
+ require 'json'
5
6
  require 'yaml'
6
7
 
7
- DROPBOX_API_SERVER = "api.dropbox.com"
8
- DROPBOX_API_CONTENT_SERVER = "api-content.dropbox.com"
8
+ module Dropbox
9
+ API_SERVER = "api.dropbox.com"
10
+ API_CONTENT_SERVER = "api-content.dropbox.com"
11
+ WEB_SERVER = "www.dropbox.com"
9
12
 
10
- API_VERSION = 1
13
+ API_VERSION = 1
14
+ SDK_VERSION = "1.1"
15
+ end
11
16
 
12
17
  # DropboxSession is responsible for holding OAuth information. It knows how to take your consumer key and secret
13
18
  # and request an access token, an authorize url, and get an access token. You just need to pass it to
14
19
  # DropboxClient after its been authorized.
15
20
  class DropboxSession
16
- def initialize(key, secret)
17
- @consumer_key = key
18
- @consumer_secret = secret
19
- @oauth_conf = {
20
- :site => "https://" + DROPBOX_API_SERVER,
21
- :scheme => :header,
22
- :http_method => :post,
23
- :request_token_url => "/#{API_VERSION}/oauth/request_token",
24
- :access_token_url => "/#{API_VERSION}/oauth/access_token",
25
- :authorize_url => "/#{API_VERSION}/oauth/authorize",
26
- }
27
21
 
28
- @consumer = OAuth::Consumer.new(@consumer_key, @consumer_secret, @oauth_conf)
29
- @access_token = nil
22
+ def initialize(consumer_key, consumer_secret)
23
+ @consumer_key = consumer_key
24
+ @consumer_secret = consumer_secret
30
25
  @request_token = nil
26
+ @access_token = nil
31
27
  end
32
28
 
33
- # This gets a request token. Callbacks are excluded, and any arguments provided are passed on
34
- # to the oauth gem's get_request_token call.
35
- def get_request_token(*args)
36
- begin
37
- @request_token ||= @consumer.get_request_token({:exclude_callback => true}, *args)
38
- rescue OAuth::Unauthorized => e
39
- raise DropboxAuthError.new("Could not get request token, unauthorized. Is your app key and secret correct? #{e}")
29
+ private
30
+
31
+ def do_http(uri, auth_token, request) # :nodoc:
32
+ http = Net::HTTP.new(uri.host, uri.port)
33
+ http.use_ssl = true
34
+
35
+ request.add_field('Authorization', build_auth_header(auth_token))
36
+
37
+ #We use this to better understand how developers are using our SDKs.
38
+ request['User-Agent'] = "OfficialDropboxRubySDK/#{Dropbox::SDK_VERSION}"
39
+
40
+ http.request(request)
41
+ end
42
+
43
+ def build_auth_header(token) # :nodoc:
44
+ header = "OAuth oauth_version=\"1.0\", oauth_signature_method=\"PLAINTEXT\", " +
45
+ "oauth_consumer_key=\"#{URI.escape(@consumer_key)}\", "
46
+ if token
47
+ key = URI.escape(token.key)
48
+ secret = URI.escape(token.secret)
49
+ header += "oauth_token=\"#{key}\", oauth_signature=\"#{URI.escape(@consumer_secret)}&#{secret}\""
50
+ else
51
+ header += "oauth_signature=\"#{URI.escape(@consumer_secret)}&\""
52
+ end
53
+ header
54
+ end
55
+
56
+ def do_get_with_token(url, token, headers=nil) # :nodoc:
57
+ uri = URI.parse(url)
58
+ do_http(uri, token, Net::HTTP::Get.new(uri.request_uri))
59
+ end
60
+
61
+ public
62
+
63
+ def do_get(url, headers=nil) # :nodoc:
64
+ assert_authorized
65
+ do_get_with_token(url, @access_token)
66
+ end
67
+
68
+ def do_http_with_body(uri, request, body)
69
+ if body != nil
70
+ if body.is_a?(Hash)
71
+ form_data = {}
72
+ body.each {|k,v| form_data[k.to_s] = v if !v.nil?}
73
+ request.set_form_data(form_data)
74
+ elsif body.respond_to?(:read)
75
+ if body.respond_to?(:length)
76
+ request["Content-Length"] = body.length.to_s
77
+ elsif body.respond_to?(:stat) && body.stat.respond_to?(:size)
78
+ request["Content-Length"] = body.stat.size.to_s
79
+ else
80
+ raise ArgumentError, "Don't know how to handle 'body' (responds to 'read' but not to 'length' or 'stat.size')."
81
+ end
82
+ request.body_stream = body
83
+ else
84
+ s = body.to_s
85
+ request["Content-Length"] = s.length
86
+ request.body = s
87
+ end
88
+ end
89
+ do_http(uri, @access_token, request)
90
+ end
91
+
92
+ def do_post(url, headers=nil, body=nil) # :nodoc:
93
+ assert_authorized
94
+ uri = URI.parse(url)
95
+ do_http_with_body(uri, Net::HTTP::Post.new(uri.request_uri, headers), body)
96
+ end
97
+
98
+ def do_put(url, headers=nil, body=nil) # :nodoc:
99
+ assert_authorized
100
+ uri = URI.parse(url)
101
+ do_http_with_body(uri, Net::HTTP::Put.new(uri.request_uri, headers), body)
102
+ end
103
+
104
+
105
+ def get_token(url_end, input_token, error_message_prefix) #: nodoc:
106
+ response = do_get_with_token("https://#{Dropbox::API_SERVER}:443/#{Dropbox::API_VERSION}/oauth#{url_end}", input_token)
107
+ if not response.kind_of?(Net::HTTPSuccess) # it must be a 200
108
+ raise DropboxAuthError.new("#{error_message_prefix} Server returned #{response.code}: #{response.message}.", response)
109
+ end
110
+ parts = CGI.parse(response.body)
111
+ if !parts.has_key? "oauth_token" and parts["oauth_token"].length != 1
112
+ raise DropboxAuthError.new("Invalid response from #{url_end}: missing \"oauth_token\" parameter: #{response.body}", response)
40
113
  end
114
+ if !parts.has_key? "oauth_token_secret" and parts["oauth_token_secret"].length != 1
115
+ raise DropboxAuthError.new("Invalid response from #{url_end}: missing \"oauth_token\" parameter: #{response.body}", response)
116
+ end
117
+
118
+ OAuthToken.new(parts["oauth_token"][0], parts["oauth_token_secret"][0])
119
+ end
120
+
121
+ # This returns a request token. Requests one from the dropbox server using the provided application key and secret if nessecary.
122
+ def get_request_token()
123
+ @request_token ||= get_token("/request_token", nil, "Error getting request token. Is your app key and secret correctly set?")
41
124
  end
42
125
 
43
126
  # This returns a URL that your user must visit to grant
44
127
  # permissions to this application.
45
- def get_authorize_url(callback=nil, *args)
46
- get_request_token(*args)
128
+ def get_authorize_url(callback=nil)
129
+ get_request_token()
47
130
 
48
- url = @request_token.authorize_url
131
+ url = "/#{Dropbox::API_VERSION}/oauth/authorize?oauth_token=#{URI.escape(@request_token.key)}"
49
132
  if callback
50
- url += "&oauth_callback=" + URI.escape(callback)
133
+ url += "&oauth_callback=#{URI.escape(callback)}"
134
+ end
135
+ if @locale
136
+ url += "&locale=#{URI.escape(@locale)}"
51
137
  end
52
138
 
53
- "https://www.dropbox.com" + url
139
+ "https://#{Dropbox::WEB_SERVER}#{url}"
54
140
  end
55
141
 
56
142
  # Clears the access_token
@@ -58,51 +144,48 @@ class DropboxSession
58
144
  @access_token = nil
59
145
  end
60
146
 
147
+ # Returns the request token, or nil if one hasn't been acquired yet.
148
+ def request_token
149
+ @request_token
150
+ end
151
+
152
+ # Returns the access token, or nil if one hasn't been acquired yet.
153
+ def access_token
154
+ @access_token
155
+ end
156
+
61
157
  # Given a saved request token and secret, set this location's token and secret
62
158
  # * token - this is the request token
63
159
  # * secret - this is the request token secret
64
160
  def set_request_token(key, secret)
65
- @request_token = OAuth::RequestToken.new(@consumer, key, secret)
161
+ @request_token = OAuthToken.new(key, secret)
66
162
  end
67
163
 
68
164
  # Given a saved access token and secret, you set this Session to use that token and secret
69
165
  # * token - this is the access token
70
166
  # * secret - this is the access token secret
71
167
  def set_access_token(key, secret)
72
- @access_token = OAuth::AccessToken.from_hash(@consumer, {:oauth_token => key, :oauth_token_secret => secret})
73
- end
74
-
75
- def check_authorized
76
- ##this check is applied before the token and secret methods
77
- raise DropboxError.new('Session does not yet have a request token') unless authorized?
78
- end
79
-
80
- # Returns the current oauth access or request token.
81
- def token
82
- (@access_token || @request_token).token
83
- end
84
-
85
- # Returns the current oauth access or request token secret.
86
- def secret
87
- (@access_token || @request_token).secret
168
+ @access_token = OAuthToken.new(key, secret)
88
169
  end
89
170
 
90
171
  # Returns the access token. If this DropboxSession doesn't yet have an access_token, it requests one
91
172
  # using the request_token generate from your app's token and secret. This request will fail unless
92
- # your user has got to the authorize_url and approved your request
173
+ # your user has gone to the authorize_url and approved your request
93
174
  def get_access_token
94
- if @access_token.nil?
95
- if @request_token.nil?
96
- raise DropboxAuthError.new("No request token. You must set this or get an authorize url first.")
97
- end
175
+ return @access_token if authorized?
98
176
 
99
- begin
100
- @access_token = @request_token.get_access_token
101
- rescue OAuth::Unauthorized => e
102
- raise DropboxAuthError.new("Could not get access token, unauthorized. Did you go to authorize_url? #{e}")
103
- end
177
+ if @request_token.nil?
178
+ raise DropboxAuthError.new("No request token. You must set this or get an authorize url first.")
179
+ end
180
+
181
+ @access_token = get_token("/access_token", @request_token, "Couldn't get access token.")
182
+ end
183
+
184
+ # If we have an access token, then do nothing. If not, throw a RuntimeError.
185
+ def assert_authorized
186
+ unless authorized?
187
+ raise RuntimeError.new('Session does not yet have a request token')
104
188
  end
105
- @access_token
106
189
  end
107
190
 
108
191
  # Returns true if this Session has been authorized and has an access_token.
@@ -112,24 +195,24 @@ class DropboxSession
112
195
 
113
196
  # serialize the DropboxSession.
114
197
  # At DropboxSession's state is capture in three key/secret pairs. Consumer, request, and access.
115
- # This takes the form of an array that is then converted to yaml
198
+ # Serialize returns these in a YAML string, generated from a converted array of the form:
116
199
  # [consumer_key, consumer_secret, request_token.token, request_token.secret, access_token.token, access_token.secret]
117
200
  # access_token is only included if it already exists in the DropboxSesssion
118
201
  def serialize
119
202
  toreturn = []
120
203
  if @access_token
121
- toreturn.push @access_token.secret, @access_token.token
204
+ toreturn.push @access_token.secret, @access_token.key
122
205
  end
123
206
 
124
- get_request_token unless @request_token
207
+ get_request_token
125
208
 
126
- toreturn.push @request_token.secret, @request_token.token
209
+ toreturn.push @request_token.secret, @request_token.key
127
210
  toreturn.push @consumer_secret, @consumer_key
128
211
 
129
212
  toreturn.to_yaml
130
213
  end
131
214
 
132
- # Takes a serialized DropboxSession and returns a new DropboxSession object
215
+ # Takes a serialized DropboxSession YAML String and returns a new DropboxSession object
133
216
  def self.deserialize(ser)
134
217
  ser = YAML::load(ser)
135
218
  session = DropboxSession.new(ser.pop, ser.pop)
@@ -143,6 +226,22 @@ class DropboxSession
143
226
  end
144
227
 
145
228
 
229
+ # A class that represents either an OAuth request token or an OAuth access token.
230
+ class OAuthToken
231
+ def initialize(key, secret)
232
+ @key = key
233
+ @secret = secret
234
+ end
235
+
236
+ def key
237
+ @key
238
+ end
239
+
240
+ def secret
241
+ @secret
242
+ end
243
+ end
244
+
146
245
 
147
246
  # This is the usual error raised on any Dropbox related Errors
148
247
  class DropboxError < RuntimeError
@@ -179,15 +278,7 @@ class DropboxClient
179
278
  # Initialize a new DropboxClient. You need to get it a session which either has been authorized. See
180
279
  # documentation on DropboxSession for how to authorize it.
181
280
  def initialize(session, root="app_folder", locale=nil)
182
- if not session.authorized?
183
- begin
184
- ## attempt to get an access token and authorize the session
185
- session.get_access_token
186
- rescue OAuth::Unauthorized => e
187
- raise DropboxAuthError.new("Could not initialize. Failed to get access token from Session. Error was: #{ e.message }")
188
- # If this was raised, the user probably didn't go to auth.get_authorize_url
189
- end
190
- end
281
+ session.get_access_token
191
282
 
192
283
  @root = root.to_s # If they passed in a symbol, make it a string
193
284
 
@@ -196,15 +287,12 @@ class DropboxClient
196
287
  end
197
288
  if @root == "app_folder"
198
289
  #App Folder is the name of the access type, but for historical reasons
199
- #sandbox is the URL root compontent that indicates this
290
+ #sandbox is the URL root component that indicates this
200
291
  @root = "sandbox"
201
292
  end
202
293
 
203
294
  @locale = locale
204
295
  @session = session
205
- @token = session.get_access_token
206
-
207
- #There's no gurantee that @token is still valid, so be sure to handle any DropboxAuthErrors that can be raised
208
296
  end
209
297
 
210
298
  # Parse response. You probably shouldn't be calling this directly. This takes responses from the server
@@ -236,7 +324,6 @@ class DropboxClient
236
324
  rescue JSON::ParserError
237
325
  raise DropboxError.new("Unable to parse JSON response", response)
238
326
  end
239
-
240
327
  end
241
328
 
242
329
 
@@ -245,7 +332,7 @@ class DropboxClient
245
332
  # For a detailed description of what this call returns, visit:
246
333
  # https://www.dropbox.com/developers/docs#account-info
247
334
  def account_info()
248
- response = @token.get build_url("/account/info")
335
+ response = @session.do_get build_url("/account/info")
249
336
  parse_response(response)
250
337
  end
251
338
 
@@ -254,7 +341,7 @@ class DropboxClient
254
341
  # Arguments:
255
342
  # * to_path: The directory path to upload the file to. If the destination
256
343
  # directory does not yet exist, it will be created.
257
- # * file_obj: A file-like object to upload. If you would like, you can
344
+ # * file_obj: A file-like object to upload. If you would like, you can
258
345
  # pass a string as file_obj.
259
346
  # * overwrite: Whether to overwrite an existing file at the given path. [default is False]
260
347
  # If overwrite is False and a file already exists there, Dropbox
@@ -275,14 +362,13 @@ class DropboxClient
275
362
  # * a Hash containing the metadata of the newly uploaded file. The file may have a different name if it conflicted.
276
363
  #
277
364
  # Simple Example
278
- # client = DropboxClient(session, "app_folder")
365
+ # client = DropboxClient(session, :app_folder)
279
366
  # #session is a DropboxSession I've already authorized
280
367
  # client.put_file('/test_file_on_dropbox', open('/tmp/test_file'))
281
368
  # This will upload the "/tmp/test_file" from my computer into the root of my App's app folder
282
369
  # and call it "test_file_on_dropbox".
283
370
  # The file will not overwrite any pre-existing file.
284
371
  def put_file(to_path, file_obj, overwrite=false, parent_rev=nil)
285
-
286
372
  path = "/files_put/#{@root}#{format_path(to_path)}"
287
373
 
288
374
  params = {
@@ -291,9 +377,9 @@ class DropboxClient
291
377
 
292
378
  params['parent_rev'] = parent_rev unless parent_rev.nil?
293
379
 
294
- response = @token.put(build_url(path, params, content_server=true),
295
- file_obj,
296
- "Content-Type" => "application/octet-stream")
380
+ response = @session.do_put(build_url(path, params, content_server=true),
381
+ {"Content-Type" => "application/octet-stream"},
382
+ file_obj)
297
383
 
298
384
  parse_response(response)
299
385
  end
@@ -311,7 +397,7 @@ class DropboxClient
311
397
  params['rev'] = rev.to_s if rev
312
398
 
313
399
  path = "/files/#{@root}#{format_path(from_path)}"
314
- response = @token.get(build_url(path, params, content_server=true))
400
+ response = @session.do_get build_url(path, params, content_server=true)
315
401
 
316
402
  parse_response(response, raw=true)
317
403
  end
@@ -336,7 +422,7 @@ class DropboxClient
336
422
  "from_path" => format_path(from_path, false),
337
423
  "to_path" => format_path(to_path, false),
338
424
  }
339
- response = @token.get(build_url("/fileops/copy", params))
425
+ response = @session.do_post build_url("/fileops/copy", params)
340
426
  parse_response(response)
341
427
  end
342
428
 
@@ -352,9 +438,9 @@ class DropboxClient
352
438
  def file_create_folder(path)
353
439
  params = {
354
440
  "root" => @root,
355
- "path" => format_path(from_path, false),
441
+ "path" => format_path(path, false),
356
442
  }
357
- response = @token.get(build_url("/fileops/create_folder", params))
443
+ response = @session.do_post build_url("/fileops/create_folder", params)
358
444
 
359
445
  parse_response(response)
360
446
  end
@@ -371,9 +457,9 @@ class DropboxClient
371
457
  def file_delete(path)
372
458
  params = {
373
459
  "root" => @root,
374
- "path" => format_path(from_path, false),
460
+ "path" => format_path(path, false),
375
461
  }
376
- response = @token.get(build_url("/fileops/delete", params))
462
+ response = @session.do_post build_url("/fileops/delete", params)
377
463
  parse_response(response)
378
464
  end
379
465
 
@@ -394,7 +480,7 @@ class DropboxClient
394
480
  "from_path" => format_path(from_path, false),
395
481
  "to_path" => format_path(to_path, false),
396
482
  }
397
- response = @token.post(build_url("/fileops/move", params))
483
+ response = @session.do_post build_url("/fileops/move", params)
398
484
  parse_response(response)
399
485
  end
400
486
 
@@ -425,7 +511,7 @@ class DropboxClient
425
511
 
426
512
  params["hash"] = hash if hash
427
513
 
428
- response = @token.get build_url("/metadata/#{@root}#{format_path(path)}", params=params)
514
+ response = @session.do_get build_url("/metadata/#{@root}#{format_path(path)}", params=params)
429
515
  if response.kind_of? Net::HTTPRedirection
430
516
  raise DropboxNotModified.new("metadata not modified")
431
517
  end
@@ -447,16 +533,14 @@ class DropboxClient
447
533
  # inside path. For a detailed description of what this call returns, visit:
448
534
  # https://www.dropbox.com/developers/docs#search
449
535
  def search(path, query, file_limit=10000, include_deleted=false)
450
-
451
536
  params = {
452
537
  'query' => query,
453
538
  'file_limit' => file_limit.to_s,
454
539
  'include_deleted' => include_deleted.to_s
455
540
  }
456
541
 
457
- response = @token.get(build_url("/search/#{@root}#{format_path(path)}", params))
542
+ response = @session.do_get build_url("/search/#{@root}#{format_path(path)}", params)
458
543
  parse_response(response)
459
-
460
544
  end
461
545
 
462
546
  # Retrive revisions of a file
@@ -478,7 +562,7 @@ class DropboxClient
478
562
  'rev_limit' => rev_limit.to_s
479
563
  }
480
564
 
481
- response = @token.get(build_url("/revisions/#{@root}#{format_path(path)}", params))
565
+ response = @session.do_get build_url("/revisions/#{@root}#{format_path(path)}", params)
482
566
  parse_response(response)
483
567
 
484
568
  end
@@ -498,7 +582,7 @@ class DropboxClient
498
582
  'rev' => rev.to_s
499
583
  }
500
584
 
501
- response = @token.get(build_url("/restore/#{@root}#{format_path(path)}", params))
585
+ response = @session.do_post build_url("/restore/#{@root}#{format_path(path)}", params)
502
586
  parse_response(response)
503
587
  end
504
588
 
@@ -515,7 +599,7 @@ class DropboxClient
515
599
  # * A Hash object that looks like the following:
516
600
  # {'url': 'https://dl.dropbox.com/0/view/wvxv1fw6on24qw7/file.mov', 'expires': 'Thu, 16 Sep 2011 01:01:25 +0000'}
517
601
  def media(path)
518
- response = @token.get(build_url("/media/#{@root}#{format_path(path)}"))
602
+ response = @session.do_get build_url("/media/#{@root}#{format_path(path)}")
519
603
  parse_response(response)
520
604
  end
521
605
 
@@ -534,7 +618,7 @@ class DropboxClient
534
618
  # For a detailed description of what this call returns, visit:
535
619
  # https://www.dropbox.com/developers/docs#share
536
620
  def shares(path)
537
- response = @token.get(build_url("/shares/#{@root}#{format_path(path)}"))
621
+ response = @session.do_get build_url("/shares/#{@root}#{format_path(path)}")
538
622
  parse_response(response)
539
623
  end
540
624
 
@@ -560,14 +644,14 @@ class DropboxClient
560
644
 
561
645
  url = build_url("/thumbnails/#{@root}#{from_path}", params, content_server=true)
562
646
 
563
- response = @token.get(url)
647
+ response = @session.do_get url
564
648
  parse_response(response, raw=true)
565
649
  end
566
650
 
567
651
  def build_url(url, params=nil, content_server=false) # :nodoc:
568
652
  port = 443
569
- host = content_server ? DROPBOX_API_CONTENT_SERVER : DROPBOX_API_SERVER
570
- versioned_url = "/#{API_VERSION}#{url}"
653
+ host = content_server ? Dropbox::API_CONTENT_SERVER : Dropbox::API_SERVER
654
+ versioned_url = "/#{Dropbox::API_VERSION}#{url}"
571
655
 
572
656
  target = URI::Generic.new("https", nil, host, port, nil, versioned_url, nil, nil, nil)
573
657
 
@@ -585,23 +669,22 @@ class DropboxClient
585
669
 
586
670
  target.to_s
587
671
  end
588
- end
589
672
 
673
+ #From the oauth spec plus "/". Slash should not be ecsaped
674
+ RESERVED_CHARACTERS = /[^a-zA-Z0-9\-\.\_\~\/]/
590
675
 
591
- #From the oauth spec plus "/". Slash should not be ecsaped
592
- RESERVED_CHARACTERS = /[^a-zA-Z0-9\-\.\_\~\/]/
676
+ def format_path(path, escape=true) # :nodoc:
677
+ path = path.gsub(/\/+/,"/")
678
+ # replace multiple slashes with a single one
593
679
 
594
- def format_path(path, escape=true) # :nodoc:
595
- path = path.gsub(/\/+/,"/")
596
- # replace multiple slashes with a single one
680
+ path = path.gsub(/^\/?/,"/")
681
+ # ensure the path starts with a slash
597
682
 
598
- path = path.gsub(/^\/?/,"/")
599
- # ensure the path starts with a slash
683
+ path.gsub(/\/?$/,"")
684
+ # ensure the path doesn't end with a slash
600
685
 
601
- path.gsub(/\/?$/,"")
602
- # ensure the path doesn't end with a slash
686
+ return URI.escape(path, RESERVED_CHARACTERS) if escape
687
+ path
688
+ end
603
689
 
604
- return URI.escape(path, RESERVED_CHARACTERS) if escape
605
- path
606
690
  end
607
-
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dropbox-sdk
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31098137
5
- prerelease: 4
4
+ hash: 13
5
+ prerelease:
6
6
  segments:
7
7
  - 1
8
- - 0
9
- - beta
10
- version: 1.0.beta
8
+ - 1
9
+ version: "1.1"
11
10
  platform: ruby
12
11
  authors:
13
12
  - Dropbox, Inc.
@@ -15,10 +14,10 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2011-09-28 00:00:00 Z
17
+ date: 2011-10-28 00:00:00 Z
19
18
  dependencies:
20
19
  - !ruby/object:Gem::Dependency
21
- name: oauth
20
+ name: json
22
21
  prerelease: false
23
22
  requirement: &id001 !ruby/object:Gem::Requirement
24
23
  none: false
@@ -31,20 +30,6 @@ dependencies:
31
30
  version: "0"
32
31
  type: :runtime
33
32
  version_requirements: *id001
34
- - !ruby/object:Gem::Dependency
35
- name: json
36
- prerelease: false
37
- requirement: &id002 !ruby/object:Gem::Requirement
38
- none: false
39
- requirements:
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- hash: 3
43
- segments:
44
- - 0
45
- version: "0"
46
- type: :runtime
47
- version_requirements: *id002
48
33
  description: " A library that provides a plain function-call interface to the\n Dropbox API web endpoints.\n"
49
34
  email:
50
35
  - support-api@dropbox.com
@@ -82,14 +67,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
82
67
  required_rubygems_version: !ruby/object:Gem::Requirement
83
68
  none: false
84
69
  requirements:
85
- - - ">"
70
+ - - ">="
86
71
  - !ruby/object:Gem::Version
87
- hash: 25
72
+ hash: 3
88
73
  segments:
89
- - 1
90
- - 3
91
- - 1
92
- version: 1.3.1
74
+ - 0
75
+ version: "0"
93
76
  requirements: []
94
77
 
95
78
  rubyforge_project: