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.
Files changed (60) hide show
  1. checksums.yaml +8 -8
  2. data/Gemfile +0 -5
  3. data/README.md +11 -308
  4. data/console.rb +3 -28
  5. data/lib/smooth_operator.rb +7 -75
  6. data/lib/smooth_operator/array_with_meta_data.rb +21 -20
  7. data/lib/smooth_operator/attribute_assignment.rb +53 -57
  8. data/lib/smooth_operator/delegation.rb +34 -15
  9. data/lib/smooth_operator/finder_methods.rb +17 -33
  10. data/lib/smooth_operator/helpers.rb +7 -37
  11. data/lib/smooth_operator/internal_attribute.rb +49 -0
  12. data/lib/smooth_operator/model_schema.rb +72 -0
  13. data/lib/smooth_operator/open_struct.rb +4 -7
  14. data/lib/smooth_operator/operator.rb +64 -102
  15. data/lib/smooth_operator/persistence.rb +64 -94
  16. data/lib/smooth_operator/remote_call.rb +70 -0
  17. data/lib/smooth_operator/serialization.rb +33 -89
  18. data/lib/smooth_operator/translation.rb +13 -26
  19. data/lib/smooth_operator/type_converter.rb +69 -0
  20. data/lib/smooth_operator/validations.rb +3 -25
  21. data/lib/smooth_operator/version.rb +1 -1
  22. data/smooth_operator.gemspec +5 -9
  23. data/spec/factories/user_factory.rb +4 -5
  24. data/spec/smooth_operator/attribute_assignment_spec.rb +11 -145
  25. data/spec/smooth_operator/delegation_spec.rb +54 -57
  26. data/spec/smooth_operator/finder_methods_spec.rb +2 -91
  27. data/spec/smooth_operator/{resource_name_spec.rb → model_schema_spec.rb} +2 -2
  28. data/spec/smooth_operator/operator_spec.rb +1 -1
  29. data/spec/smooth_operator/persistence_spec.rb +20 -140
  30. data/spec/smooth_operator/serialization_spec.rb +4 -28
  31. data/spec/spec_helper.rb +9 -7
  32. data/spec/support/models/address.rb +0 -9
  33. data/spec/support/models/post.rb +3 -9
  34. data/spec/support/models/user.rb +7 -30
  35. data/spec/support/models/user_with_address_and_posts.rb +12 -20
  36. data/spec/support/test_server.rb +7 -63
  37. metadata +18 -55
  38. data/lib/smooth_operator/associations.rb +0 -110
  39. data/lib/smooth_operator/associations/association_reflection.rb +0 -79
  40. data/lib/smooth_operator/associations/has_many_relation.rb +0 -45
  41. data/lib/smooth_operator/associations/reflection.rb +0 -41
  42. data/lib/smooth_operator/cookie_jar.rb +0 -21
  43. data/lib/smooth_operator/http_methods.rb +0 -17
  44. data/lib/smooth_operator/internal_data.rb +0 -45
  45. data/lib/smooth_operator/operators/connection_wrapper.rb +0 -15
  46. data/lib/smooth_operator/operators/faraday.rb +0 -75
  47. data/lib/smooth_operator/operators/typhoeus.rb +0 -87
  48. data/lib/smooth_operator/options.rb +0 -30
  49. data/lib/smooth_operator/remote_call/base.rb +0 -76
  50. data/lib/smooth_operator/remote_call/errors/connection_failed.rb +0 -20
  51. data/lib/smooth_operator/remote_call/errors/timeout.rb +0 -20
  52. data/lib/smooth_operator/remote_call/faraday.rb +0 -19
  53. data/lib/smooth_operator/remote_call/typhoeus.rb +0 -19
  54. data/lib/smooth_operator/resource_name.rb +0 -46
  55. data/lib/smooth_operator/schema.rb +0 -21
  56. data/lib/smooth_operator/type_casting.rb +0 -127
  57. data/spec/require_helper.rb +0 -11
  58. data/spec/smooth_operator/remote_call_spec.rb +0 -340
  59. data/spec/smooth_operator/validations_spec.rb +0 -42
  60. data/spec/support/models/comment.rb +0 -5
@@ -1,12 +1,12 @@
1
1
  require "spec_helper"
2
2
 
3
- describe SmoothOperator::ResourceName do
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::Base.new(attributes_for(: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)
@@ -1,7 +1,7 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe SmoothOperator::Operator do
4
- subject { User::Base }
4
+ subject { User }
5
5
 
6
6
  describe "#get" do
7
7
 
@@ -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 be_a_kind_of(SmoothOperator::RemoteCall::Base)
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
- result = execute_method
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 unprocessed_entity" do
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
- result = execute_method
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
- result = execute_method
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 be_a_kind_of(SmoothOperator::RemoteCall::Base)
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.serializable_hash).to eq(SmoothOperator::Helpers.stringify_keys(attributes_for(:user_with_address_and_posts)))
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.serializable_hash(options_with_only)).to eq(SmoothOperator::Helpers.stringify_keys(attributes_for(:white_list)))
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.serializable_hash(options_with_except)).not_to include(attributes_for(:black_list))
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.serializable_hash(options_with_method)).to eq(SmoothOperator::Helpers.stringify_keys(attributes_for(: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
- require 'simplecov'
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
2
3
 
3
- SimpleCov.start do
4
- root('lib/')
5
- project_name('SmoothOperator')
6
- coverage_dir('../tmp/coverage/')
7
- end
4
+ require 'bundler'
5
+ require 'smooth_operator'
6
+
7
+ Bundler.require :test, :default
8
8
 
9
- require 'require_helper'
9
+ Dir.chdir("spec/") do
10
+ Dir["support/**/*.rb"].each { |file| require file }
11
+ end
10
12
 
11
13
  FactoryGirl.find_definitions
12
14
 
@@ -1,12 +1,3 @@
1
1
  class Address < SmoothOperator::Base
2
2
 
3
- options resource_name: '',
4
- endpoint_user: 'admin',
5
- endpoint_pass: 'admin',
6
- endpoint: 'http://localhost:4567/',
7
- headers: {
8
- "X-APPTOKEN" => "app_token",
9
- "X-LAYERTOKEN" => "layer_token"
10
- }
11
-
12
3
  end
@@ -1,13 +1,7 @@
1
1
  class Post < SmoothOperator::Base
2
2
 
3
- options endpoint_user: 'admin',
4
- endpoint_pass: 'admin',
5
- rails_serialization: true,
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
@@ -1,38 +1,15 @@
1
- module User
1
+ class User < SmoothOperator::Base
2
2
 
3
- class Base < SmoothOperator::Base
3
+ self.endpoint_user = 'admin'
4
4
 
5
- options resource_name: 'user',
6
- endpoint_user: 'admin',
7
- endpoint_pass: 'admin',
8
- endpoint: 'http://localhost:4567/'
5
+ self.endpoint_pass = 'admin'
9
6
 
10
- def self.query_string(params)
11
- params['query_string_param'] = true
7
+ self.endpoint = 'http://localhost:4567/'
12
8
 
13
- params
14
- end
9
+ def self.query_string(params)
10
+ params['query_string_param'] = true
15
11
 
16
- end
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