smooth_operator 0.4.4 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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