ddy_remote_resource 0.4.2

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.
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