smooth_operator 0.4.4 → 1.2.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 +9 -9
- data/.gitignore +2 -1
- data/.rspec +4 -0
- data/Gemfile +13 -0
- data/README.md +258 -10
- data/console.rb +44 -0
- data/lib/smooth_operator/array_with_meta_data.rb +31 -0
- data/lib/smooth_operator/attribute_assignment.rb +102 -0
- data/lib/smooth_operator/attribute_methods.rb +87 -0
- data/lib/smooth_operator/attributes/base.rb +107 -0
- data/lib/smooth_operator/attributes/dirty.rb +29 -0
- data/lib/smooth_operator/attributes/normal.rb +15 -0
- data/lib/smooth_operator/delegation.rb +60 -0
- data/lib/smooth_operator/finder_methods.rb +43 -0
- data/lib/smooth_operator/helpers.rb +79 -0
- data/lib/smooth_operator/model_schema.rb +81 -0
- data/lib/smooth_operator/open_struct.rb +37 -0
- data/lib/smooth_operator/operator.rb +145 -0
- data/lib/smooth_operator/operators/faraday.rb +75 -0
- data/lib/smooth_operator/operators/typhoeus.rb +77 -0
- data/lib/smooth_operator/persistence.rb +144 -0
- data/lib/smooth_operator/relation/array_relation.rb +13 -0
- data/lib/smooth_operator/relation/association_reflection.rb +75 -0
- data/lib/smooth_operator/relation/associations.rb +75 -0
- data/lib/smooth_operator/relation/reflection.rb +41 -0
- data/lib/smooth_operator/relation/single_relation.rb +14 -0
- data/lib/smooth_operator/remote_call/base.rb +80 -0
- data/lib/smooth_operator/remote_call/errors/connection_failed.rb +20 -0
- data/lib/smooth_operator/remote_call/errors/timeout.rb +20 -0
- data/lib/smooth_operator/remote_call/faraday.rb +19 -0
- data/lib/smooth_operator/remote_call/typhoeus.rb +19 -0
- data/lib/smooth_operator/serialization.rb +79 -0
- data/lib/smooth_operator/translation.rb +27 -0
- data/lib/smooth_operator/validations.rb +15 -0
- data/lib/smooth_operator/version.rb +1 -1
- data/lib/smooth_operator.rb +26 -5
- data/smooth_operator.gemspec +12 -3
- data/spec/factories/user_factory.rb +34 -0
- data/spec/require_helper.rb +11 -0
- data/spec/smooth_operator/attribute_assignment_spec.rb +351 -0
- data/spec/smooth_operator/attributes_dirty_spec.rb +53 -0
- data/spec/smooth_operator/delegation_spec.rb +139 -0
- data/spec/smooth_operator/finder_methods_spec.rb +105 -0
- data/spec/smooth_operator/model_schema_spec.rb +31 -0
- data/spec/smooth_operator/operator_spec.rb +46 -0
- data/spec/smooth_operator/persistence_spec.rb +424 -0
- data/spec/smooth_operator/remote_call_spec.rb +320 -0
- data/spec/smooth_operator/serialization_spec.rb +80 -0
- data/spec/smooth_operator/validations_spec.rb +42 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/support/helpers/persistence_helper.rb +38 -0
- data/spec/support/localhost_server.rb +97 -0
- data/spec/support/models/address.rb +14 -0
- data/spec/support/models/comment.rb +3 -0
- data/spec/support/models/post.rb +13 -0
- data/spec/support/models/user.rb +41 -0
- data/spec/support/models/user_with_address_and_posts.rb +89 -0
- data/spec/support/test_server.rb +165 -0
- metadata +108 -18
- data/lib/smooth_operator/base.rb +0 -30
- data/lib/smooth_operator/core.rb +0 -218
- data/lib/smooth_operator/http_handlers/typhoeus/base.rb +0 -58
- data/lib/smooth_operator/http_handlers/typhoeus/orm.rb +0 -34
- data/lib/smooth_operator/http_handlers/typhoeus/remote_call.rb +0 -28
- data/lib/smooth_operator/operator/base.rb +0 -43
- data/lib/smooth_operator/operator/exceptions.rb +0 -64
- data/lib/smooth_operator/operator/orm.rb +0 -118
- data/lib/smooth_operator/operator/remote_call.rb +0 -84
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'typhoeus'
|
2
|
+
require "smooth_operator/remote_call/typhoeus"
|
3
|
+
|
4
|
+
module SmoothOperator
|
5
|
+
|
6
|
+
module Operators
|
7
|
+
|
8
|
+
module Typhoeus
|
9
|
+
|
10
|
+
extend self
|
11
|
+
|
12
|
+
def make_the_call(http_verb, resource_path, params, body, options)
|
13
|
+
request = ::Typhoeus::Request.new *typhoeus_request_args(http_verb, resource_path, params, body, options)
|
14
|
+
|
15
|
+
hydra = options[:hydra] || ::Typhoeus::Hydra::hydra
|
16
|
+
|
17
|
+
_remote_call = nil
|
18
|
+
|
19
|
+
hydra.queue(request)
|
20
|
+
|
21
|
+
request.on_complete do |typhoeus_response|
|
22
|
+
_remote_call = remote_call(typhoeus_response)
|
23
|
+
|
24
|
+
yield(_remote_call) if block_given?
|
25
|
+
end
|
26
|
+
|
27
|
+
hydra.run if Helpers.blank?(options[:hydra])
|
28
|
+
|
29
|
+
_remote_call
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
protected ################ PROTECTED ################
|
34
|
+
|
35
|
+
def typhoeus_request_args(http_verb, relative_path, params, body, options)
|
36
|
+
[url(options, relative_path), build_typhoeus_options(http_verb, params, body, options)]
|
37
|
+
end
|
38
|
+
|
39
|
+
def remote_call(typhoeus_response)
|
40
|
+
if typhoeus_response.return_code == :couldnt_connect
|
41
|
+
RemoteCall::Errors::ConnectionFailed
|
42
|
+
elsif typhoeus_response.timed_out?
|
43
|
+
RemoteCall::Errors::Timeout
|
44
|
+
else
|
45
|
+
RemoteCall::Typhoeus
|
46
|
+
end.new(typhoeus_response)
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
private ################### PRIVATE ###############
|
51
|
+
|
52
|
+
def build_typhoeus_options(http_verb, params, body, options)
|
53
|
+
typhoeus_options = { method: http_verb, headers: options[:headers].merge({ "Content-type" => "application/x-www-form-urlencoded" }) }
|
54
|
+
|
55
|
+
typhoeus_options[:timeout] = options[:timeout] if Helpers.present?(options[:timeout])
|
56
|
+
|
57
|
+
typhoeus_options[:body] = body if Helpers.present?(body)
|
58
|
+
|
59
|
+
typhoeus_options[:params] = params if Helpers.present?(params)
|
60
|
+
|
61
|
+
typhoeus_options[:userpwd] = "#{options[:endpoint_user]}:#{options[:endpoint_pass]}" if Helpers.present?(options[:endpoint_user])
|
62
|
+
|
63
|
+
typhoeus_options
|
64
|
+
end
|
65
|
+
|
66
|
+
def url(options, relative_path)
|
67
|
+
url = options[:endpoint]
|
68
|
+
|
69
|
+
slice = url[-1] != '/' ? '/' : ''
|
70
|
+
|
71
|
+
url = "#{url}#{slice}#{relative_path}" if Helpers.present?(relative_path)
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
module SmoothOperator
|
2
|
+
module Persistence
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :last_remote_call
|
9
|
+
|
10
|
+
def get_primary_key
|
11
|
+
get_internal_data(self.class.primary_key)
|
12
|
+
end
|
13
|
+
|
14
|
+
def reload(relative_path = nil, data = {}, options = {})
|
15
|
+
raise 'UnknownPath' if Helpers.blank?(relative_path) && (!respond_to?(self.class.primary_key) || Helpers.blank?(get_primary_key))
|
16
|
+
|
17
|
+
persistence_call(:reload, relative_path, data, options) do |remote_call|
|
18
|
+
block_given? ? yield(remote_call) : remote_call.status
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def new_record?(bypass_cache = false)
|
23
|
+
return @new_record if !bypass_cache && defined?(@new_record)
|
24
|
+
|
25
|
+
@new_record = Helpers.blank?(get_primary_key)
|
26
|
+
end
|
27
|
+
|
28
|
+
def marked_for_destruction?(bypass_cache = false)
|
29
|
+
return @marked_for_destruction if !bypass_cache && defined?(@marked_for_destruction)
|
30
|
+
|
31
|
+
@marked_for_destruction = ["true", "1", true].include?(get_internal_data(self.class.destroy_key))
|
32
|
+
end
|
33
|
+
|
34
|
+
def destroyed?
|
35
|
+
return @destroyed if defined?(@destroyed)
|
36
|
+
|
37
|
+
@destroyed = false
|
38
|
+
end
|
39
|
+
|
40
|
+
def persisted?
|
41
|
+
!(new_record? || destroyed?)
|
42
|
+
end
|
43
|
+
|
44
|
+
def save(relative_path = nil, data = {}, options = {})
|
45
|
+
data = data_with_object_attributes(data, options)
|
46
|
+
|
47
|
+
if new_record?
|
48
|
+
create(relative_path, data, options) { |remote_call| block_given? ? yield(remote_call) : remote_call.status }
|
49
|
+
else
|
50
|
+
update(relative_path, data, options) { |remote_call| block_given? ? yield(remote_call) : remote_call.status }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def save!(relative_path = nil, data = {}, options = {})
|
55
|
+
save(relative_path, data, options) do |remote_call|
|
56
|
+
block_given? ? yield(remote_call) : remote_call.status
|
57
|
+
end || raise('RecordNotSaved')
|
58
|
+
end
|
59
|
+
|
60
|
+
def destroy(relative_path = nil, data = {}, options = {})
|
61
|
+
return false unless persisted?
|
62
|
+
|
63
|
+
persistence_call(:destroy, relative_path, data, options) do |remote_call|
|
64
|
+
@destroyed = true if remote_call.status
|
65
|
+
|
66
|
+
block_given? ? yield(remote_call) : remote_call.status
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
protected ######################### PROTECTED ##################
|
72
|
+
|
73
|
+
def create(relative_path, data, options)
|
74
|
+
persistence_call(:create, relative_path, data, options) do |remote_call|
|
75
|
+
@new_record = false if remote_call.status
|
76
|
+
|
77
|
+
block_given? ? yield(remote_call) : remote_call
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def update(relative_path, data, options)
|
82
|
+
persistence_call(:update, relative_path, data, options) do |remote_call|
|
83
|
+
block_given? ? yield(remote_call) : remote_call
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def persistence_call(method, relative_path, data, options)
|
88
|
+
options ||= {}
|
89
|
+
|
90
|
+
http_verb = options[:http_verb] || self.class.methods_vs_http_verbs[method]
|
91
|
+
|
92
|
+
make_the_call(http_verb, relative_path, data, options) do |remote_call|
|
93
|
+
@last_remote_call = remote_call
|
94
|
+
|
95
|
+
if !@last_remote_call.error? && @last_remote_call.parsed_response.is_a?(Hash)
|
96
|
+
assign_attributes @last_remote_call.parsed_response, from_server: true
|
97
|
+
end
|
98
|
+
|
99
|
+
yield(remote_call)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def data_with_object_attributes(data, options)
|
104
|
+
data = Helpers.stringify_keys(data)
|
105
|
+
|
106
|
+
hash = serializable_hash(options[:serializable_options]).dup
|
107
|
+
|
108
|
+
hash.delete(self.class.primary_key)
|
109
|
+
|
110
|
+
{ self.class.resource_name => hash }.merge(data)
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
module ClassMethods
|
115
|
+
|
116
|
+
METHODS_VS_HTTP_VERBS = { reload: :get, create: :post, update: :put, destroy: :delete }
|
117
|
+
|
118
|
+
def methods_vs_http_verbs
|
119
|
+
Helpers.get_instance_variable(self, :methods_vs_http_verbs, METHODS_VS_HTTP_VERBS.dup)
|
120
|
+
end
|
121
|
+
|
122
|
+
def primary_key
|
123
|
+
Helpers.get_instance_variable(self, :primary_key, 'id')
|
124
|
+
end
|
125
|
+
|
126
|
+
attr_writer :primary_key
|
127
|
+
|
128
|
+
def destroy_key
|
129
|
+
Helpers.get_instance_variable(self, :destroy_key, '_destroy')
|
130
|
+
end
|
131
|
+
|
132
|
+
attr_writer :destroy_key
|
133
|
+
|
134
|
+
METHODS_VS_HTTP_VERBS.keys.each do |method|
|
135
|
+
define_method("#{method}_http_verb=") { |http_verb| methods_vs_http_verbs[method] = http_verb }
|
136
|
+
end
|
137
|
+
|
138
|
+
def create(attributes = nil, relative_path = nil, data = {}, options = {})
|
139
|
+
new(attributes).tap { |object| object.save(relative_path, data, options) }
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require "smooth_operator/relation/reflection"
|
2
|
+
|
3
|
+
module SmoothOperator
|
4
|
+
module Relation
|
5
|
+
class AssociationReflection < Reflection
|
6
|
+
|
7
|
+
attr_reader :related_reflection, :macro
|
8
|
+
|
9
|
+
def initialize(association, related_reflection, options)
|
10
|
+
super(association, options)
|
11
|
+
@macro = options[:macro] || macro_default(association)
|
12
|
+
@related_reflection = related_reflection
|
13
|
+
end
|
14
|
+
|
15
|
+
def primary_key
|
16
|
+
@primary_key ||= options[:primary_key] || :id
|
17
|
+
end
|
18
|
+
|
19
|
+
def foreign_key
|
20
|
+
@foreign_key ||= options[:foreign_key] || foreign_key_default
|
21
|
+
end
|
22
|
+
|
23
|
+
def set_relational_keys(origin, destination)
|
24
|
+
return nil if options[:standalone] == true
|
25
|
+
|
26
|
+
if has_many? || has_one?
|
27
|
+
set_foreign_key(destination, primary_key_of(origin))
|
28
|
+
elsif belongs_to?
|
29
|
+
set_foreign_key(origin, primary_key_of(destination))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def set_foreign_key(object, id)
|
34
|
+
setter = "#{foreign_key}="
|
35
|
+
|
36
|
+
if object.respond_to?(setter)
|
37
|
+
object.send(setter, id)
|
38
|
+
elsif object.respond_to?("send_to_representative")
|
39
|
+
object.send_to_representative(setter, id)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def primary_key_of(object)
|
44
|
+
object.send(primary_key)
|
45
|
+
end
|
46
|
+
|
47
|
+
def has_many?
|
48
|
+
macro == :has_many
|
49
|
+
end
|
50
|
+
|
51
|
+
def has_one?
|
52
|
+
macro == :has_one
|
53
|
+
end
|
54
|
+
|
55
|
+
def belongs_to?
|
56
|
+
macro == :belongs_to
|
57
|
+
end
|
58
|
+
|
59
|
+
private ################################# private
|
60
|
+
|
61
|
+
def macro_default(association)
|
62
|
+
Helpers.plural?(association) ? :has_many : :belongs_to
|
63
|
+
end
|
64
|
+
|
65
|
+
def foreign_key_default
|
66
|
+
if has_many? || has_one?
|
67
|
+
"#{related_reflection.single_name}_id"
|
68
|
+
elsif belongs_to?
|
69
|
+
"#{single_name}_id"
|
70
|
+
end.to_sym
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require "smooth_operator/relation/array_relation"
|
2
|
+
require "smooth_operator/relation/association_reflection"
|
3
|
+
|
4
|
+
module SmoothOperator
|
5
|
+
module Relation
|
6
|
+
module Associations
|
7
|
+
|
8
|
+
def relations
|
9
|
+
@relations ||= {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_relation(relation_name)
|
13
|
+
relations[relation_name] ||= self.class.build_relation(relation_name, get_internal_data(relation_name))
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.included(base)
|
17
|
+
base.extend(ClassMethods)
|
18
|
+
end
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
|
22
|
+
def has_many(nested_object_name, options = {})
|
23
|
+
accepts_nested_objects(nested_object_name, :has_many, options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def has_one(nested_object_name, options = {})
|
27
|
+
accepts_nested_objects(nested_object_name, :has_one, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
def belongs_to(nested_object_name, options = {})
|
31
|
+
accepts_nested_objects(nested_object_name, :belongs_to, options)
|
32
|
+
end
|
33
|
+
|
34
|
+
def reflections
|
35
|
+
Helpers.get_instance_variable(self, :reflections, {})
|
36
|
+
end
|
37
|
+
|
38
|
+
def reflect_on_association(association)
|
39
|
+
reflections[association]
|
40
|
+
end
|
41
|
+
|
42
|
+
def reflect_on_all_associations(macro = nil)
|
43
|
+
macro ? reflections.values.select { |reflection| reflection.macro == macro } : reflections.values
|
44
|
+
end
|
45
|
+
|
46
|
+
def build_relation(relation_name, data)
|
47
|
+
if reflections[relation_name.to_sym].has_many?
|
48
|
+
ArrayRelation.new(data || [], relation_name)
|
49
|
+
else
|
50
|
+
SingleRelation.new(data, relation_name)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
protected ###################### PROTECTED ###################
|
55
|
+
|
56
|
+
def accepts_nested_objects(nested_object_name, macro, options = {})
|
57
|
+
default_options = { macro: macro }
|
58
|
+
options = options.is_a?(Hash) ? options.merge(default_options) : default_options
|
59
|
+
options = Helpers.symbolyze_keys(options)
|
60
|
+
|
61
|
+
reflection = AssociationReflection.new(nested_object_name, Reflection.new(name, {}), options)
|
62
|
+
|
63
|
+
self.send(:attr_accessor, "#{nested_object_name}_attributes".to_sym)
|
64
|
+
self.instance_variable_set("@reflections", reflections.merge(nested_object_name => reflection))
|
65
|
+
|
66
|
+
define_method("existing_#{nested_object_name}") { existing_nested_objects(nested_object_name) }
|
67
|
+
define_method("build_#{reflection.single_name}") { |attributes = {}, nested_object = nil| build_nested_object(nested_object_name, attributes, nested_object) }
|
68
|
+
|
69
|
+
schema(nested_object_name => reflection.klass)
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module SmoothOperator
|
2
|
+
module Relation
|
3
|
+
class Reflection
|
4
|
+
|
5
|
+
attr_reader :name, :klass, :options
|
6
|
+
|
7
|
+
def initialize(class_name, options)
|
8
|
+
options = options.is_a?(Hash) ? options : {}
|
9
|
+
|
10
|
+
@name, @options = class_name, options
|
11
|
+
|
12
|
+
@klass = options[:class_name] || klass_default(@name)
|
13
|
+
|
14
|
+
if options.include?(:class_name) && options[:class_name].nil?
|
15
|
+
@klass = nil
|
16
|
+
elsif @klass.is_a?(String)
|
17
|
+
@klass = @klass.constantize
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def single_name
|
22
|
+
@single_name ||= options[:single_name] || name.to_s.singularize
|
23
|
+
end
|
24
|
+
|
25
|
+
def plural_name
|
26
|
+
@plural_name ||= options[:plural_name] || name.to_s.pluralize
|
27
|
+
end
|
28
|
+
|
29
|
+
private ################################# private
|
30
|
+
|
31
|
+
def klass_default(class_name)
|
32
|
+
if Helpers.plural?(class_name)
|
33
|
+
class_name.to_s.singularize.camelize
|
34
|
+
else
|
35
|
+
class_name.to_s.camelize
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module SmoothOperator
|
2
|
+
|
3
|
+
module RemoteCall
|
4
|
+
|
5
|
+
class Base
|
6
|
+
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
attr_reader :response, :http_status, :body, :headers
|
10
|
+
|
11
|
+
attr_accessor :object
|
12
|
+
|
13
|
+
def initialize(response)
|
14
|
+
@response = response
|
15
|
+
end
|
16
|
+
|
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
|
+
|
39
|
+
def not_found?
|
40
|
+
http_status == 404
|
41
|
+
end
|
42
|
+
|
43
|
+
def timeout?
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
47
|
+
def connection_failed?
|
48
|
+
false
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
def parsed_response
|
53
|
+
return nil if body.nil?
|
54
|
+
|
55
|
+
require 'json' unless defined? JSON
|
56
|
+
|
57
|
+
begin
|
58
|
+
JSON.parse(body)
|
59
|
+
rescue JSON::ParserError
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def status
|
65
|
+
error? ? nil : ok?
|
66
|
+
end
|
67
|
+
|
68
|
+
def objects
|
69
|
+
object.respond_to?(:length) ? object : []
|
70
|
+
end
|
71
|
+
|
72
|
+
def data
|
73
|
+
object.nil? ? parsed_response : object
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1,19 @@
|
|
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
|
@@ -0,0 +1,19 @@
|
|
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
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module SmoothOperator
|
2
|
+
|
3
|
+
module Serialization
|
4
|
+
|
5
|
+
def to_hash(options = nil)
|
6
|
+
Helpers.symbolyze_keys(serializable_hash(options) || {})
|
7
|
+
end
|
8
|
+
|
9
|
+
# alias :attributes :to_hash
|
10
|
+
def attributes; to_hash; end
|
11
|
+
|
12
|
+
def to_json(options = nil)
|
13
|
+
require 'json' unless defined? JSON
|
14
|
+
|
15
|
+
JSON(serializable_hash(options) || {})
|
16
|
+
end
|
17
|
+
|
18
|
+
def read_attribute_for_serialization(attribute)
|
19
|
+
send(attribute)
|
20
|
+
end
|
21
|
+
|
22
|
+
def serializable_hash(options = nil)
|
23
|
+
hash = {}
|
24
|
+
options ||= {}
|
25
|
+
|
26
|
+
attribute_names(options).each do |attribute_name|
|
27
|
+
hash[attribute_name] = read_attribute_for_hashing(attribute_name, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
method_names(options).each do |method_name|
|
31
|
+
hash[method_name.to_s] = send(method_name)
|
32
|
+
end
|
33
|
+
|
34
|
+
hash
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
protected ##################### PROTECTED ###################
|
39
|
+
|
40
|
+
# TODO: COMPLEX METHOD
|
41
|
+
def attribute_names(options)
|
42
|
+
attribute_names = internal_data.keys.sort
|
43
|
+
|
44
|
+
if only = options[:only]
|
45
|
+
attribute_names &= [*only].map(&:to_s)
|
46
|
+
elsif except = options[:except]
|
47
|
+
attribute_names -= [*except].map(&:to_s)
|
48
|
+
end
|
49
|
+
|
50
|
+
attribute_names
|
51
|
+
end
|
52
|
+
|
53
|
+
def method_names(options)
|
54
|
+
[*options[:methods]].select { |n| respond_to?(n) }
|
55
|
+
end
|
56
|
+
|
57
|
+
def read_attribute_for_hashing(attribute_name, options)
|
58
|
+
object = read_attribute_for_serialization(attribute_name)
|
59
|
+
|
60
|
+
_options = options[attribute_name] || options[attribute_name.to_sym]
|
61
|
+
|
62
|
+
if object.is_a?(Array)
|
63
|
+
object.map { |array_entry| attribute_to_hash(array_entry, _options) }
|
64
|
+
else
|
65
|
+
attribute_to_hash(object, _options)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def attribute_to_hash(object, options = nil)
|
70
|
+
if object.respond_to?(:serializable_hash)
|
71
|
+
Helpers.symbolyze_keys(object.serializable_hash(options))
|
72
|
+
else
|
73
|
+
object
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|