ddy_remote_resource 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.rspec +2 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +3 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +182 -0
  10. data/Rakefile +7 -0
  11. data/lib/extensions/ethon/easy/queryable.rb +36 -0
  12. data/lib/remote_resource.rb +64 -0
  13. data/lib/remote_resource/base.rb +126 -0
  14. data/lib/remote_resource/builder.rb +53 -0
  15. data/lib/remote_resource/collection.rb +31 -0
  16. data/lib/remote_resource/connection.rb +24 -0
  17. data/lib/remote_resource/connection_options.rb +41 -0
  18. data/lib/remote_resource/http_errors.rb +33 -0
  19. data/lib/remote_resource/querying/finder_methods.rb +34 -0
  20. data/lib/remote_resource/querying/persistence_methods.rb +38 -0
  21. data/lib/remote_resource/request.rb +106 -0
  22. data/lib/remote_resource/response.rb +69 -0
  23. data/lib/remote_resource/response_handeling.rb +48 -0
  24. data/lib/remote_resource/rest.rb +29 -0
  25. data/lib/remote_resource/url_naming.rb +34 -0
  26. data/lib/remote_resource/url_naming_determination.rb +39 -0
  27. data/lib/remote_resource/version.rb +3 -0
  28. data/remote_resource.gemspec +32 -0
  29. data/spec/lib/extensions/ethon/easy/queryable_spec.rb +135 -0
  30. data/spec/lib/remote_resource/base_spec.rb +388 -0
  31. data/spec/lib/remote_resource/builder_spec.rb +245 -0
  32. data/spec/lib/remote_resource/collection_spec.rb +148 -0
  33. data/spec/lib/remote_resource/connection_options_spec.rb +124 -0
  34. data/spec/lib/remote_resource/connection_spec.rb +61 -0
  35. data/spec/lib/remote_resource/querying/finder_methods_spec.rb +105 -0
  36. data/spec/lib/remote_resource/querying/persistence_methods_spec.rb +174 -0
  37. data/spec/lib/remote_resource/request_spec.rb +594 -0
  38. data/spec/lib/remote_resource/response_spec.rb +196 -0
  39. data/spec/lib/remote_resource/rest_spec.rb +98 -0
  40. data/spec/lib/remote_resource/url_naming_determination_spec.rb +225 -0
  41. data/spec/lib/remote_resource/url_naming_spec.rb +72 -0
  42. data/spec/lib/remote_resource/version_spec.rb +8 -0
  43. data/spec/spec_helper.rb +4 -0
  44. metadata +242 -0
@@ -0,0 +1,196 @@
1
+ require 'spec_helper'
2
+
3
+ describe RemoteResource::Response do
4
+
5
+ describe '#original_response' do
6
+ it 'is private' do
7
+ expect(described_class.private_method_defined?(:original_response)).to be_truthy
8
+ end
9
+ end
10
+
11
+ describe '#original_request' do
12
+ it 'is private' do
13
+ expect(described_class.private_method_defined?(:original_request)).to be_truthy
14
+ end
15
+ end
16
+
17
+ describe 'Typhoeus::Response' do
18
+ let(:typhoeus_options) { { body: 'typhoeus_response_body', code: 200 } }
19
+ let(:typhoeus_response) { Typhoeus::Response.new typhoeus_options }
20
+ let(:response) { described_class.new typhoeus_response }
21
+
22
+ describe '#success?' do
23
+ it 'calls the Typhoeus::Response#success?' do
24
+ expect(typhoeus_response).to receive(:success?)
25
+ response.success?
26
+ end
27
+ end
28
+
29
+ describe '#response_body' do
30
+ it 'returns the response body of the original response' do
31
+ expect(response.response_body).to eql 'typhoeus_response_body'
32
+ end
33
+ end
34
+
35
+ describe '#response_code' do
36
+ it 'returns the response code of the original response' do
37
+ expect(response.response_code).to eql 200
38
+ end
39
+ end
40
+ end
41
+
42
+ describe '#unprocessable_entity?' do
43
+ let(:response) { described_class.new double.as_null_object }
44
+
45
+ context 'when the response code is 422' do
46
+ it 'returns true' do
47
+ allow(response).to receive(:response_code) { 422 }
48
+
49
+ expect(response.unprocessable_entity?).to be_truthy
50
+ end
51
+ end
52
+
53
+ context 'when the response code is NOT 422' do
54
+ it 'returns false' do
55
+ allow(response).to receive(:response_code) { 200 }
56
+
57
+ expect(response.unprocessable_entity?).to be_falsey
58
+ end
59
+ end
60
+ end
61
+
62
+ describe '#sanitized_response_body' do
63
+ let(:response) { described_class.new double.as_null_object }
64
+
65
+ before { allow(response).to receive(:response_body) { response_body } }
66
+
67
+ context 'when response_body is nil' do
68
+ let(:response_body) { nil }
69
+
70
+ it 'returns an empty Hash' do
71
+ expect(response.sanitized_response_body).to eql({})
72
+ end
73
+ end
74
+
75
+ context 'when response_body is empty' do
76
+ let(:response_body) { '' }
77
+
78
+ it 'returns an empty Hash' do
79
+ expect(response.sanitized_response_body).to eql({})
80
+ end
81
+ end
82
+
83
+ context 'when response_body is NOT parseable' do
84
+ let(:response_body) { 'foo' }
85
+
86
+ before { allow(JSON).to receive(:parse).and_raise JSON::ParserError }
87
+
88
+ it 'returns an empty Hash' do
89
+ expect(response.sanitized_response_body).to eql({})
90
+ end
91
+ end
92
+
93
+ context 'when response_body is parseable' do
94
+ context 'and the connection_options contain a root_element' do
95
+ let(:connection_options) { { root_element: :foobar } }
96
+ let(:response) { described_class.new double.as_null_object, connection_options }
97
+
98
+ let(:response_body) { '{"foobar":{"id":"12"}}' }
99
+
100
+ it 'returns the parsed response_body unpacked from the root_element' do
101
+ expect(response.sanitized_response_body).to match({ "id" => "12" })
102
+ end
103
+ end
104
+
105
+ context 'and the connection_options do NOT contain a root_element' do
106
+ let(:response_body) { '{"id":"12"}' }
107
+
108
+ it 'returns the parsed response_body' do
109
+ expect(response.sanitized_response_body).to match({ "id" => "12" })
110
+ end
111
+ end
112
+ end
113
+ end
114
+
115
+ describe '#error_messages_response_body' do
116
+ let(:response) { described_class.new double.as_null_object }
117
+
118
+ before { allow(response).to receive(:response_body) { response_body } }
119
+
120
+ context 'when response_body is nil' do
121
+ let(:response_body) { nil }
122
+
123
+ it 'returns an empty Hash' do
124
+ expect(response.error_messages_response_body).to eql({})
125
+ end
126
+ end
127
+
128
+ context 'when response_body is empty' do
129
+ let(:response_body) { '' }
130
+
131
+ it 'returns an empty Hash' do
132
+ expect(response.error_messages_response_body).to eql({})
133
+ end
134
+ end
135
+
136
+ context 'when response_body is NOT parseable' do
137
+ let(:response_body) { 'foo' }
138
+
139
+ before { allow(JSON).to receive(:parse).and_raise JSON::ParserError }
140
+
141
+ it 'returns an empty Hash' do
142
+ expect(response.error_messages_response_body).to eql({})
143
+ end
144
+ end
145
+
146
+ context 'when response_body is parseable' do
147
+ context 'and the connection_options contain a root_element' do
148
+ let(:connection_options) { { root_element: :foobar } }
149
+ let(:response) { described_class.new double.as_null_object, connection_options }
150
+
151
+ context 'and the response_body contains an error key' do
152
+ let(:response_body) { '{"errors":{"foo":["is required"]}}' }
153
+
154
+ it 'returns the error_messages in the parsed response_body' do
155
+ expect(response.error_messages_response_body).to eql({ "foo"=>["is required"] })
156
+ end
157
+ end
158
+
159
+ context 'and the response_body contains an error key packed in the root_element' do
160
+ let(:response_body) { '{"foobar":{"errors":{"foo":["is required"]}}}' }
161
+
162
+ it 'returns the error_messages in the parsed response_body unpacked from the root_element' do
163
+ expect(response.error_messages_response_body).to eql({ "foo"=>["is required"] })
164
+ end
165
+ end
166
+
167
+ context 'and the response_body does NOT contain an error key' do
168
+ let(:response_body) { '{"id":"12"}' }
169
+
170
+ it 'returns an empty Hash' do
171
+ expect(response.error_messages_response_body).to eql({})
172
+ end
173
+ end
174
+ end
175
+
176
+ context 'and the connection_options do NOT contain a root_element' do
177
+ context 'and the response_body contains an error key' do
178
+ let(:response_body) { '{"errors":{"foo":["is required"]}}' }
179
+
180
+ it 'returns the error_messages in the parsed response_body' do
181
+ expect(response.error_messages_response_body).to eql({ "foo"=>["is required"] })
182
+ end
183
+ end
184
+
185
+ context 'and the response_body does NOT contain an error key' do
186
+ let(:response_body) { '{"id":"12"}' }
187
+
188
+ it 'returns an empty Hash' do
189
+ expect(response.error_messages_response_body).to eql({})
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
195
+
196
+ end
@@ -0,0 +1,98 @@
1
+ require 'spec_helper'
2
+
3
+ describe RemoteResource::REST do
4
+
5
+ module RemoteResource
6
+ class RESTDummy
7
+ include RemoteResource::Base
8
+
9
+ self.site = 'https://foobar.com'
10
+
11
+ end
12
+ end
13
+
14
+ let(:dummy_class) { RemoteResource::RESTDummy }
15
+ let(:dummy) { dummy_class.new }
16
+
17
+ let(:attributes) do
18
+ { name: 'Mies' }
19
+ end
20
+ let(:params) do
21
+ { id: '12' }
22
+ end
23
+ let(:connection_options) do
24
+ {
25
+ version: '/v1',
26
+ path_prefix: '/api'
27
+ }
28
+ end
29
+
30
+ let(:response) { instance_double(RemoteResource::Response) }
31
+
32
+ before { allow_any_instance_of(RemoteResource::Request).to receive(:perform) { response } }
33
+
34
+ describe '.get' do
35
+ it 'performs a RemoteResource::Request with the rest_action :get' do
36
+ expect(RemoteResource::Request).to receive(:new).with(dummy_class, :get, params, connection_options).and_call_original
37
+ expect_any_instance_of(RemoteResource::Request).to receive(:perform)
38
+ dummy_class.get params, connection_options
39
+ end
40
+ end
41
+
42
+ describe '.put' do
43
+ it 'performs a RemoteResource::Request with the rest_action :put' do
44
+ expect(RemoteResource::Request).to receive(:new).with(dummy_class, :put, attributes, connection_options).and_call_original
45
+ expect_any_instance_of(RemoteResource::Request).to receive(:perform)
46
+ dummy_class.put attributes, connection_options
47
+ end
48
+ end
49
+
50
+ describe '.patch' do
51
+ it 'performs a RemoteResource::Request with the rest_action :patch' do
52
+ expect(RemoteResource::Request).to receive(:new).with(dummy_class, :patch, attributes, connection_options).and_call_original
53
+ expect_any_instance_of(RemoteResource::Request).to receive(:perform)
54
+ dummy_class.patch attributes, connection_options
55
+ end
56
+ end
57
+
58
+ describe '.post' do
59
+ it 'performs a RemoteResource::Request with the rest_action :post' do
60
+ expect(RemoteResource::Request).to receive(:new).with(dummy_class, :post, attributes, connection_options).and_call_original
61
+ expect_any_instance_of(RemoteResource::Request).to receive(:perform)
62
+ dummy_class.post attributes, connection_options
63
+ end
64
+ end
65
+
66
+ describe '#get' do
67
+ it 'performs a RemoteResource::Request with the rest_action :get' do
68
+ expect(RemoteResource::Request).to receive(:new).with(dummy, :get, params, connection_options).and_call_original
69
+ expect_any_instance_of(RemoteResource::Request).to receive(:perform)
70
+ dummy.get params, connection_options
71
+ end
72
+ end
73
+
74
+ describe '#put' do
75
+ it 'performs a RemoteResource::Request with the rest_action :put' do
76
+ expect(RemoteResource::Request).to receive(:new).with(dummy, :put, attributes, connection_options).and_call_original
77
+ expect_any_instance_of(RemoteResource::Request).to receive(:perform)
78
+ dummy.put attributes, connection_options
79
+ end
80
+ end
81
+
82
+ describe '#patch' do
83
+ it 'performs a RemoteResource::Request with the rest_action :patch' do
84
+ expect(RemoteResource::Request).to receive(:new).with(dummy, :patch, attributes, connection_options).and_call_original
85
+ expect_any_instance_of(RemoteResource::Request).to receive(:perform)
86
+ dummy.patch attributes, connection_options
87
+ end
88
+ end
89
+
90
+ describe '#post' do
91
+ it 'performs a RemoteResource::Request with the rest_action :post' do
92
+ expect(RemoteResource::Request).to receive(:new).with(dummy, :post, attributes, connection_options).and_call_original
93
+ expect_any_instance_of(RemoteResource::Request).to receive(:perform)
94
+ dummy.post attributes, connection_options
95
+ end
96
+ end
97
+
98
+ end
@@ -0,0 +1,225 @@
1
+ require 'spec_helper'
2
+
3
+ describe RemoteResource::UrlNamingDetermination do
4
+
5
+ module RemoteResource
6
+ class UrlNamingDeterminationDummy
7
+ include RemoteResource::Base
8
+
9
+ self.site = 'http://www.foobar.com'
10
+
11
+ end
12
+ end
13
+
14
+ let(:dummy_class) { RemoteResource::UrlNamingDeterminationDummy }
15
+
16
+ let(:connection_options) { {} }
17
+ let(:url_naming_determination) { described_class.new dummy_class, connection_options }
18
+
19
+ describe '#base_url' do
20
+ context 'site' do
21
+ context 'when the connection_options contain a site' do
22
+ let(:connection_options) do
23
+ { site: 'http://www.bazbar.com' }
24
+ end
25
+
26
+ it 'uses the site of the connection_options' do
27
+ expect(url_naming_determination.base_url).to eql 'http://www.bazbar.com/url_naming_determination_dummy'
28
+ end
29
+ end
30
+
31
+ context 'when the connection_options do NOT contain a site' do
32
+ it 'uses the site of the resource_klass' do
33
+ expect(url_naming_determination.base_url).to eql 'http://www.foobar.com/url_naming_determination_dummy'
34
+ end
35
+ end
36
+ end
37
+
38
+ context 'version' do
39
+ context 'when the connection_options contain a version' do
40
+ let(:connection_options) do
41
+ { version: '/v2' }
42
+ end
43
+
44
+ it 'uses the version of the connection_options' do
45
+ expect(url_naming_determination.base_url).to eql 'http://www.foobar.com/v2/url_naming_determination_dummy'
46
+ end
47
+ end
48
+
49
+ context 'when the connection_options do NOT contain a version' do
50
+ context 'and the resource_klass contains a version' do
51
+ it 'uses the version of the resource_klass' do
52
+ dummy_class.version = '/version_4'
53
+
54
+ expect(url_naming_determination.base_url).to eql 'http://www.foobar.com/version_4/url_naming_determination_dummy'
55
+
56
+ dummy_class.version = nil
57
+ end
58
+ end
59
+
60
+ context 'and the resource_klass does NOT contain a version' do
61
+ it 'does NOT use the version' do
62
+ expect(url_naming_determination.base_url).to eql 'http://www.foobar.com/url_naming_determination_dummy'
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ context 'path_prefix' do
69
+ context 'when the connection_options contain a path_prefix' do
70
+ let(:connection_options) do
71
+ { path_prefix: '/api' }
72
+ end
73
+
74
+ it 'uses the path_prefix of the connection_options' do
75
+ expect(url_naming_determination.base_url).to eql 'http://www.foobar.com/api/url_naming_determination_dummy'
76
+ end
77
+ end
78
+
79
+ context 'when the connection_options do NOT contain a path_prefix' do
80
+ context 'and the resource_klass contains a path_prefix' do
81
+ it 'uses the path_prefix of the resource_klass' do
82
+ dummy_class.path_prefix = '/external_endpoint'
83
+
84
+ expect(url_naming_determination.base_url).to eql 'http://www.foobar.com/external_endpoint/url_naming_determination_dummy'
85
+
86
+ dummy_class.path_prefix = nil
87
+ end
88
+ end
89
+
90
+ context 'and the resource_klass does NOT contain a path_prefix' do
91
+ it 'does NOT use the path_prefix' do
92
+ expect(url_naming_determination.base_url).to eql 'http://www.foobar.com/url_naming_determination_dummy'
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ context 'id' do
99
+ context 'when an id is specified' do
100
+ it 'uses that id in the base url' do
101
+ expect(url_naming_determination.base_url(:id)).to eql 'http://www.foobar.com/url_naming_determination_dummy/id'
102
+ end
103
+ end
104
+
105
+ context 'when an id is NOT specified' do
106
+ it 'creates a base url without it' do
107
+ expect(url_naming_determination.base_url).to eql 'http://www.foobar.com/url_naming_determination_dummy'
108
+ end
109
+ end
110
+ end
111
+
112
+ context 'path_postfix' do
113
+ context 'when the connection_options contain a path_postfix' do
114
+ let(:connection_options) do
115
+ { path_postfix: '/custom' }
116
+ end
117
+
118
+ it 'uses the path_postfix of the connection_options' do
119
+ expect(url_naming_determination.base_url).to eql 'http://www.foobar.com/url_naming_determination_dummy/custom'
120
+ end
121
+
122
+ context 'and an id is specified' do
123
+ it 'uses the path_postfix of the connection_options and places the id before it' do
124
+ expect(url_naming_determination.base_url(:id)).to eql 'http://www.foobar.com/url_naming_determination_dummy/id/custom'
125
+ end
126
+ end
127
+ end
128
+
129
+ context 'when the connection_options do NOT contain a path_postfix' do
130
+ context 'and the resource_klass contains a path_postfix' do
131
+ it 'uses the path_postfix of the resource_klass' do
132
+ dummy_class.path_postfix = '/cancel'
133
+
134
+ expect(url_naming_determination.base_url).to eql 'http://www.foobar.com/url_naming_determination_dummy/cancel'
135
+
136
+ dummy_class.path_postfix = nil
137
+ end
138
+
139
+ context 'and an id is specified' do
140
+ it 'uses the path_postfix of the resource_klass and places the id before it' do
141
+ dummy_class.path_postfix = '/cancel'
142
+
143
+ expect(url_naming_determination.base_url(:id)).to eql 'http://www.foobar.com/url_naming_determination_dummy/id/cancel'
144
+
145
+ dummy_class.path_postfix = nil
146
+ end
147
+ end
148
+ end
149
+
150
+ context 'and the resource_klass does NOT contain a path_postfix' do
151
+ it 'does NOT use the path_postfix' do
152
+ expect(url_naming_determination.base_url).to eql 'http://www.foobar.com/url_naming_determination_dummy'
153
+ end
154
+
155
+ context 'and an id is specified' do
156
+ it 'places the id after the url safe relative name' do
157
+ expect(url_naming_determination.base_url(:id)).to eql 'http://www.foobar.com/url_naming_determination_dummy/id'
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
164
+
165
+ describe '#url_safe_relative_name' do
166
+ context 'when the connection_options contain a collection' do
167
+ let(:connection_options) do
168
+ { collection: true }
169
+ end
170
+
171
+ it 'uses the underscored, downcased and pluralized relative_name' do
172
+ expect(url_naming_determination.url_safe_relative_name).to eql 'url_naming_determination_dummies'
173
+ end
174
+ end
175
+
176
+ context 'when the connection_options do NOT contain a collection' do
177
+ context 'and the resource_klass contains a collection' do
178
+ it 'uses the underscored, downcased and pluralized relative_name' do
179
+ dummy_class.collection = true
180
+
181
+ expect(url_naming_determination.url_safe_relative_name).to eql 'url_naming_determination_dummies'
182
+
183
+ dummy_class.collection = false
184
+ end
185
+ end
186
+
187
+ context 'and the resource_klass does NOT contain a collection' do
188
+ it 'uses the underscored and downcased relative_name' do
189
+ expect(url_naming_determination.url_safe_relative_name).to eql 'url_naming_determination_dummy'
190
+ end
191
+ end
192
+ end
193
+ end
194
+
195
+ describe '#relative_name' do
196
+ context 'when the connection_options contain a collection_name' do
197
+ let(:connection_options) do
198
+ { collection_name: 'people' }
199
+ end
200
+
201
+ it 'uses the collection_name of the connection_options' do
202
+ expect(url_naming_determination.relative_name).to eql 'people'
203
+ end
204
+ end
205
+
206
+ context 'when the connection_options do NOT contain a collection_name' do
207
+ context 'and the resource_klass contains a collection_name' do
208
+ it 'uses the collection_name of the resource_klass' do
209
+ dummy_class.collection_name = 'cars'
210
+
211
+ expect(url_naming_determination.relative_name).to eql 'cars'
212
+
213
+ dummy_class.collection_name = nil
214
+ end
215
+ end
216
+
217
+ context 'and the resource_klass does NOT contain a collection_name' do
218
+ it 'uses the demodulized name of the resource_klass' do
219
+ expect(url_naming_determination.relative_name).to eql 'UrlNamingDeterminationDummy'
220
+ end
221
+ end
222
+ end
223
+ end
224
+
225
+ end