smooth_operator 1.3.0 → 1.8.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.
- checksums.yaml +8 -8
- data/Gemfile +0 -5
- data/README.md +11 -308
- data/console.rb +3 -28
- data/lib/smooth_operator.rb +7 -75
- data/lib/smooth_operator/array_with_meta_data.rb +21 -20
- data/lib/smooth_operator/attribute_assignment.rb +53 -57
- data/lib/smooth_operator/delegation.rb +34 -15
- data/lib/smooth_operator/finder_methods.rb +17 -33
- data/lib/smooth_operator/helpers.rb +7 -37
- data/lib/smooth_operator/internal_attribute.rb +49 -0
- data/lib/smooth_operator/model_schema.rb +72 -0
- data/lib/smooth_operator/open_struct.rb +4 -7
- data/lib/smooth_operator/operator.rb +64 -102
- data/lib/smooth_operator/persistence.rb +64 -94
- data/lib/smooth_operator/remote_call.rb +70 -0
- data/lib/smooth_operator/serialization.rb +33 -89
- data/lib/smooth_operator/translation.rb +13 -26
- data/lib/smooth_operator/type_converter.rb +69 -0
- data/lib/smooth_operator/validations.rb +3 -25
- data/lib/smooth_operator/version.rb +1 -1
- data/smooth_operator.gemspec +5 -9
- data/spec/factories/user_factory.rb +4 -5
- data/spec/smooth_operator/attribute_assignment_spec.rb +11 -145
- data/spec/smooth_operator/delegation_spec.rb +54 -57
- data/spec/smooth_operator/finder_methods_spec.rb +2 -91
- data/spec/smooth_operator/{resource_name_spec.rb → model_schema_spec.rb} +2 -2
- data/spec/smooth_operator/operator_spec.rb +1 -1
- data/spec/smooth_operator/persistence_spec.rb +20 -140
- data/spec/smooth_operator/serialization_spec.rb +4 -28
- data/spec/spec_helper.rb +9 -7
- data/spec/support/models/address.rb +0 -9
- data/spec/support/models/post.rb +3 -9
- data/spec/support/models/user.rb +7 -30
- data/spec/support/models/user_with_address_and_posts.rb +12 -20
- data/spec/support/test_server.rb +7 -63
- metadata +18 -55
- data/lib/smooth_operator/associations.rb +0 -110
- data/lib/smooth_operator/associations/association_reflection.rb +0 -79
- data/lib/smooth_operator/associations/has_many_relation.rb +0 -45
- data/lib/smooth_operator/associations/reflection.rb +0 -41
- data/lib/smooth_operator/cookie_jar.rb +0 -21
- data/lib/smooth_operator/http_methods.rb +0 -17
- data/lib/smooth_operator/internal_data.rb +0 -45
- data/lib/smooth_operator/operators/connection_wrapper.rb +0 -15
- data/lib/smooth_operator/operators/faraday.rb +0 -75
- data/lib/smooth_operator/operators/typhoeus.rb +0 -87
- data/lib/smooth_operator/options.rb +0 -30
- data/lib/smooth_operator/remote_call/base.rb +0 -76
- data/lib/smooth_operator/remote_call/errors/connection_failed.rb +0 -20
- data/lib/smooth_operator/remote_call/errors/timeout.rb +0 -20
- data/lib/smooth_operator/remote_call/faraday.rb +0 -19
- data/lib/smooth_operator/remote_call/typhoeus.rb +0 -19
- data/lib/smooth_operator/resource_name.rb +0 -46
- data/lib/smooth_operator/schema.rb +0 -21
- data/lib/smooth_operator/type_casting.rb +0 -127
- data/spec/require_helper.rb +0 -11
- data/spec/smooth_operator/remote_call_spec.rb +0 -340
- data/spec/smooth_operator/validations_spec.rb +0 -42
- data/spec/support/models/comment.rb +0 -5
@@ -1,12 +1,12 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
describe SmoothOperator::
|
3
|
+
describe SmoothOperator::ModelSchema do
|
4
4
|
|
5
5
|
describe "#known_attributes" do
|
6
6
|
let(:initial_attributes_keys) { attributes_for(:user).keys.map(&:to_s) }
|
7
7
|
|
8
8
|
context "when there is no declared schema" do
|
9
|
-
subject { User
|
9
|
+
subject { User.new(attributes_for(:user)) }
|
10
10
|
|
11
11
|
it 'it should reflect the attributes used uppon initialization' do
|
12
12
|
expect(subject.known_attributes.to_a).to match_array(initial_attributes_keys)
|
@@ -9,7 +9,7 @@ shared_examples_for "successful persistent remote call" do
|
|
9
9
|
it "it should populate 'last_remote_call' with the remote_call used on this transaction" do
|
10
10
|
expect(subject.last_remote_call).to be_nil unless method_to_execute.to_s =~ /create/
|
11
11
|
execute_method
|
12
|
-
expect(subject.last_remote_call).to
|
12
|
+
expect(subject.last_remote_call).to be_instance_of(SmoothOperator::RemoteCall::Base)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
@@ -23,13 +23,7 @@ shared_examples_for "persistent remote call" do
|
|
23
23
|
let(:method_arguments) { ['', { status: 200 }] }
|
24
24
|
|
25
25
|
it "it should return true" do
|
26
|
-
|
27
|
-
|
28
|
-
if !(method_to_execute.to_s =~ /create/)
|
29
|
-
expect(result).to be true
|
30
|
-
end
|
31
|
-
|
32
|
-
expect(subject.last_remote_call.ok?).to be true
|
26
|
+
execute_method
|
33
27
|
expect(subject.last_remote_call.status).to be true
|
34
28
|
end
|
35
29
|
|
@@ -41,17 +35,11 @@ shared_examples_for "persistent remote call" do
|
|
41
35
|
it_behaves_like "successful persistent remote call"
|
42
36
|
end
|
43
37
|
|
44
|
-
context "when the response is
|
38
|
+
context "when the response is negative" do
|
45
39
|
let(:method_arguments) { ['', { status: 422 }] }
|
46
40
|
|
47
41
|
it "it should return false" do
|
48
|
-
|
49
|
-
|
50
|
-
if !(method_to_execute.to_s =~ /create/)
|
51
|
-
expect(result).to be false
|
52
|
-
end
|
53
|
-
|
54
|
-
expect(subject.last_remote_call.not_processed?).to be true
|
42
|
+
execute_method
|
55
43
|
expect(subject.last_remote_call.status).to be false
|
56
44
|
end
|
57
45
|
|
@@ -63,39 +51,11 @@ shared_examples_for "persistent remote call" do
|
|
63
51
|
it_behaves_like "successful persistent remote call"
|
64
52
|
end
|
65
53
|
|
66
|
-
context "when the response is client side error" do
|
67
|
-
let(:method_arguments) { ['', { status: 404 }] }
|
68
|
-
|
69
|
-
it "it should return nil" do
|
70
|
-
result = execute_method
|
71
|
-
|
72
|
-
if !(method_to_execute.to_s =~ /create/)
|
73
|
-
expect(result).to be nil
|
74
|
-
end
|
75
|
-
|
76
|
-
expect(subject.last_remote_call.client_error?).to be true
|
77
|
-
expect(subject.last_remote_call.error?).to be true
|
78
|
-
expect(subject.last_remote_call.status).to be nil
|
79
|
-
end
|
80
|
-
|
81
|
-
it "it should assert the subject's persistence" do
|
82
|
-
execute_method
|
83
|
-
expect(subject.persisted?).to be(persistence_state[500])
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
54
|
context "when the there is a connection error ou http 500" do
|
88
55
|
let(:method_arguments) { ['', { status: 500 }] }
|
89
56
|
|
90
57
|
it "it should return nil" do
|
91
|
-
|
92
|
-
|
93
|
-
if !(method_to_execute.to_s =~ /create/)
|
94
|
-
expect(result).to be nil
|
95
|
-
end
|
96
|
-
|
97
|
-
expect(subject.last_remote_call.server_error?).to be true
|
98
|
-
expect(subject.last_remote_call.error?).to be true
|
58
|
+
execute_method
|
99
59
|
expect(subject.last_remote_call.status).to be_nil
|
100
60
|
end
|
101
61
|
|
@@ -107,7 +67,7 @@ shared_examples_for "persistent remote call" do
|
|
107
67
|
it "it should populate 'last_remote_call' with the remote_call used on this transaction" do
|
108
68
|
expect(subject.last_remote_call).to be_nil unless method_to_execute.to_s =~ /create/
|
109
69
|
execute_method
|
110
|
-
expect(subject.last_remote_call).to
|
70
|
+
expect(subject.last_remote_call).to be_instance_of(SmoothOperator::RemoteCall::Base)
|
111
71
|
end
|
112
72
|
|
113
73
|
it "it should assert the subject's persistence" do
|
@@ -124,89 +84,15 @@ shared_examples_for "save method" do
|
|
124
84
|
end
|
125
85
|
end
|
126
86
|
|
127
|
-
shared_examples_for "a method that calls the #make_the_call method" do
|
128
|
-
let(:method_arguments) { ['/custom_path', { "user" => { "first_name" => "nhoJ" }, "extra_params" => 'extra_params' }, { option1: 'option1', option2: 'option2', http_verb: :get, serializable_options: { only: [:first_name] } }] }
|
129
|
-
|
130
|
-
it "it should pass all arguments to #make_the_call" do
|
131
|
-
_method_arguments = method_arguments.dup
|
132
|
-
_method_arguments[0] = SmoothOperator::Helpers.remove_initial_slash(_method_arguments[0])
|
133
|
-
|
134
|
-
expect(subject.class).to receive(:make_the_call).with(:get, *_method_arguments)
|
135
|
-
|
136
|
-
execute_method
|
137
|
-
end
|
138
|
-
|
139
|
-
it "it should pass all arguments to .make_the_call" do
|
140
|
-
_method_arguments = method_arguments.dup
|
141
|
-
_method_arguments[0] = SmoothOperator::Helpers.remove_initial_slash(_method_arguments[0])
|
142
|
-
|
143
|
-
expect(subject.class).to receive(:make_the_call).with(:get, *_method_arguments)
|
144
|
-
|
145
|
-
execute_method
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
87
|
|
150
88
|
describe SmoothOperator::Persistence, helpers: :persistence do
|
151
89
|
|
152
|
-
describe "#reload" do
|
153
|
-
subject { new_user }
|
154
|
-
let(:method_to_execute) { :reload }
|
155
|
-
|
156
|
-
context "when subject doesn't has an id" do
|
157
|
-
it "it should raise 'UnknownPath'" do
|
158
|
-
expect{ subject.reload }.to raise_error 'UnknownPath'
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
context "when subject has an id" do
|
163
|
-
before do
|
164
|
-
subject.id = 1
|
165
|
-
subject.reload
|
166
|
-
end
|
167
|
-
|
168
|
-
it "it should fetch server data" do
|
169
|
-
expect(subject.attributes).to eq(attributes_for(:user_with_address_and_posts))
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
context "when calling #reload on a nested object" do
|
174
|
-
|
175
|
-
context "without the option 'ignore_parent: true'" do
|
176
|
-
before do
|
177
|
-
subject.id = 1
|
178
|
-
subject.reload
|
179
|
-
subject.posts.first.reload
|
180
|
-
end
|
181
|
-
|
182
|
-
it "it should fetch server data, with NESTED REST url" do
|
183
|
-
expect(subject.posts.first.attributes).to eq({ id: 1, body: 'from_nested_url' })
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
context "with the option 'ignore_parent: true'" do
|
188
|
-
before do
|
189
|
-
subject.id = 1
|
190
|
-
subject.reload
|
191
|
-
subject.posts.first.reload(nil, nil, { ignore_parent: true })
|
192
|
-
end
|
193
|
-
|
194
|
-
it "it should fetch server data, with REST url" do
|
195
|
-
expect(subject.posts.first.attributes).to eq({ id: 1, body: 'from_resource_url' })
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
end
|
200
|
-
|
201
|
-
it_behaves_like "a method that calls the #make_the_call method"
|
202
|
-
end
|
203
|
-
|
204
90
|
describe ".create" do
|
205
|
-
|
206
|
-
subject { created_subject }
|
91
|
+
|
207
92
|
let(:method_arguments) { [] }
|
208
93
|
|
209
94
|
context "when attributes DON'T contain an ID" do
|
95
|
+
subject { created_subject }
|
210
96
|
let(:method_to_execute) { :create_without_id }
|
211
97
|
let(:persistence_state) { { 200 => true, 422 => false, 500 => false } }
|
212
98
|
|
@@ -221,6 +107,7 @@ describe SmoothOperator::Persistence, helpers: :persistence do
|
|
221
107
|
end
|
222
108
|
|
223
109
|
context "when attributes contain an ID" do
|
110
|
+
subject { created_subject }
|
224
111
|
let(:method_to_execute) { :create_with_id }
|
225
112
|
let(:persistence_state) { { 200 => true, 422 => true, 500 => true } }
|
226
113
|
|
@@ -271,7 +158,7 @@ describe SmoothOperator::Persistence, helpers: :persistence do
|
|
271
158
|
expect(subject.destroyed?).to be(true)
|
272
159
|
end
|
273
160
|
end
|
274
|
-
|
161
|
+
|
275
162
|
context "after a failed execution of #destroy" do
|
276
163
|
subject { existing_user }
|
277
164
|
before { subject.destroy('', { status: 422 }) }
|
@@ -331,16 +218,14 @@ describe SmoothOperator::Persistence, helpers: :persistence do
|
|
331
218
|
subject { new_user }
|
332
219
|
let(:persistence_state) { { 200 => true, 422 => false, 500 => false } }
|
333
220
|
|
221
|
+
it_behaves_like "persistent remote call"
|
222
|
+
|
334
223
|
it "it should make a post http call" do
|
335
224
|
execute_method
|
336
225
|
expect(subject.last_remote_call.parsed_response['http_verb']).to eq('post')
|
337
226
|
end
|
338
227
|
|
339
228
|
it_behaves_like "save method"
|
340
|
-
|
341
|
-
it_behaves_like "persistent remote call"
|
342
|
-
|
343
|
-
it_behaves_like "a method that calls the #make_the_call method"
|
344
229
|
end
|
345
230
|
|
346
231
|
context "when an instance IS persisted" do
|
@@ -348,34 +233,31 @@ describe SmoothOperator::Persistence, helpers: :persistence do
|
|
348
233
|
subject { existing_user }
|
349
234
|
let(:persistence_state) { { 200 => true, 422 => true, 500 => true } }
|
350
235
|
|
236
|
+
it_behaves_like "persistent remote call"
|
237
|
+
|
351
238
|
it "it should make a put http call" do
|
352
239
|
execute_method
|
353
240
|
expect(subject.last_remote_call.parsed_response['http_verb']).to eq('put')
|
354
241
|
end
|
355
242
|
|
356
243
|
it_behaves_like "save method"
|
357
|
-
|
358
|
-
it_behaves_like "persistent remote call"
|
359
|
-
|
360
|
-
it_behaves_like "a method that calls the #make_the_call method"
|
361
244
|
end
|
362
245
|
|
363
246
|
context "and it uses 'patch' http verb to save" do
|
364
247
|
subject { existing_user_with_patch }
|
365
248
|
let(:persistence_state) { { 200 => true, 422 => true, 500 => true } }
|
366
249
|
|
250
|
+
it_behaves_like "persistent remote call"
|
251
|
+
|
367
252
|
it "it should make a patch http call" do
|
368
253
|
execute_method
|
369
254
|
expect(subject.last_remote_call.parsed_response['http_verb']).to eq('patch')
|
370
255
|
end
|
371
256
|
|
372
257
|
it_behaves_like "save method"
|
373
|
-
|
374
|
-
it_behaves_like "persistent remote call"
|
375
|
-
|
376
|
-
it_behaves_like "a method that calls the #make_the_call method"
|
377
258
|
end
|
378
259
|
end
|
260
|
+
|
379
261
|
end
|
380
262
|
|
381
263
|
describe "#save!" do
|
@@ -395,7 +277,7 @@ describe SmoothOperator::Persistence, helpers: :persistence do
|
|
395
277
|
end
|
396
278
|
|
397
279
|
describe "#destroy" do
|
398
|
-
|
280
|
+
|
399
281
|
let(:method_to_execute) { :destroy }
|
400
282
|
let(:method_arguments) { [] }
|
401
283
|
|
@@ -417,14 +299,12 @@ describe SmoothOperator::Persistence, helpers: :persistence do
|
|
417
299
|
subject { existing_user }
|
418
300
|
let(:persistence_state) { { 200 => false, 422 => true, 500 => true } }
|
419
301
|
|
302
|
+
it_behaves_like "persistent remote call"
|
303
|
+
|
420
304
|
it "it should make a delete http call" do
|
421
305
|
execute_method
|
422
306
|
expect(subject.last_remote_call.parsed_response['http_verb']).to eq('delete')
|
423
307
|
end
|
424
|
-
|
425
|
-
it_behaves_like "persistent remote call"
|
426
|
-
|
427
|
-
it_behaves_like "a method that calls the #make_the_call method"
|
428
308
|
end
|
429
309
|
|
430
310
|
end
|
@@ -20,33 +20,9 @@ describe SmoothOperator::Serialization do
|
|
20
20
|
describe "#to_hash" do
|
21
21
|
subject { UserWithAddressAndPosts::Son.new(attributes_for(:user_with_address_and_posts)) }
|
22
22
|
|
23
|
-
it 'it should call #serializable_hash with the same arguments' do
|
24
|
-
options = { option1: 'option1', option2: 'option2' }
|
25
|
-
|
26
|
-
expect(subject).to receive(:serializable_hash).with(options)
|
27
|
-
|
28
|
-
subject.to_hash(options)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
describe "#to_json" do
|
33
|
-
subject { UserWithAddressAndPosts::Son.new(attributes_for(:user_with_address_and_posts)) }
|
34
|
-
|
35
|
-
it 'it should call #serializable_hash with the same arguments' do
|
36
|
-
options = { option1: 'option1', option2: 'option2' }
|
37
|
-
|
38
|
-
expect(subject).to receive(:serializable_hash).with(options)
|
39
|
-
|
40
|
-
subject.to_json(options)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
describe "#serializable_hash" do
|
45
|
-
subject { UserWithAddressAndPosts::Son.new(attributes_for(:user_with_address_and_posts)) }
|
46
|
-
|
47
23
|
context "when no options are given" do
|
48
24
|
it 'it should return all attributes' do
|
49
|
-
expect(subject.
|
25
|
+
expect(subject.to_hash).to eq(attributes_for(:user_with_address_and_posts))
|
50
26
|
end
|
51
27
|
end
|
52
28
|
|
@@ -54,7 +30,7 @@ describe SmoothOperator::Serialization do
|
|
54
30
|
let(:options_with_only) { { only: [:id, :first_name] } }
|
55
31
|
|
56
32
|
it 'it should only return the filtered options' do
|
57
|
-
expect(subject.
|
33
|
+
expect(subject.to_hash(options_with_only)).to eq(attributes_for(:white_list))
|
58
34
|
end
|
59
35
|
end
|
60
36
|
|
@@ -62,7 +38,7 @@ describe SmoothOperator::Serialization do
|
|
62
38
|
let(:options_with_except) { { except: [:last_name, :admin] } }
|
63
39
|
|
64
40
|
it 'it should return all fields except for the filtered options' do
|
65
|
-
expect(subject.
|
41
|
+
expect(subject.to_hash(options_with_except)).not_to include(attributes_for(:black_list))
|
66
42
|
end
|
67
43
|
end
|
68
44
|
|
@@ -71,7 +47,7 @@ describe SmoothOperator::Serialization do
|
|
71
47
|
subject(:user_with_my_method) { UserWithAddressAndPosts::UserWithMyMethod.new(attributes_for(:user_with_address_and_posts)) }
|
72
48
|
|
73
49
|
it 'it should return all fields including the expected method and its returning value' do
|
74
|
-
expect(user_with_my_method.
|
50
|
+
expect(user_with_my_method.to_hash(options_with_method)).to eq(attributes_for(:user_with_my_method))
|
75
51
|
end
|
76
52
|
end
|
77
53
|
|
data/spec/spec_helper.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
-
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
end
|
4
|
+
require 'bundler'
|
5
|
+
require 'smooth_operator'
|
6
|
+
|
7
|
+
Bundler.require :test, :default
|
8
8
|
|
9
|
-
|
9
|
+
Dir.chdir("spec/") do
|
10
|
+
Dir["support/**/*.rb"].each { |file| require file }
|
11
|
+
end
|
10
12
|
|
11
13
|
FactoryGirl.find_definitions
|
12
14
|
|
data/spec/support/models/post.rb
CHANGED
@@ -1,13 +1,7 @@
|
|
1
1
|
class Post < SmoothOperator::Base
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
endpoint: 'http://localhost:4567/',
|
7
|
-
unknown_hash_class: SmoothOperator::OpenStruct
|
8
|
-
|
9
|
-
has_many :comments#, rails_serialization: true
|
10
|
-
|
11
|
-
belongs_to :address#, rails_serialization: true
|
3
|
+
self.turn_unknown_hash_to_open_struct = false
|
4
|
+
|
5
|
+
self.endpoint = 'http://localhost:3000/api/v0'
|
12
6
|
|
13
7
|
end
|
data/spec/support/models/user.rb
CHANGED
@@ -1,38 +1,15 @@
|
|
1
|
-
|
1
|
+
class User < SmoothOperator::Base
|
2
2
|
|
3
|
-
|
3
|
+
self.endpoint_user = 'admin'
|
4
4
|
|
5
|
-
|
6
|
-
endpoint_user: 'admin',
|
7
|
-
endpoint_pass: 'admin',
|
8
|
-
endpoint: 'http://localhost:4567/'
|
5
|
+
self.endpoint_pass = 'admin'
|
9
6
|
|
10
|
-
|
11
|
-
params['query_string_param'] = true
|
7
|
+
self.endpoint = 'http://localhost:4567/'
|
12
8
|
|
13
|
-
|
14
|
-
|
9
|
+
def self.query_string(params)
|
10
|
+
params['query_string_param'] = true
|
15
11
|
|
16
|
-
|
17
|
-
|
18
|
-
module UnknownHashClass
|
19
|
-
|
20
|
-
class OpenStructBase < User::Base
|
21
|
-
options unknown_hash_class: SmoothOperator::OpenStruct
|
22
|
-
end
|
23
|
-
|
24
|
-
class None < User::Base
|
25
|
-
options unknown_hash_class: nil
|
26
|
-
end
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
|
-
class BrokenConnection < SmoothOperator::Base
|
31
|
-
options endpoint: 'http://localhost:1234/'
|
32
|
-
end
|
33
|
-
|
34
|
-
class TimeoutConnection < Base
|
35
|
-
options timeout: 1
|
12
|
+
params
|
36
13
|
end
|
37
14
|
|
38
15
|
end
|