springboard-retail 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/.yardopts +1 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +66 -0
- data/LICENSE +21 -0
- data/README.md +253 -0
- data/Rakefile +16 -0
- data/lib/springboard-retail.rb +1 -0
- data/lib/springboard/client.rb +263 -0
- data/lib/springboard/client/body.rb +12 -0
- data/lib/springboard/client/collection.rb +108 -0
- data/lib/springboard/client/errors.rb +17 -0
- data/lib/springboard/client/resource.rb +205 -0
- data/lib/springboard/client/response.rb +85 -0
- data/lib/springboard/client/uri_ext.rb +51 -0
- data/spec/shared_client_context.rb +5 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/springboard/client/body_spec.rb +32 -0
- data/spec/springboard/client/resource_spec.rb +250 -0
- data/spec/springboard/client/response_spec.rb +100 -0
- data/spec/springboard/client/uri_ext_spec.rb +51 -0
- data/spec/springboard/client_spec.rb +214 -0
- data/springboard-retail.gemspec +20 -0
- data/vendor/cache/addressable-2.2.8.gem +0 -0
- data/vendor/cache/coderay-1.0.7.gem +0 -0
- data/vendor/cache/coveralls-0.6.9.gem +0 -0
- data/vendor/cache/crack-0.3.1.gem +0 -0
- data/vendor/cache/diff-lcs-1.1.3.gem +0 -0
- data/vendor/cache/hashie-2.0.5.gem +0 -0
- data/vendor/cache/json-1.8.1.gem +0 -0
- data/vendor/cache/method_source-0.8.gem +0 -0
- data/vendor/cache/mime-types-1.25.gem +0 -0
- data/vendor/cache/multi_json-1.8.0.gem +0 -0
- data/vendor/cache/patron-0.4.18.gem +0 -0
- data/vendor/cache/pry-0.9.10.gem +0 -0
- data/vendor/cache/rake-0.9.2.2.gem +0 -0
- data/vendor/cache/rest-client-1.6.7.gem +0 -0
- data/vendor/cache/rspec-2.11.0.gem +0 -0
- data/vendor/cache/rspec-core-2.11.1.gem +0 -0
- data/vendor/cache/rspec-expectations-2.11.2.gem +0 -0
- data/vendor/cache/rspec-mocks-2.11.1.gem +0 -0
- data/vendor/cache/simplecov-0.7.1.gem +0 -0
- data/vendor/cache/simplecov-html-0.7.1.gem +0 -0
- data/vendor/cache/slop-3.3.2.gem +0 -0
- data/vendor/cache/term-ansicolor-1.2.2.gem +0 -0
- data/vendor/cache/thor-0.18.1.gem +0 -0
- data/vendor/cache/tins-0.9.0.gem +0 -0
- data/vendor/cache/webmock-1.8.8.gem +0 -0
- metadata +148 -0
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Springboard::Client::Body do
|
4
|
+
let(:hash) { {"key1" => "val1", "key2" => {"subkey1" => "subval1"}} }
|
5
|
+
let(:body) { Springboard::Client::Body.new(hash)}
|
6
|
+
|
7
|
+
describe "[]" do
|
8
|
+
it "should support string keys" do
|
9
|
+
body["key1"].should == "val1"
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should support symbol keys" do
|
13
|
+
body[:key1].should == "val1"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "nested hashes" do
|
18
|
+
it "should support nested indifferent access" do
|
19
|
+
body[:key2][:subkey1].should == "subval1"
|
20
|
+
body['key2']['subkey1'].should == "subval1"
|
21
|
+
body[:key2]['subkey1'].should == "subval1"
|
22
|
+
body['key2'][:subkey1].should == "subval1"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "to_hash" do
|
27
|
+
it "should return the original hash" do
|
28
|
+
body.to_hash.should === hash
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,250 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Springboard::Client::Resource do
|
4
|
+
include_context "client"
|
5
|
+
|
6
|
+
let(:resource_path) { '/some/path' }
|
7
|
+
let(:resource) { Springboard::Client::Resource.new(client, resource_path) }
|
8
|
+
|
9
|
+
def parse_uri(uri)
|
10
|
+
Addressable::URI.parse(uri)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "[]" do
|
14
|
+
it "should return a new resource" do
|
15
|
+
resource["subpath"].should be_a Springboard::Client::Resource
|
16
|
+
resource["subpath"].object_id.should_not == resource.object_id
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should return a resource with the given subpath appended to its URI" do
|
20
|
+
resource["subpath"].uri.to_s.should == "/some/path/subpath"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should return a resource with the same client instance" do
|
24
|
+
resource["subpath"].client.should === resource.client
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should accept a symbol as a path" do
|
28
|
+
resource[:subpath].uri.to_s.should == "/some/path/subpath"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should accept a symbol as a path" do
|
32
|
+
resource[:subpath].uri.to_s.should == "/some/path/subpath"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should not URI encode the given subpath" do
|
36
|
+
resource["subpath with spaces"].uri.to_s.should == "/some/path/subpath with spaces"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
%w{query params}.each do |method|
|
41
|
+
describe method do
|
42
|
+
describe "when called with a hash" do
|
43
|
+
it "should set the query string parameters" do
|
44
|
+
resource.__send__(method, :a => 1, :b => 2).uri.to_s.should == "/some/path?a=1&b=2"
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should URL encode the given keys and values" do
|
48
|
+
resource.__send__(method, "i have spaces" => "so do i: duh").uri.to_s.
|
49
|
+
should == "/some/path?i%20have%20spaces=so%20do%20i%3A%20duh"
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should add bracket notation for array parameters" do
|
53
|
+
resource.__send__(method, :somearray => [1, 2, 3]).uri.to_s.should == "/some/path?somearray[]=1&somearray[]=2&somearray[]=3"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "when called without arguments" do
|
58
|
+
it "should return the current query string parameters as a hash" do
|
59
|
+
resource.__send__(method).should == {}
|
60
|
+
new_resource = resource.__send__(method, :a => 1, :b => 2)
|
61
|
+
new_resource.__send__(method).should == {"a"=>"1", "b"=>"2"}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "filter" do
|
68
|
+
describe "when given a hash" do
|
69
|
+
it "should add a _filter query string param" do
|
70
|
+
resource.filter(:a => 1, :b => 2).uri.should ==
|
71
|
+
'/some/path?_filter={"a":1,"b":2}'.to_uri
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "when called multiple times" do
|
76
|
+
it "should append args to _filter param as JSON array" do
|
77
|
+
resource.filter(:a => 1).filter(:b => 2).filter(:c => 3).uri.should ==
|
78
|
+
'/some/path?_filter=[{"a":1},{"b":2},{"c":3}]'.to_uri
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "when given a string" do
|
83
|
+
it "should add a _filter query string param" do
|
84
|
+
resource.filter('{"a":1,"b":2}').uri.should ==
|
85
|
+
'/some/path?_filter={"a":1,"b":2}'.to_uri
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "sort" do
|
91
|
+
it "should set the sort parameter based on the given values" do
|
92
|
+
resource.sort('f1', 'f2,desc').uri.query.should == 'sort[]=f1&sort[]=f2%2Cdesc'
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should replace any existing sort parameter" do
|
96
|
+
resource.sort('f1', 'f2,desc')
|
97
|
+
resource.sort('f3,asc', 'f4').uri.query.should == 'sort[]=f3%2Casc&sort[]=f4'
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
%w{count each each_page}.each do |method|
|
102
|
+
describe method do
|
103
|
+
it "should call the client's #{method} method with the resource's URI" do
|
104
|
+
client.should_receive(method).with(resource.uri)
|
105
|
+
resource.__send__(method)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
%w{get head delete}.each do |method|
|
111
|
+
describe method do
|
112
|
+
it "should call the client's #{method} method with the resource's URI and a header hash" do
|
113
|
+
client.should_receive(method).with(resource.uri, false)
|
114
|
+
resource.__send__(method)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
%w{put post}.each do |method|
|
120
|
+
describe method do
|
121
|
+
it "should call the client's #{method} method with the resource's URI, the given body, and a headers hash" do
|
122
|
+
client.should_receive(method).with(resource.uri, "body", false)
|
123
|
+
resource.__send__(method, "body")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "first" do
|
129
|
+
let(:response_data) {
|
130
|
+
{
|
131
|
+
:status => 200,
|
132
|
+
:body => {:results => [{:id => "Me first!"}, {:id => "Me second!"}]}.to_json
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
it "should set the per_page query string param to 1" do
|
137
|
+
request_stub = stub_request(:get, "#{base_url}/some/path?page=1&per_page=1").to_return(response_data)
|
138
|
+
resource.first
|
139
|
+
request_stub.should have_been_requested
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should return the first element of the :results array" do
|
143
|
+
request_stub = stub_request(:get, "#{base_url}/some/path?page=1&per_page=1").to_return(response_data)
|
144
|
+
resource.first.should == {"id" => "Me first!"}
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe "embed" do
|
149
|
+
it "should support a single embed" do
|
150
|
+
resource.embed(:thing1).uri.to_s.should ==
|
151
|
+
'/some/path?_include[]=thing1'
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should support multiple embeds" do
|
155
|
+
resource.embed(:thing1, :thing2, :thing3).uri.to_s.should ==
|
156
|
+
'/some/path?_include[]=thing1&_include[]=thing2&_include[]=thing3'
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should merge multiple embed calls" do
|
160
|
+
resource.embed(:thing1, :thing2).embed(:thing3, :thing4).uri.to_s.should ==
|
161
|
+
'/some/path?_include[]=thing1&_include[]=thing2&_include[]=thing3&_include[]=thing4'
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should merge multiple embed calls" do
|
165
|
+
resource.embed(:thing1, :thing2).embed(:thing3, :thing4).uri.to_s.should ==
|
166
|
+
'/some/path?_include[]=thing1&_include[]=thing2&_include[]=thing3&_include[]=thing4'
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should merge a call to embed with a manually added _include query param" do
|
170
|
+
resource.query('_include[]' => :thing1).embed(:thing2, :thing3).uri.to_s.should ==
|
171
|
+
'/some/path?_include[]=thing1&_include[]=thing2&_include[]=thing3'
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe "while_results" do
|
176
|
+
it "should yield each result to the block as long as the response includes results" do
|
177
|
+
results = ["r1", "r2", "r3"]
|
178
|
+
|
179
|
+
request_stub = stub_request(:get, "#{base_url}/some/path").to_return do |req|
|
180
|
+
{:body => {:results => results}.to_json}
|
181
|
+
end
|
182
|
+
|
183
|
+
yielded_results = []
|
184
|
+
|
185
|
+
# timeout in case of endless loop
|
186
|
+
Timeout::timeout(1) do
|
187
|
+
resource.while_results do |result|
|
188
|
+
yielded_results.push results.shift
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
yielded_results.should == ["r1", "r2", "r3"]
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should raise an exception if it receives an error response" do
|
196
|
+
request_stub = stub_request(:get, "#{base_url}/some/path").to_return do |req|
|
197
|
+
{:status => 400}
|
198
|
+
end
|
199
|
+
|
200
|
+
# timeout in case of endless loop
|
201
|
+
Timeout::timeout(1) do
|
202
|
+
expect do
|
203
|
+
resource.while_results do |result|
|
204
|
+
# nothing
|
205
|
+
end
|
206
|
+
end.to raise_error(Springboard::Client::RequestFailed)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
describe "exists?" do
|
211
|
+
let(:response) { mock(Springboard::Client::Response) }
|
212
|
+
|
213
|
+
it "should return true if the response indicates success" do
|
214
|
+
response.stub!(:success?).and_return(true)
|
215
|
+
client.should_receive(:head).with(resource.uri, false).and_return(response)
|
216
|
+
resource.exists?.should === true
|
217
|
+
end
|
218
|
+
|
219
|
+
it "should return false if the response status is 404" do
|
220
|
+
response.stub!(:status).and_return(404)
|
221
|
+
response.stub!(:success?).and_return(false)
|
222
|
+
client.should_receive(:head).with(resource.uri, false).and_return(response)
|
223
|
+
resource.exists?.should === false
|
224
|
+
end
|
225
|
+
|
226
|
+
it "should raise a RequestFailed exception if the request fails but the status is not 404" do
|
227
|
+
response.stub!(:status).and_return(400)
|
228
|
+
response.stub!(:success?).and_return(false)
|
229
|
+
client.should_receive(:head).with(resource.uri, false).and_return(response)
|
230
|
+
expect { resource.exists? }.to raise_error { |e|
|
231
|
+
e.should be_a Springboard::Client::RequestFailed
|
232
|
+
e.response.should === response
|
233
|
+
e.message.should == "Request during call to 'exists?' resulted in non-404 error."
|
234
|
+
}
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
describe "empty?" do
|
239
|
+
it "should return true if the resource has a count of zero" do
|
240
|
+
resource.stub!(:count).and_return 0
|
241
|
+
resource.empty?.should === true
|
242
|
+
end
|
243
|
+
|
244
|
+
it "should return false if the resource has a count greater than zero" do
|
245
|
+
resource.stub!(:count).and_return 10
|
246
|
+
resource.empty?.should === false
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Springboard::Client::Response do
|
4
|
+
include_context "client"
|
5
|
+
|
6
|
+
let(:raw_body) { '{"key":"value"}' }
|
7
|
+
let(:raw_headers) { 'X-Custom-Header: Hi' }
|
8
|
+
let(:status_code) { 200 }
|
9
|
+
let(:path) { '/path' }
|
10
|
+
let(:patron_response) { Patron::Response.new(path, status_code, 0, raw_headers, raw_body) }
|
11
|
+
let(:response) { Springboard::Client::Response.new(patron_response, client) }
|
12
|
+
|
13
|
+
describe "body" do
|
14
|
+
describe "if raw body is valid JSON" do
|
15
|
+
it "should return a Springboard::Client::Body" do
|
16
|
+
response.body.should be_a Springboard::Client::Body
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should wrap the parsed response body" do
|
20
|
+
response.body.to_hash.should == {"key" => "value"}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "if raw body is not valid JSON" do
|
25
|
+
let(:raw_body) { 'I am not JSON!' }
|
26
|
+
it "should raise an informative error" do
|
27
|
+
expect { response.body }.to raise_error \
|
28
|
+
Springboard::Client::BodyError,
|
29
|
+
"Can't parse response body. (Hint: Try the raw_body method.)"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "if raw body is empty" do
|
34
|
+
let(:raw_body) { '' }
|
35
|
+
it "should raise an informative error" do
|
36
|
+
expect { response.body }.to raise_error \
|
37
|
+
Springboard::Client::BodyError,
|
38
|
+
"Response body is empty. (Hint: If you just created a new resource, try: response.resource.get)"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "raw_body" do
|
44
|
+
it "should return the raw body JSON" do
|
45
|
+
response.raw_body.should == raw_body
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "headers" do
|
50
|
+
it "should return the response headers as a hash" do
|
51
|
+
response.headers.should == {'X-Custom-Header' => 'Hi'}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "resource" do
|
56
|
+
describe "when Location header is returned" do
|
57
|
+
let(:raw_headers) { 'Location: /new/path' }
|
58
|
+
|
59
|
+
it "should be a Springboard::Client::Resource" do
|
60
|
+
response.resource.should be_a Springboard::Client::Resource
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should have the Location header value as its URL" do
|
64
|
+
response.resource.uri.to_s.should == '/new/path'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "when Location header is not returned" do
|
69
|
+
let(:raw_headers) { '' }
|
70
|
+
|
71
|
+
it "should be nil" do
|
72
|
+
response.resource.should be_nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "[]" do
|
78
|
+
it "should forward [] to body" do
|
79
|
+
response.body.should_receive(:[]).with("key").and_return("value")
|
80
|
+
response["key"].should == "value"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "success?" do
|
85
|
+
%w{100 101 102 200 201 202 203 204 205 206 207 208 226 300 301 302 303 304 305 306 307 308}.each do |code|
|
86
|
+
it "should return true if the response status code is #{code}" do
|
87
|
+
response.stub!(:status).and_return(code.to_i)
|
88
|
+
response.success?.should === true
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
%w{400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 420 422 423 424 425 426 428 429 431
|
93
|
+
444 449 450 499 500 501 502 503 504 505 506 507 508 509 510 511 598 599}.each do |code|
|
94
|
+
it "should return false if the response status code is #{code}" do
|
95
|
+
response.stub!(:status).and_return(code.to_i)
|
96
|
+
response.success?.should === false
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Addressable::URI do
|
4
|
+
let(:uri) { Addressable::URI.parse('/relative/path') }
|
5
|
+
|
6
|
+
describe "subpath" do
|
7
|
+
it "should return a new URI with the path relative to the receiver" do
|
8
|
+
uri.subpath('other').should == Addressable::URI.parse('/relative/path/other')
|
9
|
+
uri.subpath('/other').should == Addressable::URI.parse('/relative/path/other')
|
10
|
+
uri.subpath(Addressable::URI.parse('/other')) == Addressable::URI.parse('/relative/path/other')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "merge_query_values!" do
|
15
|
+
it "should call springboard_query_values=" do
|
16
|
+
uri.query_values = {'a' => '1'}
|
17
|
+
uri.should_receive(:springboard_query_values=).with({'a' => '1', 'b' => '2'})
|
18
|
+
uri.merge_query_values! 'b' => '2'
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should merge the given values with the existing query_values" do
|
22
|
+
uri.query_values = {'a' => '1', 'b' => '2'}
|
23
|
+
uri.merge_query_values! 'b' => '20', 'c' => '30'
|
24
|
+
uri.query_values.should == {'a' => '1', 'b' => '20', 'c' => '30'}
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should set the given values if there are no existing query_values" do
|
28
|
+
uri.query_values.should be_nil
|
29
|
+
uri.merge_query_values! 'b' => '20', 'c' => '30'
|
30
|
+
uri.query_values.should == {'b' => '20', 'c' => '30'}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "springboard_query_values=" do
|
35
|
+
it "should preserve empty bracket notation for array params" do
|
36
|
+
uri.query = 'sort[]=f1&sort[]=f2'
|
37
|
+
uri.__send__(:springboard_query_values=, uri.query_values)
|
38
|
+
uri.to_s.should == '/relative/path?sort[]=f1&sort[]=f2'
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should stringify boolean param values" do
|
42
|
+
uri.__send__(:springboard_query_values=, {:p1 => true, :p2 => false})
|
43
|
+
uri.to_s.should == '/relative/path?p1=true&p2=false'
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should support hash param values" do
|
47
|
+
uri.__send__(:springboard_query_values=, {:a => {:b => {:c => 123}}})
|
48
|
+
uri.to_s.should == '/relative/path?a[b][c]=123'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|