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