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