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.
- checksums.yaml +8 -8
- data/Gemfile +0 -5
- data/README.md +11 -308
- data/console.rb +3 -28
- data/lib/smooth_operator.rb +7 -75
- data/lib/smooth_operator/array_with_meta_data.rb +21 -20
- data/lib/smooth_operator/attribute_assignment.rb +53 -57
- data/lib/smooth_operator/delegation.rb +34 -15
- data/lib/smooth_operator/finder_methods.rb +17 -33
- data/lib/smooth_operator/helpers.rb +7 -37
- data/lib/smooth_operator/internal_attribute.rb +49 -0
- data/lib/smooth_operator/model_schema.rb +72 -0
- data/lib/smooth_operator/open_struct.rb +4 -7
- data/lib/smooth_operator/operator.rb +64 -102
- data/lib/smooth_operator/persistence.rb +64 -94
- data/lib/smooth_operator/remote_call.rb +70 -0
- data/lib/smooth_operator/serialization.rb +33 -89
- data/lib/smooth_operator/translation.rb +13 -26
- data/lib/smooth_operator/type_converter.rb +69 -0
- data/lib/smooth_operator/validations.rb +3 -25
- data/lib/smooth_operator/version.rb +1 -1
- data/smooth_operator.gemspec +5 -9
- data/spec/factories/user_factory.rb +4 -5
- data/spec/smooth_operator/attribute_assignment_spec.rb +11 -145
- data/spec/smooth_operator/delegation_spec.rb +54 -57
- data/spec/smooth_operator/finder_methods_spec.rb +2 -91
- data/spec/smooth_operator/{resource_name_spec.rb → model_schema_spec.rb} +2 -2
- data/spec/smooth_operator/operator_spec.rb +1 -1
- data/spec/smooth_operator/persistence_spec.rb +20 -140
- data/spec/smooth_operator/serialization_spec.rb +4 -28
- data/spec/spec_helper.rb +9 -7
- data/spec/support/models/address.rb +0 -9
- data/spec/support/models/post.rb +3 -9
- data/spec/support/models/user.rb +7 -30
- data/spec/support/models/user_with_address_and_posts.rb +12 -20
- data/spec/support/test_server.rb +7 -63
- metadata +18 -55
- data/lib/smooth_operator/associations.rb +0 -110
- data/lib/smooth_operator/associations/association_reflection.rb +0 -79
- data/lib/smooth_operator/associations/has_many_relation.rb +0 -45
- data/lib/smooth_operator/associations/reflection.rb +0 -41
- data/lib/smooth_operator/cookie_jar.rb +0 -21
- data/lib/smooth_operator/http_methods.rb +0 -17
- data/lib/smooth_operator/internal_data.rb +0 -45
- data/lib/smooth_operator/operators/connection_wrapper.rb +0 -15
- data/lib/smooth_operator/operators/faraday.rb +0 -75
- data/lib/smooth_operator/operators/typhoeus.rb +0 -87
- data/lib/smooth_operator/options.rb +0 -30
- data/lib/smooth_operator/remote_call/base.rb +0 -76
- data/lib/smooth_operator/remote_call/errors/connection_failed.rb +0 -20
- data/lib/smooth_operator/remote_call/errors/timeout.rb +0 -20
- data/lib/smooth_operator/remote_call/faraday.rb +0 -19
- data/lib/smooth_operator/remote_call/typhoeus.rb +0 -19
- data/lib/smooth_operator/resource_name.rb +0 -46
- data/lib/smooth_operator/schema.rb +0 -21
- data/lib/smooth_operator/type_casting.rb +0 -127
- data/spec/require_helper.rb +0 -11
- data/spec/smooth_operator/remote_call_spec.rb +0 -340
- data/spec/smooth_operator/validations_spec.rb +0 -42
- 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
|
6
|
+
Helpers.symbolyze_keys serializable_hash(options)
|
7
7
|
end
|
8
|
-
|
9
|
-
|
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
|
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
|
-
|
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.
|
35
|
-
|
36
|
-
|
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
|
-
|
74
|
-
attribute_value = serialize_has_many_attribute(object, reflection, attribute_name, attribute_options)
|
43
|
+
protected ##################### PROTECTED ###################
|
75
44
|
|
76
|
-
|
77
|
-
|
45
|
+
def read_attribute_for_hashing(attribute_name, options)
|
46
|
+
object = read_attribute_for_serialization(attribute_name)
|
78
47
|
|
79
|
-
|
48
|
+
_options = options[attribute_name] || options[attribute_name.to_sym]
|
80
49
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
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
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
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
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
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?(
|
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
|
data/smooth_operator.gemspec
CHANGED
@@ -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"
|
27
|
-
spec.add_dependency
|
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
|
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
|
-
|
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
|
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
|
28
|
+
factory :black_list, class: User do
|
30
29
|
admin true
|
31
30
|
last_name 'Doe'
|
32
31
|
end
|