smooth_operator 0.4.4 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,107 @@
|
|
1
|
+
module SmoothOperator
|
2
|
+
module Attributes
|
3
|
+
|
4
|
+
class Base
|
5
|
+
|
6
|
+
protected ##################### PROTECTED ########################
|
7
|
+
|
8
|
+
def cast_to_type(name, value, parent_object)
|
9
|
+
known_by_schema, type, unknown_hash_class = parent_object.known_by_schema?(name), parent_object.get_attribute_type(name), parent_object.class.unknown_hash_class
|
10
|
+
|
11
|
+
return Helpers.duplicate(value) if known_by_schema && type.nil?
|
12
|
+
|
13
|
+
case value
|
14
|
+
when Array
|
15
|
+
value.map { |array_entry| self.class.new(name, array_entry, parent_object).value }
|
16
|
+
when Hash
|
17
|
+
type.nil? ? new_unknown_hash(value, unknown_hash_class, parent_object) : type.new(value, parent_object: parent_object)
|
18
|
+
else
|
19
|
+
convert(value, type)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def convert(value, type)
|
24
|
+
case type
|
25
|
+
|
26
|
+
when :string, :text, String
|
27
|
+
value.to_s
|
28
|
+
|
29
|
+
when :int, :integer, Integer, Fixnum
|
30
|
+
to_int(value)
|
31
|
+
|
32
|
+
when :date, Date
|
33
|
+
to_date(value)
|
34
|
+
|
35
|
+
when :float, Float
|
36
|
+
to_float(value)
|
37
|
+
|
38
|
+
when :bool, :boolean
|
39
|
+
to_boolean(value)
|
40
|
+
|
41
|
+
when :datetime, :date_time, DateTime
|
42
|
+
to_datetime(value)
|
43
|
+
|
44
|
+
else
|
45
|
+
Helpers.duplicate(value)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_date(string)
|
50
|
+
return string if string.is_a?(Date)
|
51
|
+
|
52
|
+
Date.parse(string) rescue nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_datetime(string)
|
56
|
+
return string if string.is_a?(DateTime)
|
57
|
+
|
58
|
+
DateTime.parse(string) rescue nil
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_boolean(string)
|
62
|
+
value = string.to_s.downcase
|
63
|
+
|
64
|
+
['1', 'true'].include?(value) ? true : ['0', 'false'].include?(value) ? false : nil
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_int(string)
|
68
|
+
return string if string.is_a?(Fixnum)
|
69
|
+
|
70
|
+
to_float(string).to_i
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_float(string)
|
74
|
+
return string if string.is_a?(Float)
|
75
|
+
|
76
|
+
return 0 if string.nil? || !(string.is_a?(String) || string.is_a?(Fixnum))
|
77
|
+
|
78
|
+
value = string.to_s.gsub(',', '.').scan(/-*\d+[.]*\d*/).flatten.map(&:to_f).first
|
79
|
+
|
80
|
+
value.nil? ? 0 : value
|
81
|
+
end
|
82
|
+
|
83
|
+
def new_unknown_hash(hash, unknown_hash_class, parent_object)
|
84
|
+
if unknown_hash_class == :none
|
85
|
+
hash
|
86
|
+
else
|
87
|
+
unknown_hash_class.new(cast_params(hash, unknown_hash_class, parent_object))
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
private ################### PRIVATE #####################
|
93
|
+
|
94
|
+
def cast_params(attributes, unknown_hash_class, parent_object)
|
95
|
+
hash = {}
|
96
|
+
|
97
|
+
attributes.each do |key, value|
|
98
|
+
hash[key] = cast_to_type(key, value, parent_object)
|
99
|
+
end
|
100
|
+
|
101
|
+
hash
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module SmoothOperator
|
2
|
+
module Attributes
|
3
|
+
|
4
|
+
class Dirty < Base
|
5
|
+
|
6
|
+
attr_reader :original_name, :original_value, :first_value, :value
|
7
|
+
|
8
|
+
def initialize(name, value, parent_object)
|
9
|
+
@original_name, @original_value = name, value
|
10
|
+
|
11
|
+
@first_value = set_value(value, parent_object)
|
12
|
+
end
|
13
|
+
|
14
|
+
def set_value(new_value, parent_object)
|
15
|
+
@value = cast_to_type(original_name, new_value, parent_object)
|
16
|
+
end
|
17
|
+
|
18
|
+
def changed?
|
19
|
+
@first_value != @value
|
20
|
+
end
|
21
|
+
|
22
|
+
def was
|
23
|
+
@first_value
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module SmoothOperator
|
2
|
+
|
3
|
+
module Delegation
|
4
|
+
|
5
|
+
def respond_to?(method)
|
6
|
+
if known_attribute?(method)
|
7
|
+
true
|
8
|
+
else
|
9
|
+
self.class.reflect_on_association(method) ? true : super
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_missing(method, *args, &block)
|
14
|
+
method_type, method_name = *parse_method(method)
|
15
|
+
|
16
|
+
result = case method_type
|
17
|
+
when :was
|
18
|
+
get_internal_data(method_name, :was)
|
19
|
+
when :changed
|
20
|
+
get_internal_data(method_name, :changed?)
|
21
|
+
when :setter
|
22
|
+
return push_to_internal_data(method_name, args.first)
|
23
|
+
else
|
24
|
+
if Helpers.safe_call(self.class, :reflect_on_association, method)
|
25
|
+
return get_relation(method_name)
|
26
|
+
elsif !self.class.strict_behaviour || known_attribute?(method_name)
|
27
|
+
return get_internal_data(method_name)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
result.nil? ? super : result
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
protected #################### PROTECTED ################
|
36
|
+
|
37
|
+
def parse_method(method)
|
38
|
+
method = method.to_s
|
39
|
+
|
40
|
+
if method?(method, /=$/)
|
41
|
+
[:setter, method[0..-2]]
|
42
|
+
elsif method?(method, /_was$/)
|
43
|
+
[:was, method[0..-5]]
|
44
|
+
elsif method?(method, /_changed\?$/)
|
45
|
+
[:changed, method[0..-10]]
|
46
|
+
else
|
47
|
+
[nil, method]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
private #################### PRIVATE ################
|
53
|
+
|
54
|
+
def method?(method, regex)
|
55
|
+
!! ((method.to_s) =~ regex)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'smooth_operator/array_with_meta_data'
|
2
|
+
|
3
|
+
module SmoothOperator
|
4
|
+
|
5
|
+
module FinderMethods
|
6
|
+
|
7
|
+
def find(relative_path, data = {}, options = {})
|
8
|
+
relative_path = '' if relative_path == :all
|
9
|
+
|
10
|
+
get(relative_path, data, options) do |remote_call|
|
11
|
+
remote_call.object = build_object(remote_call.parsed_response, options) if remote_call.ok?
|
12
|
+
|
13
|
+
block_given? ? yield(remote_call) : remote_call
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
protected #################### PROTECTED ##################
|
19
|
+
|
20
|
+
def build_object(parsed_response, options, from_array = false)
|
21
|
+
if parsed_response.is_a?(Array)
|
22
|
+
parsed_response.map { |array_entry| build_object(array_entry, options, true) }
|
23
|
+
elsif parsed_response.is_a?(Hash)
|
24
|
+
if parsed_response.include?(object_class.resources_name) && !from_array
|
25
|
+
ArrayWithMetaData.new(parsed_response, object_class)
|
26
|
+
else
|
27
|
+
object_class.new(parsed_response, from_server: true)
|
28
|
+
end
|
29
|
+
else
|
30
|
+
parsed_response
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
private #################### PRIVATE ##################
|
36
|
+
|
37
|
+
def object_class
|
38
|
+
@object_class ||= self.class == Class ? self : self.class
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module SmoothOperator
|
2
|
+
|
3
|
+
module Helpers
|
4
|
+
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def safe_call(object, method, *args)
|
8
|
+
if object.respond_to?(method)
|
9
|
+
object.send(method, *args)
|
10
|
+
else
|
11
|
+
false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def super_method(object, method_name, *args)
|
16
|
+
object.superclass.send(method_name, *args) if object.superclass.respond_to?(method_name)
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_instance_variable(object, variable, default_value)
|
20
|
+
instance_var = object.instance_variable_get("@#{variable}")
|
21
|
+
|
22
|
+
return instance_var unless instance_var.nil?
|
23
|
+
|
24
|
+
instance_var = (super_method(object, variable) || default_value)
|
25
|
+
|
26
|
+
if instance_var.class == Class
|
27
|
+
object.instance_variable_set("@#{variable}", instance_var)
|
28
|
+
else
|
29
|
+
object.instance_variable_set("@#{variable}", duplicate(instance_var))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def stringify_keys(hash)
|
34
|
+
stringified_hash = {}
|
35
|
+
hash.keys.each { |key| stringified_hash[key.to_s] = hash[key] }
|
36
|
+
stringified_hash
|
37
|
+
end
|
38
|
+
|
39
|
+
def symbolyze_keys(hash)
|
40
|
+
hash.keys.reduce({}) do |cloned_hash, key|
|
41
|
+
cloned_hash[key.to_sym] = hash[key]
|
42
|
+
cloned_hash
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def plural?(string)
|
47
|
+
string = string.to_s
|
48
|
+
string == string.pluralize
|
49
|
+
end
|
50
|
+
|
51
|
+
def duplicate(object)
|
52
|
+
object.dup rescue object
|
53
|
+
end
|
54
|
+
|
55
|
+
def blank?(object)
|
56
|
+
case object
|
57
|
+
when String
|
58
|
+
object.to_s == ''
|
59
|
+
when Array
|
60
|
+
object.empty?
|
61
|
+
else
|
62
|
+
object.nil?
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def present?(object)
|
67
|
+
!blank?(object)
|
68
|
+
end
|
69
|
+
|
70
|
+
def absolute_path?(string)
|
71
|
+
present?(string) && string[0] == '/'
|
72
|
+
end
|
73
|
+
|
74
|
+
def remove_initial_slash(string)
|
75
|
+
string[1..-1]
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module SmoothOperator
|
2
|
+
module ModelSchema
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
def known_attribute?(attribute)
|
9
|
+
known_attributes.include?(attribute.to_s)
|
10
|
+
end
|
11
|
+
|
12
|
+
def known_by_schema?(attribute)
|
13
|
+
self.class.internal_structure.include?(attribute.to_s)
|
14
|
+
end
|
15
|
+
|
16
|
+
def known_attributes
|
17
|
+
@known_attributes ||= self.class.known_attributes.dup
|
18
|
+
end
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
|
22
|
+
def resources_name(default_bypass = nil)
|
23
|
+
return @resources_name if defined?(@resources_name)
|
24
|
+
|
25
|
+
(Helpers.super_method(self, :resources_name, true) || (default_bypass ? nil : self.resource_name.pluralize))
|
26
|
+
end
|
27
|
+
attr_writer :resources_name
|
28
|
+
|
29
|
+
def resource_name(default_bypass = nil)
|
30
|
+
return @resource_name if defined?(@resource_name)
|
31
|
+
|
32
|
+
(Helpers.super_method(self, :resource_name, true) || (default_bypass ? nil : self.model_name.to_s.underscore))
|
33
|
+
end
|
34
|
+
attr_writer :resource_name
|
35
|
+
|
36
|
+
def schema(structure)
|
37
|
+
internal_structure.merge! Helpers.stringify_keys(structure)
|
38
|
+
|
39
|
+
known_attributes.merge internal_structure.keys
|
40
|
+
end
|
41
|
+
|
42
|
+
def internal_structure
|
43
|
+
Helpers.get_instance_variable(self, :internal_structure, { "errors" => nil })
|
44
|
+
end
|
45
|
+
|
46
|
+
def known_attributes
|
47
|
+
Helpers.get_instance_variable(self, :known_attributes, Set.new)
|
48
|
+
end
|
49
|
+
|
50
|
+
def model_name
|
51
|
+
return '' if @_model_name == :none
|
52
|
+
|
53
|
+
if defined? ActiveModel
|
54
|
+
rails_model_name_method
|
55
|
+
else
|
56
|
+
@_model_name ||= name.split('::').last.underscore.capitalize
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def model_name=(name)
|
61
|
+
@_model_name = name
|
62
|
+
end
|
63
|
+
|
64
|
+
protected ############## PROTECTED #############
|
65
|
+
|
66
|
+
def rails_model_name_method
|
67
|
+
@model_name ||= begin
|
68
|
+
namespace ||= self.parents.detect do |n|
|
69
|
+
n.respond_to?(:use_relative_model_naming?) && n.use_relative_model_naming?
|
70
|
+
end
|
71
|
+
|
72
|
+
ActiveModel::Name.new(self, namespace, @_model_name).tap do |model_name|
|
73
|
+
def model_name.human(options = {}); @klass.send(:_translate, "models.#{i18n_key}", options); end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "smooth_operator/delegation"
|
2
|
+
require "smooth_operator/validations"
|
3
|
+
require "smooth_operator/model_schema"
|
4
|
+
require "smooth_operator/serialization"
|
5
|
+
require "smooth_operator/attribute_methods"
|
6
|
+
require "smooth_operator/attribute_assignment"
|
7
|
+
|
8
|
+
module SmoothOperator
|
9
|
+
module OpenStruct
|
10
|
+
|
11
|
+
class Base
|
12
|
+
|
13
|
+
include Delegation
|
14
|
+
include Validations
|
15
|
+
include ModelSchema
|
16
|
+
include Serialization
|
17
|
+
include AttributeMethods
|
18
|
+
include AttributeAssignment
|
19
|
+
|
20
|
+
def self.strict_behaviour=(value)
|
21
|
+
@strict_behaviour = value
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.strict_behaviour
|
25
|
+
Helpers.get_instance_variable(self, :strict_behaviour, false)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
class Dirty < Base
|
31
|
+
|
32
|
+
dirty_attributes
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require "smooth_operator/remote_call/base"
|
2
|
+
require "smooth_operator/operators/faraday"
|
3
|
+
require "smooth_operator/operators/typhoeus"
|
4
|
+
require "smooth_operator/remote_call/errors/timeout"
|
5
|
+
require "smooth_operator/remote_call/errors/connection_failed"
|
6
|
+
|
7
|
+
module SmoothOperator
|
8
|
+
|
9
|
+
module Operator
|
10
|
+
|
11
|
+
def make_the_call(http_verb, relative_path = '', data = {}, options = {})
|
12
|
+
options ||= {}
|
13
|
+
|
14
|
+
relative_path = resource_path(relative_path)
|
15
|
+
|
16
|
+
if !parent_object.nil? && options[:ignore_parent] != true
|
17
|
+
options[:resources_name] ||= "#{parent_object.class.resources_name}/#{parent_object.get_primary_key}/#{self.class.resources_name}"
|
18
|
+
end
|
19
|
+
|
20
|
+
self.class.make_the_call(http_verb, relative_path, data, options) do |remote_call|
|
21
|
+
yield(remote_call)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
protected ######################## PROTECTED ###################
|
26
|
+
|
27
|
+
def resource_path(relative_path)
|
28
|
+
if Helpers.absolute_path?(relative_path)
|
29
|
+
Helpers.remove_initial_slash(relative_path)
|
30
|
+
elsif persisted?
|
31
|
+
Helpers.present?(relative_path) ? "#{get_primary_key}/#{relative_path}" : get_primary_key.to_s
|
32
|
+
else
|
33
|
+
relative_path
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
########################### MODULES BELLOW ###############################
|
39
|
+
|
40
|
+
module HttpMethods
|
41
|
+
|
42
|
+
HTTP_VERBS = %w[get post put patch delete]
|
43
|
+
|
44
|
+
HTTP_VERBS.each do |method|
|
45
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
46
|
+
def #{method}(relative_path = '', params = {}, options = {})
|
47
|
+
make_the_call(:#{method}, relative_path, params, options) do |remote_call|
|
48
|
+
block_given? ? yield(remote_call) : remote_call
|
49
|
+
end
|
50
|
+
end
|
51
|
+
RUBY
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
module ClassMethods
|
57
|
+
|
58
|
+
OPTIONS = [:endpoint, :endpoint_user, :endpoint_pass, :timeout]
|
59
|
+
|
60
|
+
OPTIONS.each do |option|
|
61
|
+
define_method(option) { Helpers.get_instance_variable(self, option, '') }
|
62
|
+
end
|
63
|
+
|
64
|
+
attr_writer *OPTIONS
|
65
|
+
|
66
|
+
def headers
|
67
|
+
Helpers.get_instance_variable(self, :headers, {})
|
68
|
+
end
|
69
|
+
|
70
|
+
attr_writer :headers
|
71
|
+
|
72
|
+
|
73
|
+
def make_the_call(http_verb, relative_path = '', data = {}, options = {})
|
74
|
+
operator_args = operator_method_args(http_verb, relative_path, data, options)
|
75
|
+
|
76
|
+
if Helpers.present?(operator_args[4][:hydra])
|
77
|
+
operator_call = Operators::Typhoeus
|
78
|
+
else
|
79
|
+
operator_call = Operators::Faraday
|
80
|
+
end
|
81
|
+
|
82
|
+
operator_call.make_the_call(*operator_args) do |remote_call|
|
83
|
+
block_given? ? yield(remote_call) : remote_call
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def query_string(params)
|
88
|
+
params
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
protected #################### PROTECTED ##################
|
93
|
+
|
94
|
+
def operator_method_args(http_verb, relative_path, data, options)
|
95
|
+
options = populate_options(options)
|
96
|
+
|
97
|
+
[http_verb, resource_path(relative_path, options), *strip_params(http_verb, data), options]
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
private #################### PRIVATE ##################
|
102
|
+
|
103
|
+
def populate_options(options)
|
104
|
+
options ||= {}
|
105
|
+
|
106
|
+
OPTIONS.each { |option| options[option] ||= send(option) }
|
107
|
+
|
108
|
+
options[:headers] = headers.merge(options[:headers] || {})
|
109
|
+
|
110
|
+
options
|
111
|
+
end
|
112
|
+
|
113
|
+
def resource_path(relative_path, options)
|
114
|
+
_resources_name = options[:resources_name] || self.resources_name
|
115
|
+
|
116
|
+
if Helpers.present?(_resources_name)
|
117
|
+
Helpers.present?(relative_path) ? "#{_resources_name}/#{relative_path}" : _resources_name
|
118
|
+
else
|
119
|
+
relative_path.to_s
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def strip_params(http_verb, data)
|
124
|
+
data ||= {}
|
125
|
+
|
126
|
+
if [:get, :head, :delete].include?(http_verb)
|
127
|
+
[query_string(data), nil]
|
128
|
+
else
|
129
|
+
[query_string({}), data]
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
include HttpMethods
|
137
|
+
|
138
|
+
def self.included(base)
|
139
|
+
base.extend(ClassMethods)
|
140
|
+
base.extend(HttpMethods)
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'typhoeus/adapters/faraday'
|
3
|
+
require "smooth_operator/remote_call/faraday"
|
4
|
+
|
5
|
+
module SmoothOperator
|
6
|
+
|
7
|
+
module Operators
|
8
|
+
|
9
|
+
module Faraday
|
10
|
+
|
11
|
+
extend self
|
12
|
+
|
13
|
+
# def generate_parallel_connection
|
14
|
+
# generate_connection(:typhoeus)
|
15
|
+
# end
|
16
|
+
|
17
|
+
def generate_connection(adapter = nil, options = nil)
|
18
|
+
adapter ||= :net_http
|
19
|
+
|
20
|
+
::Faraday.new(url: options[:endpoint]) do |builder|
|
21
|
+
builder.options[:timeout] = options[:timeout].to_i unless Helpers.blank?(options[:timeout])
|
22
|
+
builder.request :url_encoded
|
23
|
+
builder.adapter adapter
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def make_the_call(http_verb, resource_path, params, body, options)
|
28
|
+
connection, request_options, options = strip_options(options)
|
29
|
+
|
30
|
+
remote_call = begin
|
31
|
+
set_basic_authentication(connection, options)
|
32
|
+
|
33
|
+
response = connection.send(http_verb, resource_path) do |request|
|
34
|
+
request_configuration(request, request_options, options, params, body)
|
35
|
+
end
|
36
|
+
|
37
|
+
RemoteCall::Faraday.new(response)
|
38
|
+
rescue ::Faraday::Error::ConnectionFailed
|
39
|
+
RemoteCall::Errors::ConnectionFailed.new(response)
|
40
|
+
rescue ::Faraday::Error::TimeoutError
|
41
|
+
RemoteCall::Errors::Timeout.new(response)
|
42
|
+
end
|
43
|
+
|
44
|
+
block_given? ? yield(remote_call) : remote_call
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
protected ################ PROTECTED ################
|
49
|
+
|
50
|
+
def strip_options(options)
|
51
|
+
request_options = options.delete(:request_options) || {}
|
52
|
+
|
53
|
+
connection = options.delete(:connection) || generate_connection(nil, options)
|
54
|
+
|
55
|
+
[connection, request_options, options]
|
56
|
+
end
|
57
|
+
|
58
|
+
def set_basic_authentication(connection, options)
|
59
|
+
connection.basic_auth(options[:endpoint_user], options[:endpoint_pass]) if Helpers.present?(options[:endpoint_user])
|
60
|
+
end
|
61
|
+
|
62
|
+
def request_configuration(request, request_options, options, params, body)
|
63
|
+
request_options.each { |key, value| request.options.send("#{key}=", value) }
|
64
|
+
|
65
|
+
options[:headers].each { |key, value| request.headers[key] = value }
|
66
|
+
|
67
|
+
params.each { |key, value| request.params[key] = value }
|
68
|
+
|
69
|
+
request.body = body
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|