smooth_operator 1.3.0 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
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,76 +0,0 @@
1
- require "smooth_operator/cookie_jar"
2
-
3
- module SmoothOperator
4
- module RemoteCall
5
-
6
- class Base
7
-
8
- extend Forwardable
9
-
10
- attr_reader :response, :http_status, :body, :headers
11
-
12
- attr_accessor :object
13
-
14
- def initialize(response)
15
- @response = response
16
- end
17
-
18
- def ok?
19
- http_status.between?(200, 299) || http_status == 304
20
- end
21
-
22
- def not_processed?
23
- http_status == 422
24
- end
25
-
26
- def error?
27
- !ok? && !not_processed?
28
- end
29
-
30
- def client_error?
31
- http_status.between?(400, 499)
32
- end
33
-
34
- def server_error?
35
- http_status.between?(500, 599) || http_status == 0
36
- end
37
-
38
- def not_found?
39
- http_status == 404
40
- end
41
-
42
- def timeout?
43
- false
44
- end
45
-
46
- def connection_failed?
47
- false
48
- end
49
-
50
- def parsed_response
51
- return nil if body.nil?
52
-
53
- require 'json' unless defined? JSON
54
-
55
- begin
56
- JSON.parse(body)
57
- rescue JSON::ParserError
58
- body
59
- end
60
- end
61
-
62
- def status
63
- error? ? nil : ok?
64
- end
65
-
66
- def data
67
- object.nil? ? parsed_response : object
68
- end
69
-
70
- def cookie(header_field = 'set-cookie')
71
- CookieJar.new.parse(headers[header_field])
72
- end
73
-
74
- end
75
- end
76
- end
@@ -1,20 +0,0 @@
1
- module SmoothOperator
2
- module RemoteCall
3
- module Errors
4
-
5
- class ConnectionFailed < Base
6
-
7
- def initialize(response)
8
- super
9
- @http_status = 0
10
- end
11
-
12
- def connection_failed?
13
- true
14
- end
15
-
16
- end
17
-
18
- end
19
- end
20
- end
@@ -1,20 +0,0 @@
1
- module SmoothOperator
2
- module RemoteCall
3
- module Errors
4
-
5
- class Timeout < Base
6
-
7
- def initialize(response)
8
- super
9
- @http_status = 0
10
- end
11
-
12
- def timeout?
13
- true
14
- end
15
-
16
- end
17
-
18
- end
19
- end
20
- end
@@ -1,19 +0,0 @@
1
- module SmoothOperator
2
-
3
- module RemoteCall
4
-
5
- class Faraday < Base
6
-
7
- def initialize(response)
8
- @response = response
9
-
10
- @body = response.body
11
- @headers = response.headers
12
- @http_status = response.status
13
- end
14
-
15
- end
16
-
17
- end
18
-
19
- end
@@ -1,19 +0,0 @@
1
- module SmoothOperator
2
-
3
- module RemoteCall
4
-
5
- class Typhoeus < Base
6
-
7
- def initialize(response)
8
- @response = response
9
-
10
- @body = response.body
11
- @http_status = response.code
12
- @headers = response.headers_hash
13
- end
14
-
15
- end
16
-
17
- end
18
-
19
- end
@@ -1,46 +0,0 @@
1
- module SmoothOperator
2
- module ResourceName
3
-
4
- def resources_name
5
- get_option :resources_name, self.resource_name.pluralize
6
- end
7
-
8
- def resource_name
9
- get_option :resource_name, self.model_name.to_s.underscore
10
- end
11
-
12
- def model_name
13
- return '' if custom_model_name == :none
14
-
15
- if defined? ActiveModel
16
- smooth_model_name
17
- else
18
- custom_model_name ||= name.split('::').last.underscore.capitalize
19
- end
20
- end
21
-
22
- def model_name=(name)
23
- @custom_model_name = name
24
- end
25
-
26
- def custom_model_name
27
- Helpers.get_instance_variable(self, :custom_model_name, nil)
28
- end
29
-
30
- protected ############## PROTECTED #############
31
-
32
- def smooth_model_name
33
- @_model_name ||= begin
34
- namespace ||= self.parents.detect do |n|
35
- n.respond_to?(:use_relative_model_naming?) && n.use_relative_model_naming?
36
- end
37
-
38
- ActiveModel::Name.new(self, namespace, custom_model_name).tap do |model_name|
39
- def model_name.human(options = {}); SmoothOperator::Translation::HelperMethods.translate("models.#{i18n_key}", options); end
40
- end
41
- end
42
- end
43
-
44
- end
45
-
46
- end
@@ -1,21 +0,0 @@
1
- module SmoothOperator
2
- module Schema
3
-
4
- def schema(structure)
5
- internal_structure.merge! Helpers.stringify_keys(structure)
6
- end
7
-
8
- def internal_structure
9
- Helpers.get_instance_variable(self, :internal_structure, {})
10
- end
11
-
12
- def known_attribute?(attribute)
13
- internal_structure.has_key?(attribute.to_s)
14
- end
15
-
16
- def attribute_type(attribute)
17
- internal_structure[attribute.to_s]
18
- end
19
-
20
- end
21
- end
@@ -1,127 +0,0 @@
1
- module SmoothOperator
2
- module TypeCasting
3
-
4
- # RIPPED FROM RAILS
5
- TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE', 'on', 'ON'].to_set
6
- FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF'].to_set
7
-
8
- extend self
9
-
10
- def cast_to_type(name, value, parent_object)
11
- type, known_attribute, unknown_hash_class = extract_args(parent_object.class, name)
12
-
13
- return Helpers.duplicate(value) if known_attribute && type.nil?
14
-
15
- case value
16
- when Array
17
- value.map { |array_entry| cast_to_type(name, array_entry, parent_object) }
18
- when Hash
19
- type.nil? ? new_unknown_hash(value, unknown_hash_class, parent_object) : type.new(value, parent_object: parent_object)
20
- else
21
- convert(value, type)
22
- end
23
- end
24
-
25
- protected ##################### PROTECTED ########################
26
-
27
- def extract_args(parent_object_class, name)
28
- known_attribute, attribute_type = false, false
29
-
30
- if parent_object_class.respond_to?(:known_attribute?)
31
- known_attribute = parent_object_class.known_attribute?(name)
32
- end
33
-
34
- if parent_object_class.respond_to?(:attribute_type)
35
- attribute_type = parent_object_class.attribute_type(name)
36
- end
37
-
38
- [
39
- attribute_type,
40
- known_attribute,
41
- parent_object_class.unknown_hash_class
42
- ]
43
- end
44
-
45
- def convert(value, type)
46
- case type
47
-
48
- when :string, :text, String
49
- value.to_s
50
-
51
- when :int, :integer, Integer, Fixnum
52
- to_int(value)
53
-
54
- when :date, Date
55
- to_date(value)
56
-
57
- when :float, Float
58
- to_float(value)
59
-
60
- when :bool, :boolean
61
- to_boolean(value)
62
-
63
- when :datetime, :date_time, DateTime
64
- to_datetime(value)
65
-
66
- else
67
- Helpers.duplicate(value)
68
- end
69
- end
70
-
71
- def to_date(string)
72
- return string if string.is_a?(Date)
73
-
74
- Date.parse(string) rescue nil
75
- end
76
-
77
- def to_datetime(string)
78
- return string if string.is_a?(DateTime)
79
-
80
- DateTime.parse(string) rescue nil
81
- end
82
-
83
- def to_boolean(string)
84
- value = string.to_s.downcase
85
-
86
- TRUE_VALUES.include?(value) ? true : FALSE_VALUES.include?(value) ? false : nil
87
- end
88
-
89
- def to_int(string)
90
- return string if string.is_a?(Fixnum)
91
-
92
- to_float(string).to_i
93
- end
94
-
95
- def to_float(string)
96
- return string if string.is_a?(Float)
97
-
98
- return 0 if string.nil? || !(string.is_a?(String) || string.is_a?(Fixnum))
99
-
100
- value = string.to_s.gsub(',', '.').scan(/-*\d+[.]*\d*/).flatten.map(&:to_f).first
101
-
102
- value.nil? ? 0 : value
103
- end
104
-
105
- def new_unknown_hash(hash, unknown_hash_class, parent_object)
106
- if unknown_hash_class.nil?
107
- hash
108
- else
109
- unknown_hash_class.new(cast_params(hash, unknown_hash_class, parent_object))
110
- end
111
- end
112
-
113
- private ################### PRIVATE #####################
114
-
115
- def cast_params(attributes, unknown_hash_class, parent_object)
116
- hash = {}
117
-
118
- attributes.each do |key, value|
119
- hash[key] = cast_to_type(key, value, parent_object)
120
- end
121
-
122
- hash
123
- end
124
-
125
- end
126
-
127
- end
@@ -1,11 +0,0 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__))
2
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
3
-
4
- require 'bundler/setup'
5
- require 'smooth_operator'
6
-
7
- Bundler.require :test, :default
8
-
9
- Dir.chdir("spec/") do
10
- Dir["support/**/*.rb"].each { |file| require file }
11
- end
@@ -1,340 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe SmoothOperator::RemoteCall do
4
-
5
- context "when the server response has a http code in the 200 range" do
6
- before(:all) do
7
- @subject = UserWithAddressAndPosts::Son.new(attributes_for(:user_with_address_and_posts))
8
- @subject.save(nil, { status: 200 })
9
- end
10
-
11
- it "#ok? should return true" do
12
- expect(@subject.last_remote_call.ok?).to be true
13
- end
14
-
15
- it "#not_processed? should return false" do
16
- expect(@subject.last_remote_call.not_processed?).to be false
17
- end
18
-
19
- it "#client_error? should return false" do
20
- expect(@subject.last_remote_call.client_error?).to be false
21
- end
22
-
23
- it "#server_error? should return false" do
24
- expect(@subject.last_remote_call.server_error?).to be false
25
- end
26
-
27
- it "#error? should return false" do
28
- expect(@subject.last_remote_call.error?).to be false
29
- end
30
-
31
- it "#not_found? should return false" do
32
- expect(@subject.last_remote_call.not_found?).to be false
33
- end
34
-
35
- it "#timeout? should return false" do
36
- expect(@subject.last_remote_call.timeout?).to be false
37
- end
38
-
39
- it "#connection_failed? should return false" do
40
- expect(@subject.last_remote_call.connection_failed?).to be false
41
- end
42
-
43
- it "#status should return true" do
44
- expect(@subject.last_remote_call.status).to be true
45
- end
46
- end
47
-
48
- context "when the server response has a http code in the 400 range (not 422, 404)" do
49
- before(:all) do
50
- @subject = UserWithAddressAndPosts::Son.new(attributes_for(:user_with_address_and_posts))
51
- @subject.save(nil, { status: 400 })
52
- end
53
-
54
- it "#ok? should return false" do
55
- expect(@subject.last_remote_call.ok?).to be false
56
- end
57
-
58
- it "#not_processed? should return false" do
59
- expect(@subject.last_remote_call.not_processed?).to be false
60
- end
61
-
62
- it "#client_error? should return true" do
63
- expect(@subject.last_remote_call.client_error?).to be true
64
- end
65
-
66
- it "#server_error? should return false" do
67
- expect(@subject.last_remote_call.server_error?).to be false
68
- end
69
-
70
- it "#error? should return true" do
71
- expect(@subject.last_remote_call.error?).to be true
72
- end
73
-
74
- it "#not_found? should return false" do
75
- expect(@subject.last_remote_call.not_found?).to be false
76
- end
77
-
78
- it "#timeout? should return false" do
79
- expect(@subject.last_remote_call.timeout?).to be false
80
- end
81
-
82
- it "#connection_failed? should return false" do
83
- expect(@subject.last_remote_call.connection_failed?).to be false
84
- end
85
-
86
- it "#status should return nil" do
87
- expect(@subject.last_remote_call.status).to be nil
88
- end
89
- end
90
-
91
- context "when the server response has a http is 404" do
92
- before(:all) do
93
- @subject = UserWithAddressAndPosts::Son.new(attributes_for(:user_with_address_and_posts))
94
- @subject.save(nil, { status: 404 })
95
- end
96
-
97
- it "#ok? should return false" do
98
- expect(@subject.last_remote_call.ok?).to be false
99
- end
100
-
101
- it "#not_processed? should return false" do
102
- expect(@subject.last_remote_call.not_processed?).to be false
103
- end
104
-
105
- it "#client_error? should return true" do
106
- expect(@subject.last_remote_call.client_error?).to be true
107
- end
108
-
109
- it "#server_error? should return false" do
110
- expect(@subject.last_remote_call.server_error?).to be false
111
- end
112
-
113
- it "#error? should return true" do
114
- expect(@subject.last_remote_call.error?).to be true
115
- end
116
-
117
- it "#not_found? should return true" do
118
- expect(@subject.last_remote_call.not_found?).to be true
119
- end
120
-
121
- it "#timeout? should return false" do
122
- expect(@subject.last_remote_call.timeout?).to be false
123
- end
124
-
125
- it "#connection_failed? should return false" do
126
- expect(@subject.last_remote_call.connection_failed?).to be false
127
- end
128
-
129
- it "#status should return nil" do
130
- expect(@subject.last_remote_call.status).to be nil
131
- end
132
- end
133
-
134
- context "when the server response has a http is 422" do
135
- before(:all) do
136
- @subject = UserWithAddressAndPosts::Son.new(attributes_for(:user_with_address_and_posts))
137
- @subject.save(nil, { status: 422 })
138
- end
139
-
140
- it "#ok? should return false" do
141
- expect(@subject.last_remote_call.ok?).to be false
142
- end
143
-
144
- it "#not_processed? should return true" do
145
- expect(@subject.last_remote_call.not_processed?).to be true
146
- end
147
-
148
- it "#client_error? should return true" do
149
- expect(@subject.last_remote_call.client_error?).to be true
150
- end
151
-
152
- it "#server_error? should return false" do
153
- expect(@subject.last_remote_call.server_error?).to be false
154
- end
155
-
156
- it "#error? should return false" do
157
- expect(@subject.last_remote_call.error?).to be false
158
- end
159
-
160
- it "#not_found? should return false" do
161
- expect(@subject.last_remote_call.not_found?).to be false
162
- end
163
-
164
- it "#timeout? should return false" do
165
- expect(@subject.last_remote_call.timeout?).to be false
166
- end
167
-
168
- it "#connection_failed? should return false" do
169
- expect(@subject.last_remote_call.connection_failed?).to be false
170
- end
171
-
172
- it "#status should return false" do
173
- expect(@subject.last_remote_call.status).to be false
174
- end
175
- end
176
-
177
- context "when the server response has a http code in the 500 range" do
178
- before(:all) do
179
- @subject = UserWithAddressAndPosts::Son.new(attributes_for(:user_with_address_and_posts))
180
- @subject.save(nil, { status: 500 })
181
- end
182
-
183
- it "#ok? should return false" do
184
- expect(@subject.last_remote_call.ok?).to be false
185
- end
186
-
187
- it "#not_processed? should return false" do
188
- expect(@subject.last_remote_call.not_processed?).to be false
189
- end
190
-
191
- it "#client_error? should return false" do
192
- expect(@subject.last_remote_call.client_error?).to be false
193
- end
194
-
195
- it "#server_error? should return true" do
196
- expect(@subject.last_remote_call.server_error?).to be true
197
- end
198
-
199
- it "#error? should return true" do
200
- expect(@subject.last_remote_call.error?).to be true
201
- end
202
-
203
- it "#not_found? should return false" do
204
- expect(@subject.last_remote_call.not_found?).to be false
205
- end
206
-
207
- it "#timeout? should return false" do
208
- expect(@subject.last_remote_call.timeout?).to be false
209
- end
210
-
211
- it "#connection_failed? should return false" do
212
- expect(@subject.last_remote_call.connection_failed?).to be false
213
- end
214
-
215
- it "#status should return nil" do
216
- expect(@subject.last_remote_call.status).to be nil
217
- end
218
- end
219
-
220
- context "when the connection is broken" do
221
- before(:all) do
222
- @subject = User::BrokenConnection.new
223
- @subject.save
224
- end
225
-
226
- it "#ok? should return false" do
227
- expect(@subject.last_remote_call.ok?).to be false
228
- end
229
-
230
- it "#not_processed? should return false" do
231
- expect(@subject.last_remote_call.not_processed?).to be false
232
- end
233
-
234
- it "#client_error? should return false" do
235
- expect(@subject.last_remote_call.client_error?).to be false
236
- end
237
-
238
- it "#server_error? should return true" do
239
- expect(@subject.last_remote_call.server_error?).to be true
240
- end
241
-
242
- it "#error? should return true" do
243
- expect(@subject.last_remote_call.error?).to be true
244
- end
245
-
246
- it "#not_found? should return false" do
247
- expect(@subject.last_remote_call.not_found?).to be false
248
- end
249
-
250
- it "#timeout? should return false" do
251
- expect(@subject.last_remote_call.timeout?).to be false
252
- end
253
-
254
- it "#connection_failed? should return true" do
255
- expect(@subject.last_remote_call.connection_failed?).to be true
256
- end
257
-
258
- it "#status should return nil" do
259
- expect(@subject.last_remote_call.status).to be nil
260
- end
261
- end
262
-
263
- context "when the connection exceeds the timeout", current: true do
264
- before(:all) do
265
- @subject = User::TimeoutConnection.new
266
- @subject.save('/timeout')
267
- end
268
-
269
- it "#ok? should return false" do
270
- expect(@subject.last_remote_call.ok?).to be false
271
- end
272
-
273
- it "#not_processed? should return false" do
274
- expect(@subject.last_remote_call.not_processed?).to be false
275
- end
276
-
277
- it "#client_error? should return false" do
278
- expect(@subject.last_remote_call.client_error?).to be false
279
- end
280
-
281
- it "#server_error? should return true" do
282
- expect(@subject.last_remote_call.server_error?).to be true
283
- end
284
-
285
- it "#error? should return true" do
286
- expect(@subject.last_remote_call.error?).to be true
287
- end
288
-
289
- it "#not_found? should return false" do
290
- expect(@subject.last_remote_call.not_found?).to be false
291
- end
292
-
293
- it "#timeout? should return true" do
294
- expect(@subject.last_remote_call.timeout?).to be true
295
- end
296
-
297
- it "#connection_failed? should return false" do
298
- expect(@subject.last_remote_call.connection_failed?).to be false
299
- end
300
-
301
- it "#status should return nil" do
302
- expect(@subject.last_remote_call.status).to be nil
303
- end
304
- end
305
-
306
- describe "#parsed_response" do
307
- context "when the server response's body does not contains valid json data" do
308
- let(:remote_call) { User::Base.find('bad_json') }
309
-
310
- it "it should return what the server has returned" do
311
- expect(remote_call.data).to eq('ok')
312
- end
313
- end
314
- end
315
-
316
- describe "#http_status" do
317
- context "when a server connection is established" do
318
- before do
319
- @subject = UserWithAddressAndPosts::Son.new(attributes_for(:user_with_address_and_posts))
320
- @subject.save(nil, { status: 422 })
321
- end
322
-
323
- it "it should return the server's http response code" do
324
- expect(@subject.last_remote_call.http_status).to be 422
325
- end
326
- end
327
-
328
- context "when a server connection fails" do
329
- before do
330
- @subject = User::TimeoutConnection.new
331
- @subject.save('/timeout')
332
- end
333
-
334
- it "should return 0" do
335
- expect(@subject.last_remote_call.http_status).to be 0
336
- end
337
- end
338
- end
339
-
340
- end