smooth_operator 0.4.4 → 1.2.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 (68) hide show
  1. checksums.yaml +9 -9
  2. data/.gitignore +2 -1
  3. data/.rspec +4 -0
  4. data/Gemfile +13 -0
  5. data/README.md +258 -10
  6. data/console.rb +44 -0
  7. data/lib/smooth_operator/array_with_meta_data.rb +31 -0
  8. data/lib/smooth_operator/attribute_assignment.rb +102 -0
  9. data/lib/smooth_operator/attribute_methods.rb +87 -0
  10. data/lib/smooth_operator/attributes/base.rb +107 -0
  11. data/lib/smooth_operator/attributes/dirty.rb +29 -0
  12. data/lib/smooth_operator/attributes/normal.rb +15 -0
  13. data/lib/smooth_operator/delegation.rb +60 -0
  14. data/lib/smooth_operator/finder_methods.rb +43 -0
  15. data/lib/smooth_operator/helpers.rb +79 -0
  16. data/lib/smooth_operator/model_schema.rb +81 -0
  17. data/lib/smooth_operator/open_struct.rb +37 -0
  18. data/lib/smooth_operator/operator.rb +145 -0
  19. data/lib/smooth_operator/operators/faraday.rb +75 -0
  20. data/lib/smooth_operator/operators/typhoeus.rb +77 -0
  21. data/lib/smooth_operator/persistence.rb +144 -0
  22. data/lib/smooth_operator/relation/array_relation.rb +13 -0
  23. data/lib/smooth_operator/relation/association_reflection.rb +75 -0
  24. data/lib/smooth_operator/relation/associations.rb +75 -0
  25. data/lib/smooth_operator/relation/reflection.rb +41 -0
  26. data/lib/smooth_operator/relation/single_relation.rb +14 -0
  27. data/lib/smooth_operator/remote_call/base.rb +80 -0
  28. data/lib/smooth_operator/remote_call/errors/connection_failed.rb +20 -0
  29. data/lib/smooth_operator/remote_call/errors/timeout.rb +20 -0
  30. data/lib/smooth_operator/remote_call/faraday.rb +19 -0
  31. data/lib/smooth_operator/remote_call/typhoeus.rb +19 -0
  32. data/lib/smooth_operator/serialization.rb +79 -0
  33. data/lib/smooth_operator/translation.rb +27 -0
  34. data/lib/smooth_operator/validations.rb +15 -0
  35. data/lib/smooth_operator/version.rb +1 -1
  36. data/lib/smooth_operator.rb +26 -5
  37. data/smooth_operator.gemspec +12 -3
  38. data/spec/factories/user_factory.rb +34 -0
  39. data/spec/require_helper.rb +11 -0
  40. data/spec/smooth_operator/attribute_assignment_spec.rb +351 -0
  41. data/spec/smooth_operator/attributes_dirty_spec.rb +53 -0
  42. data/spec/smooth_operator/delegation_spec.rb +139 -0
  43. data/spec/smooth_operator/finder_methods_spec.rb +105 -0
  44. data/spec/smooth_operator/model_schema_spec.rb +31 -0
  45. data/spec/smooth_operator/operator_spec.rb +46 -0
  46. data/spec/smooth_operator/persistence_spec.rb +424 -0
  47. data/spec/smooth_operator/remote_call_spec.rb +320 -0
  48. data/spec/smooth_operator/serialization_spec.rb +80 -0
  49. data/spec/smooth_operator/validations_spec.rb +42 -0
  50. data/spec/spec_helper.rb +25 -0
  51. data/spec/support/helpers/persistence_helper.rb +38 -0
  52. data/spec/support/localhost_server.rb +97 -0
  53. data/spec/support/models/address.rb +14 -0
  54. data/spec/support/models/comment.rb +3 -0
  55. data/spec/support/models/post.rb +13 -0
  56. data/spec/support/models/user.rb +41 -0
  57. data/spec/support/models/user_with_address_and_posts.rb +89 -0
  58. data/spec/support/test_server.rb +165 -0
  59. metadata +108 -18
  60. data/lib/smooth_operator/base.rb +0 -30
  61. data/lib/smooth_operator/core.rb +0 -218
  62. data/lib/smooth_operator/http_handlers/typhoeus/base.rb +0 -58
  63. data/lib/smooth_operator/http_handlers/typhoeus/orm.rb +0 -34
  64. data/lib/smooth_operator/http_handlers/typhoeus/remote_call.rb +0 -28
  65. data/lib/smooth_operator/operator/base.rb +0 -43
  66. data/lib/smooth_operator/operator/exceptions.rb +0 -64
  67. data/lib/smooth_operator/operator/orm.rb +0 -118
  68. data/lib/smooth_operator/operator/remote_call.rb +0 -84
@@ -0,0 +1,139 @@
1
+ require "spec_helper"
2
+
3
+ describe SmoothOperator::Delegation do
4
+
5
+ describe "#respond_to?" do
6
+ let(:initial_attributes_keys) { attributes_for(:user_with_address_and_posts).keys }
7
+
8
+ context "when there is no declared schema" do
9
+ subject { UserWithAddressAndPosts::UserWithMyMethod.new(attributes_for(:user_with_address_and_posts)) }
10
+
11
+ it 'it should return true for every attribute used uppon initialization' do
12
+ initial_attributes_keys.each do |attribute|
13
+ expect(subject.respond_to?(attribute)).to eq(true)
14
+ end
15
+ end
16
+
17
+ it 'it should return false in for unknown attributes/methods' do
18
+ expect(subject.respond_to?(:unknown)).to eq(false)
19
+ end
20
+
21
+ it 'it should return true for any existing method' do
22
+ expect(subject.respond_to?(:my_method)).to eq(true)
23
+ end
24
+ end
25
+
26
+ context "when there is a known schema" do
27
+ subject { UserWithAddressAndPosts::Son.new(attributes_for(:user_with_address_and_posts)) }
28
+ let(:known_schema_attributes) { ["posts", "address", "manager"] }
29
+
30
+ it 'it should return true for every attribute used uppon initialization' do
31
+ initial_attributes_keys.each do |attribute|
32
+ expect(subject.respond_to?(attribute)).to eq(true)
33
+ end
34
+ end
35
+
36
+ it 'it should return true for known schema attributes' do
37
+ known_schema_attributes.each do |attribute|
38
+ expect(subject.respond_to?(attribute)).to eq(true)
39
+ end
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+ describe "#method_missing" do
46
+
47
+ context "when calling a method that matches the initialized attributes" do
48
+ subject { User::Base.new(attributes_for(:user)) }
49
+
50
+ it 'it should return the value of that same attribute' do
51
+ attributes_for(:user).each do |key, value|
52
+ expect(subject.send(key)).to eq(value)
53
+ end
54
+ end
55
+ end
56
+
57
+ context "when .strict_behaviour is true" do
58
+ subject { UserWithAddressAndPosts::Son.new(attributes_for(:user_with_address_and_posts)) }
59
+
60
+ context "when calling a method that doesn't match the initialized attributes but matches the schema" do
61
+ it 'it should return nil' do
62
+ expect(subject.manager).to eq(nil)
63
+ end
64
+
65
+ it "#respond_to? must return true" do
66
+ expect(subject.respond_to?(:manager)).to eq(true)
67
+ end
68
+ end
69
+
70
+ context "when calling a method that doesn't match either the schema nor the initialized attributes" do
71
+ it 'it should raise NoMethodError' do
72
+ expect { subject.unknown_method }.to raise_error NoMethodError
73
+ end
74
+
75
+ it "#respond_to? must return false" do
76
+ expect(subject.respond_to?(:unknown_method)).to eq(false)
77
+ end
78
+ end
79
+
80
+ context "when setting a new attribute not declared on schema" do
81
+ before { subject.unknown_attribute = 'unknown_value' }
82
+
83
+ it "#known_attributes must reflect that new attribute" do
84
+ expect(subject.known_attributes.to_a).to include('unknown_attribute')
85
+ end
86
+
87
+ it "#respond_to? must return true" do
88
+ expect(subject.respond_to?(:unknown_attribute)).to eq(true)
89
+ end
90
+
91
+ it "calling a method with the same name must return that attribute's value" do
92
+ expect(subject.unknown_attribute).to eq('unknown_value')
93
+ end
94
+ end
95
+ end
96
+
97
+ context "when .strict_behaviour is false" do
98
+ subject { UserWithAddressAndPosts::SoftBehaviour.new(attributes_for(:user_with_address_and_posts)) }
99
+
100
+ context "when calling a method that doesn't match the initialized attributes but matches the schema" do
101
+ it 'it should return nil' do
102
+ expect(subject.manager).to eq(nil)
103
+ end
104
+
105
+ it "#respond_to? must return true" do
106
+ expect(subject.respond_to?(:manager)).to eq(true)
107
+ end
108
+ end
109
+
110
+ context "when calling a method that doesn't match either the schema nor the initialized attributes" do
111
+ it 'it should return nil' do
112
+ expect(subject.unknown_method).to eq(nil)
113
+ end
114
+
115
+ it "#respond_to? must return false" do
116
+ expect(subject.respond_to?(:unknown_method)).to eq(false)
117
+ end
118
+ end
119
+
120
+ context "when setting a new attribute not declared on schema" do
121
+ before { subject.unknown_attribute = 'unknown_value' }
122
+
123
+ it "#known_attributes must reflect that new attribute" do
124
+ expect(subject.known_attributes.to_a).to include('unknown_attribute')
125
+ end
126
+
127
+ it "#respond_to? must return true" do
128
+ expect(subject.respond_to?(:unknown_attribute)).to eq(true)
129
+ end
130
+
131
+ it "calling a method with the same name must return that attribute's value" do
132
+ expect(subject.unknown_attribute).to eq('unknown_value')
133
+ end
134
+ end
135
+ end
136
+
137
+ end
138
+
139
+ end
@@ -0,0 +1,105 @@
1
+ require "spec_helper"
2
+
3
+ shared_examples_for "finder method" do
4
+ it "it should return a RemoteCall instance with a subject's class instance" do
5
+ expect(user).to be_instance_of(subject)
6
+ end
7
+
8
+ it "the instance class should be populated with the returned hash" do
9
+ expect(user.attributes).to eq(attributes_for(:user_with_address_and_posts))
10
+ end
11
+
12
+ it "#has_data_from_server and #from_server should return true" do
13
+ expect(user.has_data_from_server).to be true
14
+ expect(user.from_server).to be true
15
+ end
16
+ end
17
+
18
+ describe SmoothOperator::FinderMethods do
19
+ subject { UserWithAddressAndPosts::Son }
20
+
21
+ # describe ".all" do
22
+ # context "when NO arguments are passed" do
23
+ # it "it should can .find(:all, {}, {})" do
24
+ # expect(subject).to receive(:find).with(:all, {}, {})
25
+ # subject.all
26
+ # end
27
+ # end
28
+
29
+ # context "when arguments are passed" do
30
+ # it "it should can .find(:all) with the same arguments that .alll has received" do
31
+ # arguments = [{ id: 2 }, { http_verb: 'head' }]
32
+
33
+ # expect(subject).to receive(:find).with(:all, *arguments)
34
+
35
+ # subject.all(*arguments)
36
+ # end
37
+ # end
38
+ # end
39
+
40
+ describe ".find" do
41
+ context "when the server returns a single hash" do
42
+ let(:user) { subject.find(5).object }
43
+
44
+ it_behaves_like "finder method"
45
+ end
46
+
47
+ context "when the server returns a hash with meta_data" do
48
+ let(:user) { subject.find("5/with_metadata").object }
49
+
50
+ it_behaves_like "finder method"
51
+
52
+ it "#meta_data should reflect the receiving meta_data" do
53
+ expect(user._meta_data).to eq({ "status" => 1 })
54
+ end
55
+
56
+ it "user should NOT contain meta_data" do
57
+ expect { user.status }.to raise_error NoMethodError
58
+ end
59
+ end
60
+
61
+ context "when the server returns an array" do
62
+ it "it should return a RemoteCall instance an array that contains a subject's class instance, one for every array's entry" do
63
+ remote_call = subject.find(:all)
64
+ users = remote_call.objects
65
+
66
+ expect(users).to be_instance_of(Array)
67
+ expect(users[0]).to be_instance_of(subject)
68
+ expect(users[1]).to be_instance_of(subject)
69
+ end
70
+
71
+ it "if any of the array entries is not a hash, it shall not be converted or alteread" do
72
+ remote_call = subject.find('misc_array')
73
+ users = remote_call.objects
74
+
75
+ expect(users).to be_instance_of(Array)
76
+ expect(users[0]).to be_instance_of(subject)
77
+ expect(users[1]).to be(2)
78
+ end
79
+ end
80
+
81
+ context "when the server returns a hash with a key (equal to subject's call.resources_name) containing an array" do
82
+ it "it should return a RemoteCall instance an instance of ArrayWithMetaData" do
83
+ remote_call = subject.find('with_metadata')
84
+ users = remote_call.data
85
+
86
+ expect(users).to be_instance_of(SmoothOperator::ArrayWithMetaData)
87
+ expect(users.page).to be(1)
88
+ expect(users.total).to be(6)
89
+ users.each { |user| expect(user).to be_instance_of(subject) }
90
+ end
91
+ end
92
+
93
+ context "when the server returns an array with nested object on each entry, with the same name has the resource" do
94
+ it "it should return an Array with Class instances" do
95
+ remote_call = subject.find('array_with_nested_users')
96
+ users = remote_call.data
97
+
98
+ expect(users).to be_instance_of(Array)
99
+ users.each { |user| expect(user).to be_instance_of(subject) }
100
+ end
101
+ end
102
+
103
+ end
104
+
105
+ end
@@ -0,0 +1,31 @@
1
+ require "spec_helper"
2
+
3
+ describe SmoothOperator::ModelSchema do
4
+
5
+ describe "#known_attributes" do
6
+ let(:initial_attributes_keys) { attributes_for(:user).keys.map(&:to_s) }
7
+
8
+ context "when there is no declared schema" do
9
+ subject { User::Base.new(attributes_for(:user)) }
10
+
11
+ it 'it should reflect the attributes used uppon initialization' do
12
+ expect(subject.known_attributes.to_a).to match_array(initial_attributes_keys)
13
+ end
14
+ end
15
+
16
+ context "when there is a known schema" do
17
+ subject { UserWithAddressAndPosts::Son.new(attributes_for(:user)) }
18
+ let(:known_schema_attributes) { ["posts", "address", "manager"] }
19
+
20
+ it 'it should reflect the attributes used uppon initialization' do
21
+ expect(subject.known_attributes.to_a).to include(*initial_attributes_keys)
22
+ end
23
+
24
+ it 'it should reflect the known schema attributes' do
25
+ expect(subject.known_attributes.to_a).to include(*known_schema_attributes)
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,46 @@
1
+ require "spec_helper"
2
+
3
+ describe SmoothOperator::Operator do
4
+ subject { User::Base }
5
+
6
+ describe "#get" do
7
+
8
+ context "submiting a hash, with an array" do
9
+
10
+ it 'should correctly encode that hash' do
11
+ remote_call = subject.get('test_hash_with_array', attributes_for(:user_with_address_and_posts))
12
+
13
+ expect(remote_call.status).to eq(true)
14
+ end
15
+
16
+ end
17
+
18
+ it "should send the extra params set by .query_string method" do
19
+ remote_call = subject.get('test_query_string', { normal_param: true })
20
+
21
+ expect(remote_call.status).to eq(true)
22
+ end
23
+
24
+ end
25
+
26
+ describe "#post" do
27
+
28
+ context "submiting a hash, with an array" do
29
+
30
+ it 'should correctly encode that hash' do
31
+ remote_call = subject.post('test_hash_with_array', attributes_for(:user_with_address_and_posts))
32
+
33
+ expect(remote_call.status).to eq(true)
34
+ end
35
+
36
+ end
37
+
38
+ it "should send the extra params set by .query_string method" do
39
+ remote_call = subject.post('test_query_string', { normal_param: true })
40
+
41
+ expect(remote_call.status).to eq(true)
42
+ end
43
+
44
+ end
45
+
46
+ end