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
@@ -0,0 +1,70 @@
1
+ module SmoothOperator
2
+
3
+ module RemoteCall
4
+
5
+ class Base
6
+
7
+ extend Forwardable
8
+
9
+ attr_reader :response
10
+
11
+ attr_accessor :object
12
+
13
+ def_delegator :response, :status, :http_status
14
+
15
+ def_delegators :response, :success?, :headers, :body
16
+
17
+ def initialize(response, object_class = nil)
18
+ @response, @object_class = response, object_class
19
+ end
20
+
21
+
22
+ def failure?
23
+ http_status.between?(400, 499)
24
+ end
25
+
26
+ def error?
27
+ http_status.between?(500, 599)
28
+ end
29
+
30
+ def parsed_response
31
+ require 'json' unless defined? JSON
32
+
33
+ begin
34
+ JSON.parse(body)
35
+ rescue JSON::ParserError
36
+ nil
37
+ end
38
+ end
39
+
40
+ def status
41
+ error? ? nil : success?
42
+ end
43
+
44
+ def objects
45
+ object.respond_to?(:length) ? object : []
46
+ end
47
+
48
+ def data
49
+ object.nil? ? parsed_response : object
50
+ end
51
+
52
+ end
53
+
54
+ class ConnectionFailed
55
+
56
+ attr_reader :data, :object, :objects, :status, :headers, :body
57
+
58
+ def http_status; 0; end
59
+
60
+ def error?; true; end
61
+
62
+ def success?; false; end
63
+
64
+ def failure?; false; end
65
+
66
+ end
67
+
68
+ end
69
+
70
+ end
@@ -3,121 +3,65 @@ module SmoothOperator
3
3
  module Serialization
4
4
 
5
5
  def to_hash(options = nil)
6
- Helpers.symbolyze_keys(serializable_hash(options) || {})
6
+ Helpers.symbolyze_keys serializable_hash(options)
7
7
  end
8
-
9
- def attributes; to_hash; end
10
-
8
+
9
+ alias :attributes :to_hash
10
+
11
11
  def to_json(options = nil)
12
12
  require 'json' unless defined? JSON
13
-
14
- JSON(serializable_hash(options) || {})
13
+
14
+ JSON(serializable_hash(options))
15
15
  end
16
16
 
17
17
  def read_attribute_for_serialization(attribute)
18
18
  send(attribute)
19
19
  end
20
20
 
21
- def serializable_hash(options = nil)
22
- hash = {}
21
+ def serializable_hash(options = nil) # Code inspired in ActiveSupport#serializable_hash
23
22
  options ||= {}
24
- method_names = HelperMethods.method_names(self, options)
25
- attribute_names = HelperMethods.attribute_names(self, options)
26
23
 
27
- attribute_names.each do |attribute_name|
28
- attribute_name, attribute_value = HelperMethods
29
- .serialize_normal_or_rails_way(self, attribute_name, options)
24
+ attribute_names = internal_data.keys.sort
30
25
 
31
- hash[attribute_name] = attribute_value
26
+ if only = options[:only]
27
+ attribute_names &= [*only].map(&:to_s)
28
+ elsif except = options[:except]
29
+ attribute_names -= [*except].map(&:to_s)
32
30
  end
33
31
 
34
- method_names.each do |method_name|
35
- hash[method_name.to_s] = HelperMethods.serialize_normal_attribute(send(method_name), method_name, options[method_name])
36
- end
32
+ method_names = [*options[:methods]].select { |n| respond_to?(n) }
33
+
34
+ hash = {}
35
+
36
+ attribute_names.each { |attribute_name| hash[attribute_name] = read_attribute_for_hashing(attribute_name, options) }
37
+ method_names.each { |method_name| hash[method_name.to_s] = send(method_name) }
37
38
 
38
39
  hash
39
40
  end
40
41
 
41
- module HelperMethods
42
-
43
- extend self
44
-
45
- def attribute_names(object, options)
46
- attribute_names = object.internal_data.keys.sort
47
-
48
- if only = options[:only]
49
- white_list = [*only].map(&:to_s)
50
-
51
- attribute_names &= white_list
52
- elsif except = options[:except]
53
- black_list = [*except].map(&:to_s)
54
-
55
- attribute_names -= black_list
56
- end
57
-
58
- attribute_names
59
- end
60
-
61
- def method_names(object, options)
62
- [*options[:methods]].select { |n| object.respond_to?(n) }
63
- end
64
-
65
- def serialize_normal_or_rails_way(object, attribute_name, options)
66
- _attribute_name, attribute_sym = attribute_name, attribute_name.to_sym
67
-
68
- reflection = object.class.respond_to?(:reflect_on_association) &&
69
- object.class.reflect_on_association(attribute_sym)
70
-
71
- attribute_options = options[attribute_sym]
72
42
 
73
- if reflection && reflection.rails_serialization?
74
- attribute_value = serialize_has_many_attribute(object, reflection, attribute_name, attribute_options)
43
+ protected ##################### PROTECTED ###################
75
44
 
76
- _attribute_name = "#{attribute_name}_attributes"
77
- end
45
+ def read_attribute_for_hashing(attribute_name, options)
46
+ object = read_attribute_for_serialization(attribute_name)
78
47
 
79
- attribute_value ||= serialize_normal_attribute(object, attribute_name, attribute_options)
48
+ _options = options[attribute_name] || options[attribute_name.to_sym]
80
49
 
81
- [_attribute_name, attribute_value]
82
- end
83
-
84
- def serialize_has_many_attribute(parent_object, reflection, attribute_name, options)
85
- return nil unless reflection.has_many?
86
-
87
- object = parent_object.read_attribute_for_serialization(attribute_name)
88
-
89
- object.reduce({}) do |hash, array_entry|
90
- id = Helpers.present?(array_entry.id) ? array_entry.id : Helpers.generated_id
91
-
92
- hash[id.to_s] = attribute_to_hash(array_entry, options)
93
-
94
- hash
95
- end
96
- end
97
-
98
- def serialize_normal_attribute(parent_object, attribute_name, options)
99
- if parent_object.respond_to?(:read_attribute_for_serialization)
100
- object = parent_object.read_attribute_for_serialization(attribute_name)
101
- else
102
- object = parent_object
103
- end
104
-
105
- if object.is_a?(Array)
106
- object.map { |array_entry| attribute_to_hash(array_entry, options) }
107
- else
108
- attribute_to_hash(object, options)
109
- end
50
+ if object.is_a?(Array)
51
+ object.map { |array_entry| attribute_to_hash(array_entry, _options) }
52
+ else
53
+ attribute_to_hash(object, _options)
110
54
  end
55
+ end
111
56
 
112
- def attribute_to_hash(object, options = nil)
113
- if object.respond_to?(:serializable_hash)
114
- Helpers.symbolyze_keys(object.serializable_hash(options))
115
- else
116
- object
117
- end
57
+ def attribute_to_hash(object, options = nil)
58
+ if object.respond_to?(:serializable_hash)
59
+ Helpers.symbolyze_keys(object.serializable_hash(options))
60
+ else
61
+ object
118
62
  end
119
-
120
63
  end
121
64
 
122
65
  end
66
+
123
67
  end
@@ -1,33 +1,20 @@
1
1
  module SmoothOperator
2
+
2
3
  module Translation
3
4
 
4
5
  def human_attribute_name(attribute_key_name, options = {})
5
- HelperMethods.translate(
6
- "attributes.#{model_name.i18n_key}.#{attribute_key_name}",
7
- options
8
- )
9
- end
10
-
11
- module HelperMethods
12
-
13
- extend self
14
-
15
- def translate(namespace = '', options = {})
16
- no_translation = "-- no translation --"
17
-
18
- defaults = ["smooth_operator.#{namespace}".to_sym]
19
- defaults << "activerecord.#{namespace}".to_sym
20
- defaults << options[:default] if options[:default]
21
- defaults.flatten!
22
- defaults << no_translation
23
-
24
- options = { count: 1, default: defaults }
25
- .merge!(options.except(:default))
26
-
27
- I18n.translate(defaults.shift, options)
28
- end
29
-
6
+ no_translation = "-- no translation --"
7
+
8
+ defaults = ["smooth_operator.attributes.#{name.underscore}.#{attribute_key_name}".to_sym]
9
+ defaults << "activerecord.attributes.#{name.underscore}.#{attribute_key_name}".to_sym
10
+ defaults << options[:default] if options[:default]
11
+ defaults.flatten!
12
+ defaults << no_translation
13
+ options[:count] ||= 1
14
+
15
+ I18n.translate(defaults.shift, options.merge(default: defaults))
30
16
  end
31
17
 
32
18
  end
33
- end
19
+
20
+ end
@@ -0,0 +1,69 @@
1
+ module SmoothOperator
2
+
3
+ module TypeConverter
4
+
5
+ extend self
6
+
7
+ def convert(value, type)
8
+ case type
9
+
10
+ when :string, :text, String
11
+ value.to_s
12
+
13
+ when :int, :integer, Integer, Fixnum
14
+ TypeConverter.to_int(value)
15
+
16
+ when :date, Date
17
+ TypeConverter.to_date(value)
18
+
19
+ when :float, Float
20
+ TypeConverter.to_float(value)
21
+
22
+ when :bool, :boolean
23
+ TypeConverter.to_boolean(value)
24
+
25
+ when :datetime, :date_time, DateTime
26
+ TypeConverter.to_datetime(value)
27
+
28
+ else
29
+ value
30
+ end
31
+ end
32
+
33
+ def to_int(string)
34
+ return string if string.is_a?(Fixnum)
35
+
36
+ to_float(string).to_i
37
+ end
38
+
39
+ def to_date(string)
40
+ return string if string.is_a?(Date)
41
+
42
+ Date.parse(string) rescue nil
43
+ end
44
+
45
+ def to_datetime(string)
46
+ return string if string.is_a?(DateTime)
47
+
48
+ DateTime.parse(string) rescue nil
49
+ end
50
+
51
+ def to_boolean(string)
52
+ value = string.to_s.downcase
53
+
54
+ ['1', 'true'].include?(value) ? true : ['0', 'false'].include?(value) ? false : nil
55
+ end
56
+
57
+ def to_float(string)
58
+ return string if string.is_a?(Float)
59
+
60
+ return 0 if string.nil? || !string.is_a?(String)
61
+
62
+ value = string.scan(/-*\d+[,.]*\d*/).flatten.map(&:to_f).first
63
+
64
+ value.nil? ? 0 : value
65
+ end
66
+
67
+ end
68
+
69
+ end
@@ -1,37 +1,15 @@
1
1
  module SmoothOperator
2
+
2
3
  module Validations
3
4
 
4
5
  def valid?(context = nil)
5
- Helpers.blank?(induced_errors)
6
+ Helpers.blank?(get_internal_data("errors"))
6
7
  end
7
8
 
8
9
  def invalid?
9
10
  !valid?
10
11
  end
11
12
 
12
- def induced_errors
13
- @induced_errors ||= {}
14
- end
15
-
16
- def clear_induced_errors
17
- @induced_errors = {}
18
- end
19
-
20
- def induce_errors(value)
21
- @induced_errors = value
22
- end
23
-
24
- def self.included(base)
25
- base.extend(ClassMethods)
26
- end
27
-
28
- module ClassMethods
29
-
30
- def errors_key
31
- get_option :errors_key, 'errors'
32
- end
33
-
34
- end
35
-
36
13
  end
14
+
37
15
  end
@@ -1,3 +1,3 @@
1
1
  module SmoothOperator
2
- VERSION = '1.3.0'
2
+ VERSION = "1.8.0"
3
3
  end
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.authors = ["João Gonçalves"]
13
13
  spec.email = ["goncalves.joao@gmail.com"]
14
14
  spec.description = %q{ActiveResource alternative}
15
- spec.summary = %q{Simple and fully customizable alternative to ActiveResource, using faraday gem to stablish remote calls"}
15
+ spec.summary = %q{Simple and fully customizable alternative to ActiveResource, using faraday gem to stablish parallel remote calls"}
16
16
  spec.homepage = "https://github.com/goncalvesjoao/smooth_operator"
17
17
  spec.license = "MIT"
18
18
 
@@ -20,13 +20,9 @@ Gem::Specification.new do |spec|
20
20
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
21
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
22
  spec.require_paths = ["lib"]
23
-
23
+
24
24
  spec.add_development_dependency "bundler", "~> 1.3"
25
-
26
- spec.add_dependency "json", '~> 1.5'
27
- spec.add_dependency "faraday", "~> 0.8"
28
- spec.add_dependency "typhoeus", "~> 0.6"
29
-
30
- # this is necessary if you want to typhoeus to correctly encode arrays
31
- # spec.add_dependency "ethon", :git => 'https://github.com/goncalvesjoao/ethon'
25
+
26
+ spec.add_dependency "json"
27
+ spec.add_dependency 'faraday', '> 0.9.0.rc5'
32
28
  end
@@ -1,6 +1,6 @@
1
1
  FactoryGirl.define do
2
2
 
3
- factory :user, class: User::Base do
3
+ factory :user, class: User do
4
4
 
5
5
  id 1
6
6
  admin true
@@ -9,8 +9,7 @@ FactoryGirl.define do
9
9
 
10
10
  trait :with_address_and_posts do
11
11
  address { { street: 'my_street' } }
12
- # posts [{ id: 1, body: 'post1' }, { id: 2, body: 'post2' }]
13
- posts [{ id: 1 }, { id: 2 }]
12
+ posts [{ body: 'post1' }, { body: 'post2' }]
14
13
  end
15
14
  factory :user_with_address_and_posts, traits: [:with_address_and_posts]
16
15
 
@@ -21,12 +20,12 @@ FactoryGirl.define do
21
20
 
22
21
  end
23
22
 
24
- factory :white_list, class: User::Base do
23
+ factory :white_list, class: User do
25
24
  id 1
26
25
  first_name 'John'
27
26
  end
28
27
 
29
- factory :black_list, class: User::Base do
28
+ factory :black_list, class: User do
30
29
  admin true
31
30
  last_name 'Doe'
32
31
  end