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.
- 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
@@ -1,79 +0,0 @@
|
|
1
|
-
require "smooth_operator/associations/reflection"
|
2
|
-
|
3
|
-
module SmoothOperator
|
4
|
-
module Associations
|
5
|
-
class AssociationReflection < Reflection
|
6
|
-
|
7
|
-
attr_reader :related_reflection, :macro
|
8
|
-
|
9
|
-
def initialize(association, related_reflection, options)
|
10
|
-
super(association, options)
|
11
|
-
|
12
|
-
@related_reflection, @macro = related_reflection, options[:macro]
|
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
|
-
def collection?
|
60
|
-
has_many?
|
61
|
-
end
|
62
|
-
|
63
|
-
def rails_serialization?
|
64
|
-
options[:rails_serialization] == true
|
65
|
-
end
|
66
|
-
|
67
|
-
private ################################# private
|
68
|
-
|
69
|
-
def foreign_key_default
|
70
|
-
if has_many? || has_one?
|
71
|
-
"#{related_reflection.single_name}_id"
|
72
|
-
elsif belongs_to?
|
73
|
-
"#{single_name}_id"
|
74
|
-
end.to_sym
|
75
|
-
end
|
76
|
-
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
module SmoothOperator
|
2
|
-
module Associations
|
3
|
-
class HasManyRelation < SimpleDelegator
|
4
|
-
|
5
|
-
attr_reader :object, :association
|
6
|
-
|
7
|
-
def initialize(object, association)
|
8
|
-
@object, @association = object, association
|
9
|
-
end
|
10
|
-
|
11
|
-
def reload
|
12
|
-
"TODO"
|
13
|
-
end
|
14
|
-
|
15
|
-
def new(attributes = {})
|
16
|
-
object.class.reflect_on_association(association).klass.new(attributes)
|
17
|
-
end
|
18
|
-
|
19
|
-
def build(attributes = {})
|
20
|
-
new_array, new_array_entry = get_array, new(attributes)
|
21
|
-
|
22
|
-
new_array.push new_array_entry
|
23
|
-
|
24
|
-
object.send("#{association}=", new_array)
|
25
|
-
|
26
|
-
new_array_entry
|
27
|
-
end
|
28
|
-
|
29
|
-
undef :is_a?
|
30
|
-
|
31
|
-
protected ############### PROTECTED ###############
|
32
|
-
|
33
|
-
def get_array
|
34
|
-
data = object.internal_data_get(association.to_s)
|
35
|
-
|
36
|
-
data.nil? ? [] : [*data]
|
37
|
-
end
|
38
|
-
|
39
|
-
def refresh
|
40
|
-
__setobj__ get_array
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
module SmoothOperator
|
2
|
-
module Associations
|
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 rescue OpenStruct
|
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
|
@@ -1,21 +0,0 @@
|
|
1
|
-
module SmoothOperator
|
2
|
-
class CookieJar < Hash
|
3
|
-
|
4
|
-
def to_s
|
5
|
-
self.map { |key, value| "#{key}=#{value}"}.join("; ")
|
6
|
-
end
|
7
|
-
|
8
|
-
def parse(*cookie_strings)
|
9
|
-
cookie_strings.each do |cookie_string|
|
10
|
-
next unless cookie_string.is_a?(String)
|
11
|
-
|
12
|
-
key, value = cookie_string.split('; ').first.split('=', 2)
|
13
|
-
|
14
|
-
self[key] = value
|
15
|
-
end
|
16
|
-
|
17
|
-
self
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
21
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module SmoothOperator
|
2
|
-
module HttpMethods
|
3
|
-
|
4
|
-
HTTP_VERBS = %w[get post put patch delete]
|
5
|
-
|
6
|
-
HTTP_VERBS.each do |method|
|
7
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
8
|
-
def #{method}(relative_path = '', params = {}, options = {})
|
9
|
-
make_the_call(:#{method}, relative_path, params, options) do |remote_call|
|
10
|
-
block_given? ? yield(remote_call) : remote_call
|
11
|
-
end
|
12
|
-
end
|
13
|
-
RUBY
|
14
|
-
end
|
15
|
-
|
16
|
-
end
|
17
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
require 'smooth_operator/type_casting'
|
2
|
-
|
3
|
-
module SmoothOperator
|
4
|
-
module InternalData
|
5
|
-
|
6
|
-
def internal_data
|
7
|
-
@internal_data ||= {}
|
8
|
-
end
|
9
|
-
|
10
|
-
def known_attributes
|
11
|
-
return @known_attributes if defined?(@known_attributes)
|
12
|
-
|
13
|
-
schema_attributes = if self.class.respond_to?(:internal_structure)
|
14
|
-
self.class.internal_structure.keys
|
15
|
-
else
|
16
|
-
[]
|
17
|
-
end
|
18
|
-
|
19
|
-
@known_attributes = Set.new(schema_attributes)
|
20
|
-
end
|
21
|
-
|
22
|
-
def known_attribute?(attribute)
|
23
|
-
known_attributes.include?(attribute.to_s)
|
24
|
-
end
|
25
|
-
|
26
|
-
def internal_data_get(attribute_name)
|
27
|
-
internal_data[attribute_name]
|
28
|
-
end
|
29
|
-
|
30
|
-
def internal_data_push(attribute_name, attribute_value)
|
31
|
-
attribute_name = attribute_name.to_s
|
32
|
-
|
33
|
-
known_attributes.add attribute_name
|
34
|
-
|
35
|
-
internal_data[attribute_name] = TypeCasting.cast_to_type(attribute_name, attribute_value, self)
|
36
|
-
|
37
|
-
if self.class.respond_to?(:smooth_operator?)
|
38
|
-
marked_for_destruction?(attribute_value) if attribute_name == self.class.destroy_key
|
39
|
-
|
40
|
-
new_record?(true) if attribute_name == self.class.primary_key
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
end
|
45
|
-
end
|
@@ -1,75 +0,0 @@
|
|
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
|
-
ConnectionWrapper.new(::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)).connection
|
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
|
@@ -1,87 +0,0 @@
|
|
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 generate_parallel_connection
|
13
|
-
generate_connection
|
14
|
-
end
|
15
|
-
|
16
|
-
def generate_connection(adapter = nil, options = nil)
|
17
|
-
ConnectionWrapper.new(::Typhoeus::Hydra::hydra)
|
18
|
-
end
|
19
|
-
|
20
|
-
def make_the_call(http_verb, resource_path, params, body, options)
|
21
|
-
request = ::Typhoeus::Request.new *typhoeus_request_args(http_verb, resource_path, params, body, options)
|
22
|
-
|
23
|
-
hydra = (options[:connection] || generate_connection).connection
|
24
|
-
|
25
|
-
request_result = nil
|
26
|
-
|
27
|
-
hydra.queue(request)
|
28
|
-
|
29
|
-
request.on_complete do |typhoeus_response|
|
30
|
-
remote_call = remote_call(typhoeus_response)
|
31
|
-
|
32
|
-
if block_given?
|
33
|
-
request_result = yield(remote_call)
|
34
|
-
else
|
35
|
-
request_result = remote_call
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
hydra.run if Helpers.blank?(options[:connection])
|
40
|
-
|
41
|
-
request_result
|
42
|
-
end
|
43
|
-
|
44
|
-
protected ################ PROTECTED ################
|
45
|
-
|
46
|
-
def typhoeus_request_args(http_verb, relative_path, params, body, options)
|
47
|
-
[url(options, relative_path), build_typhoeus_options(http_verb, params, body, options)]
|
48
|
-
end
|
49
|
-
|
50
|
-
def remote_call(typhoeus_response)
|
51
|
-
if typhoeus_response.return_code == :couldnt_connect
|
52
|
-
RemoteCall::Errors::ConnectionFailed
|
53
|
-
elsif typhoeus_response.timed_out?
|
54
|
-
RemoteCall::Errors::Timeout
|
55
|
-
else
|
56
|
-
RemoteCall::Typhoeus
|
57
|
-
end.new(typhoeus_response)
|
58
|
-
end
|
59
|
-
|
60
|
-
private ################### PRIVATE ###############
|
61
|
-
|
62
|
-
def build_typhoeus_options(http_verb, params, body, options)
|
63
|
-
typhoeus_options = { method: http_verb, headers: options[:headers].merge({ "Content-type" => "application/x-www-form-urlencoded" }) }
|
64
|
-
|
65
|
-
typhoeus_options[:timeout] = options[:timeout] if Helpers.present?(options[:timeout])
|
66
|
-
|
67
|
-
typhoeus_options[:body] = body if Helpers.present?(body)
|
68
|
-
|
69
|
-
typhoeus_options[:params] = params if Helpers.present?(params)
|
70
|
-
|
71
|
-
typhoeus_options[:userpwd] = "#{options[:endpoint_user]}:#{options[:endpoint_pass]}" if Helpers.present?(options[:endpoint_user])
|
72
|
-
|
73
|
-
typhoeus_options
|
74
|
-
end
|
75
|
-
|
76
|
-
def url(options, relative_path)
|
77
|
-
url = options[:endpoint]
|
78
|
-
|
79
|
-
slice = url[-1] != '/' ? '/' : ''
|
80
|
-
|
81
|
-
url = "#{url}#{slice}#{relative_path}" if Helpers.present?(relative_path)
|
82
|
-
end
|
83
|
-
|
84
|
-
end
|
85
|
-
|
86
|
-
end
|
87
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
module SmoothOperator
|
2
|
-
module Options
|
3
|
-
|
4
|
-
def get_option(option, default, *args)
|
5
|
-
return default unless config_options.include?(option)
|
6
|
-
|
7
|
-
_option = config_options[option]
|
8
|
-
|
9
|
-
case _option
|
10
|
-
when Symbol
|
11
|
-
respond_to?(_option) ? send(_option, *args) : _option
|
12
|
-
when Proc
|
13
|
-
_option.call(*args)
|
14
|
-
else
|
15
|
-
_option
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def config_options
|
20
|
-
Helpers.get_instance_variable(self, :config_options, {})
|
21
|
-
end
|
22
|
-
|
23
|
-
def smooth_operator_options(options = {})
|
24
|
-
config_options.merge!(options)
|
25
|
-
end
|
26
|
-
|
27
|
-
alias_method :options, :smooth_operator_options
|
28
|
-
|
29
|
-
end
|
30
|
-
end
|