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,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