thounds 0.0.1

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,93 @@
1
+ require 'faraday'
2
+ require File.expand_path('../version', __FILE__)
3
+
4
+ module Thounds
5
+ # Defines constants and methods related to configuration
6
+ module Configuration
7
+ # An array of valid keys in the options hash when configuring a {Thounds::API}
8
+ VALID_OPTIONS_KEYS = [
9
+ :adapter,
10
+ :consumer_key,
11
+ :consumer_secret,
12
+ :endpoint,
13
+ :format,
14
+ :oauth_token,
15
+ :oauth_token_secret,
16
+ :proxy,
17
+ :user_agent].freeze
18
+
19
+ # An array of valid request/response formats
20
+ #
21
+ # @note Not all methods support the XML format.
22
+ VALID_FORMATS = [
23
+ :json,
24
+ :xml].freeze
25
+
26
+ # The adapter that will be used to connect if none is set
27
+ #
28
+ # @note The default faraday adapter is Net::HTTP.
29
+ DEFAULT_ADAPTER = Faraday.default_adapter
30
+
31
+ # By default, don't set an application key
32
+ DEFAULT_CONSUMER_KEY = nil
33
+
34
+ # By default, don't set an application secret
35
+ DEFAULT_CONSUMER_SECRET = nil
36
+
37
+ # The endpoint that will be used to connect if none is set
38
+ #
39
+ # @note This is configurable in case you want to use HTTP instead of HTTPS, specify a different API version, or use a Thounds-compatible endpoint.
40
+ DEFAULT_ENDPOINT = 'http://thounds.local:3000/'.freeze
41
+
42
+ # The response format appended to the path and sent in the 'Accept' header if none is set
43
+ #
44
+ # @note JSON is preferred over XML because it is more concise and faster to parse.
45
+ DEFAULT_FORMAT = :json
46
+
47
+ # By default, don't set a user oauth token
48
+ DEFAULT_OAUTH_TOKEN = nil
49
+
50
+ # By default, don't set a user oauth secret
51
+ DEFAULT_OAUTH_TOKEN_SECRET = nil
52
+
53
+ # By default, don't use a proxy server
54
+ DEFAULT_PROXY = nil
55
+
56
+ # The user agent that will be sent to the API endpoint if none is set
57
+ DEFAULT_USER_AGENT = "Thounds Ruby Gem #{Thounds::VERSION}".freeze
58
+
59
+ # @private
60
+ attr_accessor *VALID_OPTIONS_KEYS
61
+
62
+ # When this module is extended, set all configuration options to their default values
63
+ def self.extended(base)
64
+ base.reset
65
+ end
66
+
67
+ # Convenience method to allow configuration options to be set in a block
68
+ def configure
69
+ yield self
70
+ end
71
+
72
+ # Create a hash of options and their values
73
+ def options
74
+ VALID_OPTIONS_KEYS.inject({}) do |option, key|
75
+ option.merge!(key => send(key))
76
+ end
77
+ end
78
+
79
+ # Reset all configuration options to defaults
80
+ def reset
81
+ self.adapter = DEFAULT_ADAPTER
82
+ self.consumer_key = DEFAULT_CONSUMER_KEY
83
+ self.consumer_secret = DEFAULT_CONSUMER_SECRET
84
+ self.endpoint = DEFAULT_ENDPOINT
85
+ self.format = DEFAULT_FORMAT
86
+ self.oauth_token = DEFAULT_OAUTH_TOKEN
87
+ self.oauth_token_secret = DEFAULT_OAUTH_TOKEN_SECRET
88
+ self.proxy = DEFAULT_PROXY
89
+ self.user_agent = DEFAULT_USER_AGENT
90
+ self
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,33 @@
1
+ require 'faraday_middleware'
2
+ Dir[File.expand_path('../../faraday/*.rb', __FILE__)].each{|f| require f}
3
+
4
+ module Thounds
5
+ # @private
6
+ module Connection
7
+ private
8
+
9
+ def connection(raw=false)
10
+ options = {
11
+ :headers => {'Accept' => "application/#{format}", 'User-Agent' => user_agent},
12
+ :proxy => proxy,
13
+ :ssl => {:verify => false},
14
+ :url => api_endpoint,
15
+ }
16
+
17
+ Faraday::Connection.new(options) do |connection|
18
+ connection.use Faraday::Request::Multipart
19
+ connection.use Faraday::Request::OAuth, authentication if authenticated?
20
+ connection.adapter(adapter)
21
+ connection.use Faraday::Response::RaiseHttp5xx
22
+ unless raw
23
+ case format.to_s.downcase
24
+ when 'json' then connection.use Faraday::Response::ParseJson
25
+ when 'xml' then connection.use Faraday::Response::ParseXml
26
+ end
27
+ end
28
+ connection.use Faraday::Response::RaiseHttp4xx
29
+ connection.use Faraday::Response::Mashify unless raw
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,28 @@
1
+ module Thounds
2
+ # Custom error class for rescuing from all Thounds errors
3
+ class Error < StandardError; end
4
+
5
+ # Raised when Thounds returns the HTTP status code 400
6
+ class BadRequest < Error; end
7
+
8
+ # Raised when Thounds returns the HTTP status code 401
9
+ class Unauthorized < Error; end
10
+
11
+ # Raised when Thounds returns the HTTP status code 403
12
+ class Forbidden < Error; end
13
+
14
+ # Raised when Thounds returns the HTTP status code 404
15
+ class NotFound < Error; end
16
+
17
+ # Raised when Thounds returns the HTTP status code 406
18
+ class NotAcceptable < Error; end
19
+
20
+ # Raised when Thounds returns the HTTP status code 500
21
+ class InternalServerError < Error; end
22
+
23
+ # Raised when Thounds returns the HTTP status code 502
24
+ class BadGateway < Error; end
25
+
26
+ # Raised when Thounds returns the HTTP status code 503
27
+ class ServiceUnavailable < Error; end
28
+ end
@@ -0,0 +1,24 @@
1
+ module Thounds
2
+ # Defines HTTP request methods
3
+ module Request
4
+ # Perform an HTTP request
5
+ def request(method, path, options={}, raw=false)
6
+ response = connection(raw).send(method) do |request|
7
+ case method
8
+ when :get, :delete
9
+ request.url(formatted_path(path), options)
10
+ when :post, :put
11
+ request.path = formatted_path(path)
12
+ request.body = options unless options.empty?
13
+ end
14
+ end
15
+ raw ? response : response.body
16
+ end
17
+
18
+ private
19
+
20
+ def formatted_path(path)
21
+ path
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,4 @@
1
+ module Thounds
2
+ # The version of the gem
3
+ VERSION = '0.0.1'.freeze unless defined?(::Thounds::VERSION)
4
+ end
@@ -0,0 +1,31 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ describe Faraday::Response do
4
+ before do
5
+ @client = Thounds::Client.new
6
+ end
7
+
8
+ {
9
+ 400 => Thounds::BadRequest,
10
+ 401 => Thounds::Unauthorized,
11
+ 403 => Thounds::Forbidden,
12
+ 404 => Thounds::NotFound,
13
+ 406 => Thounds::NotAcceptable,
14
+ 500 => Thounds::InternalServerError,
15
+ 502 => Thounds::BadGateway,
16
+ 503 => Thounds::ServiceUnavailable,
17
+ }.each do |status, exception|
18
+ context "when HTTP status is #{status}" do
19
+
20
+ before do
21
+ stub_get('users/171').to_return(:status => status)
22
+ end
23
+
24
+ it "should raise #{exception.name} error" do
25
+ lambda do
26
+ @client.users(171) {|user| user}
27
+ end.should raise_error(exception)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1 @@
1
+ {"friend_of_mine":true,"blog_url":null,"created_at":"2009-06-30T09:52:15Z","city":"30027","friendship_id":2914,"profile_url":"smashing","about":null,"avatar":"http://gravatar.com/avatar/8e6e5c47e1d1b87a322fd2bac7f09d2e.png?d=http%3A%2F%2Fthounds.com%2Fimages%2Favatar-big.jpg&r=PG&s=77","country":"Italy","default_thound":{"privacy":"contacts","public_url":"http://thounds.local:3000/t/6245c9","created_at":"2009-07-24T13:08:08Z","bpm":60,"video":false,"lead_track_id":961,"comments_count":0,"mix_url":"http://thounds.local:3000/thounds/611/stream","user_id":31,"plays_count":6,"mix_duration":0,"tracks":[{"title":"Smash Vs. Fraioli from http://www.randomthink.net/labs/html5drums/","duration":0,"created_at":"2009-07-24T13:08:08Z","privacy":"contacts","offset":0,"path":"thounds/611/tracks/961.mp3","uri":"http://thounds.local:3000/tracks/961/stream","youtube_id":null,"thound_id":611,"lat":null,"user_id":31,"host":"s3","lng":null,"delay":0,"cover":null,"id":961,"user":{"city":"30027","avatar":"http://gravatar.com/avatar/8e6e5c47e1d1b87a322fd2bac7f09d2e.png?d=http%3A%2F%2Fwww.thounds.com%2Fimages%2Favatar-big.jpg&r=PG&s=77","country":"Italy","name":"Smash","id":31},"tags":"drum"},{"title":"yo!","duration":0,"created_at":"2010-04-01T08:17:49Z","privacy":"contacts","offset":133,"path":"/mp3/thound_user_171_mix_thound_611_1270109855794.mp3","uri":"http://stage.thounds.astrails.com//mp3/thound_user_171_mix_thound_611_1270109855794.mp3","youtube_id":null,"thound_id":611,"lat":null,"user_id":171,"host":"stage.thounds.astrails.com","lng":null,"delay":0,"cover":null,"id":2223,"user":{"city":"Treviso","avatar":"http://gravatar.com/avatar/5420033d57945e871b468e1a225cb079.png?d=http%3A%2F%2Fwww.thounds.com%2Fimages%2Favatar-big.jpg&r=PG&s=77","country":"Guinea","name":"Giovanni \u3072\u3089\u304c\u306a","id":171},"tags":"ciao"}],"id":611,"tags":"drum ciao","public_id":"6245c9"},"is_new_user":false,"name":"Smash","id":31,"site_url":null,"tags":[]}
@@ -0,0 +1,54 @@
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_group 'Thounds', 'lib/thounds'
4
+ add_group 'Faraday Middleware', 'lib/faraday'
5
+ add_group 'Specs', 'spec'
6
+ end
7
+
8
+ require File.expand_path('../../lib/thounds', __FILE__)
9
+
10
+ require 'rspec'
11
+ require 'webmock/rspec'
12
+ RSpec.configure do |config|
13
+ config.include WebMock::API
14
+ end
15
+
16
+ def a_delete(path)
17
+ a_request(:delete, Thounds.endpoint + path)
18
+ end
19
+
20
+ def a_get(path)
21
+ a_request(:get, Thounds.endpoint + path)
22
+ end
23
+
24
+ def a_post(path)
25
+ a_request(:post, Thounds.endpoint + path)
26
+ end
27
+
28
+ def a_put(path)
29
+ a_request(:put, Thounds.endpoint + path)
30
+ end
31
+
32
+ def stub_delete(path)
33
+ stub_request(:delete, Thounds.endpoint + path)
34
+ end
35
+
36
+ def stub_get(path)
37
+ stub_request(:get, Thounds.endpoint + path)
38
+ end
39
+
40
+ def stub_post(path)
41
+ stub_request(:post, Thounds.endpoint + path)
42
+ end
43
+
44
+ def stub_put(path)
45
+ stub_request(:put, Thounds.endpoint + path)
46
+ end
47
+
48
+ def fixture_path
49
+ File.expand_path("../fixtures", __FILE__)
50
+ end
51
+
52
+ def fixture(file)
53
+ File.new(fixture_path + '/' + file)
54
+ end
@@ -0,0 +1,68 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ describe Thounds::API do
4
+ before do
5
+ @keys = Thounds::Configuration::VALID_OPTIONS_KEYS
6
+ end
7
+
8
+ context "with module configuration" do
9
+
10
+ before do
11
+ Thounds.configure do |config|
12
+ @keys.each do |key|
13
+ config.send("#{key}=", key)
14
+ end
15
+ end
16
+ end
17
+
18
+ after do
19
+ Thounds.reset
20
+ end
21
+
22
+ it "should inherit module configuration" do
23
+ api = Thounds::API.new
24
+ @keys.each do |key|
25
+ api.send(key).should == key
26
+ end
27
+ end
28
+
29
+ context "with class configuration" do
30
+
31
+ before do
32
+ @configuration = {
33
+ :consumer_key => 'CK',
34
+ :consumer_secret => 'CS',
35
+ :oauth_token => 'OT',
36
+ :oauth_token_secret => 'OS',
37
+ :adapter => :typhoeus,
38
+ :endpoint => 'http://tumblr.com/',
39
+ :format => :xml,
40
+ :proxy => 'http://giovanni:secret@proxy.example.com:8080',
41
+ :user_agent => 'Custom User Agent',
42
+ }
43
+ end
44
+
45
+ context "during initialization"
46
+
47
+ it "should override module configuration" do
48
+ api = Thounds::API.new(@configuration)
49
+ @keys.each do |key|
50
+ api.send(key).should == @configuration[key]
51
+ end
52
+ end
53
+
54
+ context "after initilization" do
55
+
56
+ it "should override module configuration after initialization" do
57
+ api = Thounds::API.new
58
+ @configuration.each do |key, value|
59
+ api.send("#{key}=", value)
60
+ end
61
+ @keys.each do |key|
62
+ api.send(key).should == @configuration[key]
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,10 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ describe Thounds::Client do
4
+ it "should connect using the endpoint configuration" do
5
+ client = Thounds::Client.new
6
+ endpoint = URI.parse(client.api_endpoint)
7
+ connection = client.send(:connection).build_url(nil).to_s
8
+ connection.should == endpoint.to_s
9
+ end
10
+ end
@@ -0,0 +1,358 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ describe Thounds do
4
+ after do
5
+ Thounds.reset
6
+ end
7
+
8
+ context "when delegating to a client" do
9
+
10
+ before do
11
+ stub_get("users/31").
12
+ to_return(:body => fixture("user_31.js"), :headers => {:content_type => "application/json; charset=utf-8"})
13
+ end
14
+
15
+ it "should get the correct resource" do
16
+ Thounds.users(31) {|user| user}
17
+ a_get("users/31").
18
+ should have_been_made
19
+ end
20
+
21
+ it "should return the same results as a client" do
22
+ class_obj = nil
23
+ client_obj = nil
24
+
25
+ Thounds.users(31) {|user| class_obj = user}
26
+ Thounds::Client.new.users(31) {|user| client_obj = user}
27
+
28
+ class_obj.should == client_obj
29
+ end
30
+
31
+ end
32
+
33
+ context "when making a request to" do
34
+
35
+ # http://developers.thounds.com/API/HomeStream
36
+ describe "GET home" do
37
+ before do
38
+ stub_get("home")
39
+ end
40
+
41
+ it "should use 'home' request path" do
42
+ Thounds.home {|r| r}.proxy.path.should == "home"
43
+ end
44
+ end
45
+
46
+ # http://developers.thounds.com/API/UserMetadata
47
+ describe "GET profile" do
48
+ before do
49
+ stub_get("profile")
50
+ end
51
+
52
+ it "should use 'profile' request path" do
53
+ Thounds.profile {|r| r}.proxy.path.should == "profile"
54
+ end
55
+ end
56
+
57
+ # http://developers.thounds.com/API/UserMetadata
58
+ describe "GET users/123" do
59
+ before do
60
+ stub_get("users/123")
61
+ end
62
+
63
+ it "should use 'users/123' request path" do
64
+ Thounds.users(123) {|r| r}.proxy.path.should == "users/123"
65
+ end
66
+ end
67
+
68
+ # http://developers.thounds.com/API/UserBand
69
+ # http://developers.thounds.com/API/UserLibrary
70
+ # http://developers.thounds.com/API/UserNotifications
71
+ ["band", "library", "notifications"].each do |member|
72
+ describe "GET profile/#{member}" do
73
+ before do
74
+ stub_get("profile/#{member}")
75
+ end
76
+
77
+ it "should use 'profile/#{member}' request path" do
78
+ Thounds.profile.send(member) {|r| r}.proxy.path.should == "profile/#{member}"
79
+ end
80
+ end
81
+ end
82
+
83
+ # http://developers.thounds.com/API/UserBand
84
+ # http://developers.thounds.com/API/UserLibrary
85
+ ["band", "library"].each do |member|
86
+ describe "GET users/123/#{member}" do
87
+ before do
88
+ stub_get("users/123/#{member}")
89
+ end
90
+
91
+ it "should use 'users/123/#{member}' request path" do
92
+ Thounds.users(123).send(member) {|r| r}.proxy.path.should == "users/123/#{member}"
93
+ end
94
+ end
95
+ end
96
+
97
+ # http://developers.thounds.com/API/UserRegistration
98
+ describe "POST users" do
99
+ before do
100
+ stub_post("users")
101
+
102
+ @options = {
103
+ :user => {
104
+ :name => "John Doe",
105
+ :email => "john@doe.com",
106
+ :country => "Italy",
107
+ :city => "Roma",
108
+ :tags => "jazz vocal"
109
+ }
110
+ }
111
+ @request = Thounds.users.post(@options) {|r| r}
112
+ end
113
+
114
+ it "should use 'users' request path" do
115
+ @request.proxy.path.should == "users"
116
+ end
117
+
118
+ it "should use POST request verb" do
119
+ @request.proxy.verb.should == :post
120
+ end
121
+
122
+ it "should include new user parameters into request" do
123
+ @request.proxy.options.should == @options
124
+ end
125
+ end
126
+
127
+ # http://developers.thounds.com/API/FriendshipRequest
128
+ describe "POST users/123/friendships" do
129
+ before do
130
+ stub_post("users/123/friendships")
131
+
132
+ @request = Thounds.users(123).friendships.post {|r| r}
133
+ end
134
+
135
+ it "should use 'users/123/friendships' request path" do
136
+ @request.proxy.path.should == "users/123/friendships"
137
+ end
138
+
139
+ it "should use POST request verb" do
140
+ @request.proxy.verb.should == :post
141
+ end
142
+ end
143
+
144
+ # http://developers.thounds.com/API/FriendshipAcceptRefuse
145
+ # http://developers.thounds.com/API/FriendshipDelete
146
+ [:put, :delete].each do |verb|
147
+ describe "#{verb.to_s.upcase} profile/friendships/123" do
148
+ before do
149
+ send("stub_#{verb}", "profile/friendships/123")
150
+
151
+ @request = Thounds.profile.friendships(123).send(verb) {|r| r}
152
+ end
153
+
154
+ it "should use 'profile/friendships/123' request path" do
155
+ @request.proxy.path.should == "profile/friendships/123"
156
+ end
157
+
158
+ it "should use #{verb.to_s.upcase} request verb" do
159
+ @request.proxy.verb.should == verb
160
+ end
161
+ end
162
+ end
163
+
164
+ # http://developers.thounds.com/API/ThoundMetadata
165
+ # http://developers.thounds.com/API/ThoundDelete
166
+ [:get, :delete].each do |verb|
167
+ describe "#{verb.to_s.upcase} thounds/123" do
168
+ before do
169
+ send("stub_#{verb}", "thounds/123")
170
+
171
+ @request = Thounds.thounds(123).send(verb) {|r| r}
172
+ end
173
+
174
+ it "should use 'thounds/123' request path" do
175
+ @request.proxy.path.should == "thounds/123"
176
+ end
177
+
178
+ it "should use #{verb.to_s.upcase} request verb" do
179
+ @request.proxy.verb.should == verb
180
+ end
181
+ end
182
+ end
183
+
184
+ # http://developers.thounds.com/API/ThoundPublicStream
185
+ describe "GET thounds/public_stream" do
186
+ before do
187
+ stub_get("thounds/public_stream")
188
+ end
189
+
190
+ it "should use 'thounds/public_stream' request path" do
191
+ Thounds.thounds.public_stream {|r| r}.proxy.path.should == "thounds/public_stream"
192
+ end
193
+ end
194
+
195
+ # http://developers.thounds.com/API/ThoundSearch
196
+ describe "GET thounds/search" do
197
+ before do
198
+ stub_get("thounds/search?q=query")
199
+
200
+ @options = {:q => "query"}
201
+ @request = Thounds.thounds.search(@options) {|r| r}
202
+ end
203
+
204
+ it "should use 'thounds/search' request path" do
205
+ @request.proxy.path.should == "thounds/search"
206
+ end
207
+
208
+ it "should include new user parameters into request" do
209
+ @request.proxy.options.should == @options
210
+ end
211
+ end
212
+
213
+ # http://developers.thounds.com/API/TrackCreate
214
+ # http://developers.thounds.com/API/ThoundCreate
215
+ describe "POST tracks" do
216
+ before do
217
+ stub_post("tracks")
218
+
219
+ @options = {
220
+ :track => {
221
+ :delay => 0,
222
+ :offset => 0,
223
+ :duration => 0,
224
+ :lat => 45.4375,
225
+ :lng => 12.3358,
226
+ :title => "My new default thound!",
227
+ :privacy => "contacts",
228
+ :thound_attributes => {
229
+ :bpm => 90
230
+ },
231
+ :tag_list => "vocal jazz",
232
+ :thoundfile => "SUQzB...",
233
+ :coverfile => "iVBOR..."
234
+ }
235
+ }
236
+ @request = Thounds.tracks.post(@options) {|r| r}
237
+ end
238
+
239
+ it "should use 'tracks' request path" do
240
+ @request.proxy.path.should == "tracks"
241
+ end
242
+
243
+ it "should use POST request verb" do
244
+ @request.proxy.verb.should == :post
245
+ end
246
+
247
+ it "should include new track parameters into request" do
248
+ @request.proxy.options.should == @options
249
+ end
250
+ end
251
+
252
+ # http://developers.thounds.com/API/TrackDelete
253
+ describe "DELETE tracks/123" do
254
+ before do
255
+ stub_delete("tracks/123")
256
+
257
+ @request = Thounds.tracks(123).delete {|r| r}
258
+ end
259
+
260
+ it "should use 'tracks/123' request path" do
261
+ @request.proxy.path.should == "tracks/123"
262
+ end
263
+
264
+ it "should use DELETE request verb" do
265
+ @request.proxy.verb.should == :delete
266
+ end
267
+ end
268
+
269
+ # http://developers.thounds.com/API/TrackNotificationsDelete
270
+ describe "DELETE track_notifications/123" do
271
+ before do
272
+ stub_delete("track_notifications/123")
273
+
274
+ @request = Thounds.track_notifications(123).delete {|r| r}
275
+ end
276
+
277
+ it "should use 'track_notifications/123' request path" do
278
+ @request.proxy.path.should == "track_notifications/123"
279
+ end
280
+
281
+ it "should use DELETE request verb" do
282
+ @request.proxy.verb.should == :delete
283
+ end
284
+ end
285
+
286
+ end
287
+
288
+ describe ".client" do
289
+ it "should be a Thounds::Client" do
290
+ Thounds.client.should be_a Thounds::Client
291
+ end
292
+ end
293
+
294
+ describe ".adapter" do
295
+ it "should return the default adapter" do
296
+ Thounds.adapter.should == Thounds::Configuration::DEFAULT_ADAPTER
297
+ end
298
+ end
299
+
300
+ describe ".adapter=" do
301
+ it "should set the adapter" do
302
+ Thounds.adapter = :typhoeus
303
+ Thounds.adapter.should == :typhoeus
304
+ end
305
+ end
306
+
307
+ describe ".endpoint" do
308
+ it "should return the default endpoint" do
309
+ Thounds.endpoint.should == Thounds::Configuration::DEFAULT_ENDPOINT
310
+ end
311
+ end
312
+
313
+ describe ".endpoint=" do
314
+ it "should set the endpoint" do
315
+ Thounds.endpoint = 'http://tumblr.com/'
316
+ Thounds.endpoint.should == 'http://tumblr.com/'
317
+ end
318
+ end
319
+
320
+ describe ".format" do
321
+ it "should return the default format" do
322
+ Thounds.format.should == Thounds::Configuration::DEFAULT_FORMAT
323
+ end
324
+ end
325
+
326
+ describe ".format=" do
327
+ it "should set the format" do
328
+ Thounds.format = 'xml'
329
+ Thounds.format.should == 'xml'
330
+ end
331
+ end
332
+
333
+ describe ".user_agent" do
334
+ it "should return the default user agent" do
335
+ Thounds.user_agent.should == Thounds::Configuration::DEFAULT_USER_AGENT
336
+ end
337
+ end
338
+
339
+ describe ".user_agent=" do
340
+ it "should set the user_agent" do
341
+ Thounds.user_agent = 'Custom User Agent'
342
+ Thounds.user_agent.should == 'Custom User Agent'
343
+ end
344
+ end
345
+
346
+ describe ".configure" do
347
+
348
+ Thounds::Configuration::VALID_OPTIONS_KEYS.each do |key|
349
+
350
+ it "should set the #{key}" do
351
+ Thounds.configure do |config|
352
+ config.send("#{key}=", key)
353
+ Thounds.send(key).should == key
354
+ end
355
+ end
356
+ end
357
+ end
358
+ end