voorhees 0.2.0
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/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.markdown +240 -0
- data/Rakefile +55 -0
- data/VERSION +1 -0
- data/examples/twitter.rb +85 -0
- data/lib/voorhees.rb +6 -0
- data/lib/voorhees/config.rb +87 -0
- data/lib/voorhees/exceptions.rb +9 -0
- data/lib/voorhees/logging.rb +5 -0
- data/lib/voorhees/request.rb +146 -0
- data/lib/voorhees/resource.rb +141 -0
- data/lib/voorhees/response.rb +36 -0
- data/spec/config_spec.rb +144 -0
- data/spec/fixtures/resources.rb +18 -0
- data/spec/fixtures/user.json +32 -0
- data/spec/fixtures/users.json +1 -0
- data/spec/request_spec.rb +455 -0
- data/spec/resource_spec.rb +335 -0
- data/spec/response_spec.rb +93 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/voorhees_spec.rb +1 -0
- data/voorhees.gemspec +65 -0
- metadata +85 -0
@@ -0,0 +1,335 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe User do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
load_json
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "ClassMethods" do
|
10
|
+
describe "new_from_json" do
|
11
|
+
|
12
|
+
it "Should create a new User" do
|
13
|
+
User.should_receive(:new).once.and_return(mock(:user, :null_object => true))
|
14
|
+
user_from_json
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should assign the JSON to User#raw_json" do
|
18
|
+
mock_user = mock(:user, :null_object => true)
|
19
|
+
User.stub!(:new).and_return(mock_user)
|
20
|
+
mock_user.should_receive(:raw_json=).with(@json)
|
21
|
+
user_from_json
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should assign the hierarchy to User#json_hierarchy" do
|
25
|
+
mock_user = mock(:user, :null_object => true)
|
26
|
+
User.stub!(:new).and_return(mock_user)
|
27
|
+
mock_user.should_receive(:json_hierarchy=).with(@hierarchy)
|
28
|
+
user_from_json
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should return the new user" do
|
32
|
+
user_from_json.should be_an_instance_of(User)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "json_request" do
|
37
|
+
|
38
|
+
before :each do
|
39
|
+
@json_string= "{}"
|
40
|
+
@json_hash = {}
|
41
|
+
|
42
|
+
@request = mock(:request, :null_object => true)
|
43
|
+
@response = mock(:response, :null_object => true)
|
44
|
+
@objects = [mock(:object)]
|
45
|
+
|
46
|
+
Voorhees::Request.stub!(:new).and_return(@request)
|
47
|
+
@request.stub!(:perform).and_return(@response)
|
48
|
+
|
49
|
+
@response.stub!(:to_objects).and_return(@objects)
|
50
|
+
@response.stub!(:json).and_return(@json_hash)
|
51
|
+
@response.stub!(:body).and_return(@json_string)
|
52
|
+
end
|
53
|
+
|
54
|
+
def perform_request
|
55
|
+
User.json_request{}
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
it "should call Request.new with the current class if no class is passed" do
|
60
|
+
Voorhees::Request.should_receive(:new).with(User).and_return(@request)
|
61
|
+
perform_request
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should call Request.new with the specified class if a class is passed" do
|
65
|
+
Voorhees::Request.should_receive(:new).with(Message).and_return(@request)
|
66
|
+
User.json_request(:class => Message) do |request|
|
67
|
+
# ...
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
it "should yeild a request" do
|
73
|
+
User.json_request do |r|
|
74
|
+
r.should == @request
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should raise a LocalJumpError exception if a block is not given" do
|
79
|
+
lambda{
|
80
|
+
User.json_request
|
81
|
+
}.should raise_error(LocalJumpError)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should implicitly call Request#perform" do
|
85
|
+
@request.should_receive(:perform).once
|
86
|
+
perform_request
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should return the result of Response#to_objects if :returning is not set" do
|
90
|
+
perform_request.should == @objects
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should return the JSON string if :returning is set to :raw" do
|
94
|
+
User.json_request(:returning => :raw){}.should == @json_string
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should return the JSON hash if :returning is set to :json" do
|
98
|
+
User.json_request(:returning => :json){}.should == @json_hash
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should return the objects string if :returning is set to :objects" do
|
102
|
+
User.json_request(:returning => :objects){}.should == @objects
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should return the response if :returning is set to :response" do
|
106
|
+
User.json_request(:returning => :response){}.should == @response
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "json_service" do
|
112
|
+
|
113
|
+
before :each do
|
114
|
+
@service_name = :list
|
115
|
+
@service_attrs = {
|
116
|
+
:timeout => 100,
|
117
|
+
:required => [:monkeys]
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
def define_service
|
122
|
+
User.json_service @service_name, @service_attrs
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should define a method with the same name as the service" do
|
126
|
+
User.should_not respond_to(@service_name)
|
127
|
+
define_service
|
128
|
+
User.should respond_to(@service_name)
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "calling the defined method" do
|
132
|
+
|
133
|
+
before :each do
|
134
|
+
define_service
|
135
|
+
|
136
|
+
@request = mock(:request, :null_object => true)
|
137
|
+
@response = mock(:response, :null_object => true)
|
138
|
+
@objects = [mock(:object)]
|
139
|
+
|
140
|
+
Voorhees::Request.stub!(:new).and_return(@request)
|
141
|
+
@request.stub!(:perform).and_return(@response)
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should call User#json_request" do
|
145
|
+
User.should_receive(:json_request).and_return(@response)
|
146
|
+
User.list
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should pass service attributes onto the request" do
|
150
|
+
@service_attrs.each do |key, value|
|
151
|
+
@request.should_receive("#{key}=").with(value)
|
152
|
+
end
|
153
|
+
User.list
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should use any hash passed in to set the request parameters" do
|
157
|
+
params = {:monkeys => true}
|
158
|
+
@request.should_receive(:parameters=).with(params)
|
159
|
+
User.list(params)
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should return the result of Response#to_objects" do
|
163
|
+
@response.should_receive(:to_objects).and_return(@objects)
|
164
|
+
User.list.should == @objects
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe "InstanceMethods" do
|
171
|
+
|
172
|
+
describe "#raw_json" do
|
173
|
+
it "should contain the raw json" do
|
174
|
+
user_from_json.raw_json.should == @json
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe "#json_attributes" do
|
179
|
+
it "should contain symbols of the keys of the attributes available as underscored" do
|
180
|
+
user_from_json.json_attributes.sort.should == [:address, :camel_case, :email, :id, :messages, :name, :pet, :username]
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "#json_request" do
|
185
|
+
|
186
|
+
before :each do
|
187
|
+
@request = mock(:request, :null_object => true)
|
188
|
+
@response = mock(:response, :null_object => true)
|
189
|
+
|
190
|
+
Voorhees::Request.stub!(:new).and_return(@request)
|
191
|
+
@request.stub!(:perform).and_return(@response)
|
192
|
+
end
|
193
|
+
|
194
|
+
def perform_request
|
195
|
+
user_from_json.json_request{}
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should pass the request to the class method" do
|
199
|
+
User.should_receive(:json_request)
|
200
|
+
user_from_json.json_request{}
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should raise a LocalJumpError exception if a block is not given" do
|
204
|
+
lambda{
|
205
|
+
user_from_json.json_request
|
206
|
+
}.should raise_error(LocalJumpError)
|
207
|
+
end
|
208
|
+
|
209
|
+
it "should implicitly call Request#perform" do
|
210
|
+
@request.should_receive(:perform).once
|
211
|
+
perform_request
|
212
|
+
end
|
213
|
+
|
214
|
+
it "should return the result of Request#perform" do
|
215
|
+
perform_request.should == @response
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
219
|
+
|
220
|
+
describe "calling assignment method with name of a json attribute" do
|
221
|
+
|
222
|
+
it "should define an assignment method" do
|
223
|
+
user = user_from_json
|
224
|
+
|
225
|
+
user.should_not respond_to(:email=)
|
226
|
+
user.email = "test"
|
227
|
+
user.should respond_to(:email=)
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should assign the value" do
|
231
|
+
user = user_from_json
|
232
|
+
new_email = "a_new_address@example.com"
|
233
|
+
|
234
|
+
user.email = new_email
|
235
|
+
user.email.should == new_email
|
236
|
+
end
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
describe "calling method with the name of a json attribute" do
|
241
|
+
|
242
|
+
it "should return the correct data from #id" do
|
243
|
+
user = user_from_json
|
244
|
+
user.id.should == @json["id"]
|
245
|
+
end
|
246
|
+
|
247
|
+
it "should define a method of the same name" do
|
248
|
+
user = user_from_json
|
249
|
+
|
250
|
+
user.should_not respond_to(:email)
|
251
|
+
user.email
|
252
|
+
user.should respond_to(:email)
|
253
|
+
end
|
254
|
+
|
255
|
+
it "should return the correct data from defined methods" do
|
256
|
+
user = user_from_json
|
257
|
+
|
258
|
+
user.email # first access, now it's defined
|
259
|
+
user.email.should == @json["email"]
|
260
|
+
end
|
261
|
+
|
262
|
+
describe "which is a simple value" do
|
263
|
+
it "should return the value of the attribute" do
|
264
|
+
user_from_json.email.should == @json["email"]
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
describe "which is camelCase in the JSON" do
|
269
|
+
it "should return the value of the attribute" do
|
270
|
+
user_from_json.camel_case.should == @json["camelCase"]
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
describe "which is a collection" do
|
275
|
+
it "should return an array" do
|
276
|
+
user_from_json.messages.should be_an_instance_of(Array)
|
277
|
+
end
|
278
|
+
|
279
|
+
it "should infer the type of objects based on the collection name" do
|
280
|
+
user_from_json.messages.each do |m|
|
281
|
+
m.should be_an_instance_of(Message)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
describe "which is a sub-object" do
|
287
|
+
|
288
|
+
it "should return as a Hash if the hierarchy is not defined" do
|
289
|
+
@hierarchy = {
|
290
|
+
}
|
291
|
+
user_from_json.pet.should be_a(Hash)
|
292
|
+
end
|
293
|
+
|
294
|
+
it "should return as the right class if the hierarchy is defined as symbol" do
|
295
|
+
@hierarchy = {
|
296
|
+
:address => :address
|
297
|
+
}
|
298
|
+
user_from_json.address.should be_a(Address)
|
299
|
+
end
|
300
|
+
|
301
|
+
it "should return as the right class if the hierarchy is defined as Class" do
|
302
|
+
@hierarchy = {
|
303
|
+
:address => Address
|
304
|
+
}
|
305
|
+
user_from_json.address.should be_a(Address)
|
306
|
+
end
|
307
|
+
|
308
|
+
it "should return as the right class for multiple depths" do
|
309
|
+
@hierarchy = {
|
310
|
+
:address => [Address, {
|
311
|
+
:coords => LatLon
|
312
|
+
}]
|
313
|
+
}
|
314
|
+
user_from_json.address.coords.should be_a(LatLon)
|
315
|
+
end
|
316
|
+
|
317
|
+
end
|
318
|
+
|
319
|
+
end
|
320
|
+
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
def load_json
|
325
|
+
body = ''
|
326
|
+
path = File.expand_path(File.dirname(__FILE__) + '/fixtures/user.json')
|
327
|
+
File.open(path, 'r') do |f|
|
328
|
+
body = f.read
|
329
|
+
end
|
330
|
+
@json = JSON.parse(body)
|
331
|
+
end
|
332
|
+
|
333
|
+
def user_from_json
|
334
|
+
User.new_from_json(@json, @hierarchy)
|
335
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Voorhees::Response do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
User.stub!(:new_from_json).and_return(User.new)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "to_objects" do
|
10
|
+
|
11
|
+
describe "with no class set" do
|
12
|
+
|
13
|
+
before :each do
|
14
|
+
@klass = nil
|
15
|
+
build_response(:users)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should return nil" do
|
19
|
+
@response.to_objects.should be_nil
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "with a class which does not have Voorhees::Resource mixed in" do
|
25
|
+
|
26
|
+
before :each do
|
27
|
+
@klass = NotResource
|
28
|
+
build_response(:users)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should raise a Voorhees::NotResourceError exception" do
|
32
|
+
lambda{
|
33
|
+
@response.to_objects
|
34
|
+
}.should raise_error(Voorhees::NotResourceError)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "with a class which has Voorhees::Resource mixed in" do
|
40
|
+
|
41
|
+
before :each do
|
42
|
+
@klass = User
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "with JSON containing an array of 2 items" do
|
46
|
+
|
47
|
+
before :each do
|
48
|
+
build_response(:users)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should return an array of 2 objects of the right class" do
|
52
|
+
users = @response.to_objects
|
53
|
+
users.length.should == 2
|
54
|
+
users.each do |u|
|
55
|
+
u.should be_an_instance_of(User)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should create objects by sending the JSON and hierarchy to Class.new_from_json" do
|
60
|
+
User.should_receive(:new_from_json).with(@response.json[0], @hierarchy).ordered
|
61
|
+
User.should_receive(:new_from_json).with(@response.json[1], @hierarchy).ordered
|
62
|
+
@response.to_objects
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "with JSON containing one item" do
|
67
|
+
|
68
|
+
before :each do
|
69
|
+
build_response(:user)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should return one object of the right class" do
|
73
|
+
user = @response.to_objects
|
74
|
+
user.should be_an_instance_of(User)
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def build_response(fixture)
|
83
|
+
body = ''
|
84
|
+
path = File.expand_path(File.dirname(__FILE__) + "/fixtures/#{fixture}.json")
|
85
|
+
File.open(path, 'r') do |f|
|
86
|
+
body = f.read
|
87
|
+
end
|
88
|
+
|
89
|
+
@hierarchy = {
|
90
|
+
:address => Address
|
91
|
+
}
|
92
|
+
@response = Voorhees::Response.new(body, @klass, @hierarchy)
|
93
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'json'
|
4
|
+
require 'active_support'
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
7
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
8
|
+
require 'voorhees'
|
9
|
+
|
10
|
+
require File.expand_path(File.dirname(__FILE__) + '/fixtures/resources')
|
11
|
+
|
12
|
+
Spec::Runner.configure do |config|
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
# allow sorting by symbol
|
17
|
+
class Symbol
|
18
|
+
def <=>(a)
|
19
|
+
self.to_s <=> a.to_s
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|