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
@@ -1,35 +1,36 @@
|
|
1
1
|
module SmoothOperator
|
2
|
-
class ArrayWithMetaData < SimpleDelegator
|
3
2
|
|
4
|
-
|
3
|
+
class ArrayWithMetaData < OpenStruct
|
4
|
+
|
5
|
+
extend Forwardable
|
5
6
|
|
6
|
-
|
7
|
-
resources_name = object_class.resources_name
|
7
|
+
include Enumerable
|
8
8
|
|
9
|
-
|
10
|
-
object_class.new(array_entry)
|
11
|
-
end
|
9
|
+
attr_reader :meta_data, :internal_array, :table_name, :object_class
|
12
10
|
|
13
|
-
|
11
|
+
def_delegators :internal_array, :length, :<<
|
14
12
|
|
15
|
-
|
13
|
+
def initialize(attributes, table_name, object_class)
|
14
|
+
_attributes = attributes.dup
|
16
15
|
|
17
|
-
|
16
|
+
@table_name, @object_class = table_name, object_class
|
18
17
|
|
19
|
-
|
18
|
+
@internal_array = [*_attributes[table_name]].map { |array_entry| object_class.new(array_entry) }
|
19
|
+
_attributes.delete(table_name)
|
20
|
+
|
21
|
+
@meta_data = _attributes
|
20
22
|
end
|
21
23
|
|
22
|
-
protected ############# PROTECTED ###################
|
23
24
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
end
|
25
|
+
def each
|
26
|
+
internal_array.each { |array_entry| yield array_entry }
|
27
|
+
end
|
28
|
+
|
29
|
+
def method_missing(method, *args, &block)
|
30
|
+
_method = method.to_s
|
31
|
+
meta_data.include?(_method) ? meta_data[_method] : super
|
32
32
|
end
|
33
33
|
|
34
34
|
end
|
35
|
+
|
35
36
|
end
|
@@ -1,55 +1,78 @@
|
|
1
|
+
require 'smooth_operator/internal_attribute'
|
2
|
+
|
1
3
|
module SmoothOperator
|
4
|
+
|
2
5
|
module AttributeAssignment
|
3
6
|
|
4
|
-
def
|
5
|
-
|
7
|
+
def self.included(base)
|
8
|
+
base.extend(ClassMethods)
|
9
|
+
end
|
6
10
|
|
7
|
-
|
11
|
+
module ClassMethods
|
8
12
|
|
9
|
-
|
13
|
+
attr_accessor :turn_unknown_hash_to_open_struct
|
10
14
|
|
11
|
-
|
12
|
-
|
15
|
+
def attributes_white_list
|
16
|
+
Helpers.get_instance_variable(self, :attributes_white_list, Set.new)
|
17
|
+
end
|
13
18
|
|
14
|
-
|
19
|
+
def attributes_black_list
|
20
|
+
Helpers.get_instance_variable(self, :attributes_black_list, Set.new)
|
21
|
+
end
|
15
22
|
|
16
|
-
|
17
|
-
|
23
|
+
def attributes_white_list_add(*getters)
|
24
|
+
attributes_white_list.merge getters.map(&:to_s)
|
25
|
+
end
|
18
26
|
|
19
|
-
|
27
|
+
def attributes_black_list_add(*getters)
|
28
|
+
attributes_black_list.merge getters.map(&:to_s)
|
29
|
+
end
|
20
30
|
|
21
|
-
|
31
|
+
end
|
22
32
|
|
23
|
-
@_options.merge!(options) if options.is_a? Hash
|
24
33
|
|
25
|
-
|
26
|
-
|
34
|
+
def initialize(attributes = {})
|
35
|
+
before_initialize(attributes)
|
27
36
|
|
28
|
-
|
29
|
-
end
|
30
|
-
end
|
37
|
+
assign_attributes attributes
|
31
38
|
|
32
|
-
|
39
|
+
after_initialize(attributes)
|
40
|
+
end
|
33
41
|
|
34
|
-
def
|
42
|
+
def assign_attributes(attributes = {})
|
35
43
|
return nil unless attributes.is_a?(Hash)
|
44
|
+
|
45
|
+
attributes.each { |name, value| push_to_internal_data(name, value) }
|
46
|
+
end
|
47
|
+
|
48
|
+
def internal_data
|
49
|
+
@internal_data ||= {}
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_internal_data(field, method = :value)
|
53
|
+
internal_data[field].nil? ? nil : internal_data[field].send(method)
|
54
|
+
end
|
36
55
|
|
37
|
-
|
56
|
+
def push_to_internal_data(attribute_name, attribute_value)
|
57
|
+
attribute_name = attribute_name.to_s
|
38
58
|
|
39
|
-
|
40
|
-
|
41
|
-
|
59
|
+
return nil unless allowed_attribute(attribute_name)
|
60
|
+
|
61
|
+
known_attributes.add attribute_name
|
62
|
+
|
63
|
+
if internal_data[attribute_name].nil?
|
64
|
+
internal_data[attribute_name] = InternalAttribute.new(attribute_name, attribute_value, internal_structure[attribute_name], self.class.turn_unknown_hash_to_open_struct)
|
42
65
|
else
|
43
|
-
|
44
|
-
@_meta_data = {}
|
66
|
+
internal_data[attribute_name].set_value(attribute_value)
|
45
67
|
end
|
46
|
-
|
47
|
-
attributes
|
48
68
|
end
|
49
69
|
|
50
|
-
|
70
|
+
|
71
|
+
protected #################### PROTECTED METHODS DOWN BELOW ######################
|
72
|
+
|
73
|
+
def before_initialize(attributes); end
|
51
74
|
|
52
|
-
def after_initialize(attributes
|
75
|
+
def after_initialize(attributes); end
|
53
76
|
|
54
77
|
def allowed_attribute(attribute)
|
55
78
|
if !self.class.attributes_white_list.empty?
|
@@ -61,33 +84,6 @@ module SmoothOperator
|
|
61
84
|
end
|
62
85
|
end
|
63
86
|
|
64
|
-
def self.included(base)
|
65
|
-
base.extend(ClassMethods)
|
66
|
-
end
|
67
|
-
|
68
|
-
module ClassMethods
|
69
|
-
|
70
|
-
def unknown_hash_class
|
71
|
-
get_option :unknown_hash_class, ::OpenStruct
|
72
|
-
end
|
73
|
-
|
74
|
-
def attributes_white_list
|
75
|
-
Helpers.get_instance_variable(self, :attributes_white_list, Set.new)
|
76
|
-
end
|
77
|
-
|
78
|
-
def attributes_black_list
|
79
|
-
Helpers.get_instance_variable(self, :attributes_black_list, Set.new)
|
80
|
-
end
|
81
|
-
|
82
|
-
def attributes_white_list_add(*getters)
|
83
|
-
attributes_white_list.merge getters.map(&:to_s)
|
84
|
-
end
|
85
|
-
|
86
|
-
def attributes_black_list_add(*getters)
|
87
|
-
attributes_black_list.merge getters.map(&:to_s)
|
88
|
-
end
|
89
|
-
|
90
|
-
end
|
91
|
-
|
92
87
|
end
|
88
|
+
|
93
89
|
end
|
@@ -1,33 +1,52 @@
|
|
1
1
|
module SmoothOperator
|
2
|
+
|
2
3
|
module Delegation
|
3
4
|
|
4
|
-
def respond_to?(method
|
5
|
-
|
5
|
+
def respond_to?(method)
|
6
|
+
known_attributes.include?(method.to_s) ? true : super
|
6
7
|
end
|
7
8
|
|
8
9
|
def method_missing(method, *args, &block)
|
9
|
-
method_name = method
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
method_type, method_name = *parse_method(method)
|
11
|
+
|
12
|
+
result = case method_type
|
13
|
+
when :was
|
14
|
+
get_internal_data(method_name, :was)
|
15
|
+
when :changed
|
16
|
+
get_internal_data(method_name, :changed?)
|
17
|
+
when :setter
|
18
|
+
return push_to_internal_data(method_name, args.first)
|
15
19
|
else
|
16
|
-
|
20
|
+
return get_internal_data(method_name) if respond_to?(method_name)
|
17
21
|
end
|
18
|
-
end
|
19
22
|
|
20
|
-
|
21
|
-
base.extend(ClassMethods)
|
23
|
+
result.nil? ? super : result
|
22
24
|
end
|
23
25
|
|
24
|
-
module ClassMethods
|
25
26
|
|
26
|
-
|
27
|
-
|
27
|
+
protected #################### PROTECTED ################
|
28
|
+
|
29
|
+
def parse_method(method)
|
30
|
+
method = method.to_s
|
31
|
+
|
32
|
+
if method?(method, /=$/)
|
33
|
+
[:setter, method[0..-2]]
|
34
|
+
elsif method?(method, /_was$/)
|
35
|
+
[:was, method[0..-5]]
|
36
|
+
elsif method?(method, /_changed\?$/)
|
37
|
+
[:changed, method[0..-10]]
|
38
|
+
else
|
39
|
+
[nil, method]
|
28
40
|
end
|
41
|
+
end
|
42
|
+
|
29
43
|
|
44
|
+
private #################### PRIVATE ################
|
45
|
+
|
46
|
+
def method?(method, regex)
|
47
|
+
!! ((method.to_s) =~ regex)
|
30
48
|
end
|
31
49
|
|
32
50
|
end
|
51
|
+
|
33
52
|
end
|
@@ -1,52 +1,36 @@
|
|
1
1
|
require 'smooth_operator/array_with_meta_data'
|
2
2
|
|
3
3
|
module SmoothOperator
|
4
|
+
|
4
5
|
module FinderMethods
|
5
6
|
|
7
|
+
def all(data = {}, options = {})
|
8
|
+
find(:all, data, options)
|
9
|
+
end
|
10
|
+
|
6
11
|
def find(relative_path, data = {}, options = {})
|
7
12
|
relative_path = '' if relative_path == :all
|
8
13
|
|
9
|
-
get(relative_path, data, options) do |remote_call|
|
10
|
-
|
11
|
-
remote_call.object = HelperMethods
|
12
|
-
.build_object(self, remote_call.parsed_response, options)
|
13
|
-
end
|
14
|
-
|
15
|
-
block_given? ? yield(remote_call) : remote_call
|
14
|
+
get(relative_path, data, options).tap do |remote_call|
|
15
|
+
remote_call.object = build_object(remote_call.parsed_response, options)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
module HelperMethods
|
20
|
-
|
21
|
-
extend self
|
22
19
|
|
23
|
-
|
24
|
-
if parsed_response.is_a?(Array)
|
25
|
-
parse_array(parsed_response, object, options)
|
26
|
-
elsif parsed_response.is_a?(Hash)
|
27
|
-
parse_hash(object, parsed_response, options, from_array)
|
28
|
-
else
|
29
|
-
parsed_response
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def parse_array(parsed_response, object, options)
|
34
|
-
parsed_response.map do |array_entry|
|
35
|
-
build_object(object, array_entry, options, true)
|
36
|
-
end
|
37
|
-
end
|
20
|
+
protected #################### PROTECTED ##################
|
38
21
|
|
39
|
-
|
40
|
-
|
22
|
+
def build_object(parsed_response, options)
|
23
|
+
table_name = (options[:table_name] || self.table_name).to_s
|
41
24
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
25
|
+
if parsed_response.is_a?(Array)
|
26
|
+
parsed_response.map { |array_entry| build_object(array_entry, options) }
|
27
|
+
elsif parsed_response.is_a?(Hash)
|
28
|
+
parsed_response.include?(table_name) ? ArrayWithMetaData.new(parsed_response, table_name, self) : new(parsed_response)
|
29
|
+
else
|
30
|
+
parsed_response
|
47
31
|
end
|
48
|
-
|
49
32
|
end
|
50
33
|
|
51
34
|
end
|
35
|
+
|
52
36
|
end
|
@@ -3,23 +3,9 @@ module SmoothOperator
|
|
3
3
|
module Helpers
|
4
4
|
|
5
5
|
extend self
|
6
|
-
|
7
|
-
def generated_id
|
8
|
-
Time.now.to_f.to_s.split('.')[1]
|
9
|
-
end
|
10
|
-
|
11
|
-
def primary_key(object)
|
12
|
-
object.internal_data_get(object.class.primary_key)
|
13
|
-
end
|
14
|
-
|
15
|
-
def has_primary_key?(object)
|
16
|
-
blank? primary_key(object)
|
17
|
-
end
|
18
|
-
|
6
|
+
|
19
7
|
def super_method(object, method_name, *args)
|
20
|
-
if object.superclass.respond_to?(method_name)
|
21
|
-
object.superclass.send(method_name, *args)
|
22
|
-
end
|
8
|
+
object.superclass.send(method_name, *args) if object.superclass.respond_to?(method_name)
|
23
9
|
end
|
24
10
|
|
25
11
|
def get_instance_variable(object, variable, default_value)
|
@@ -27,12 +13,8 @@ module SmoothOperator
|
|
27
13
|
|
28
14
|
return instance_var unless instance_var.nil?
|
29
15
|
|
30
|
-
|
31
|
-
|
32
|
-
if instance_var.class == Class
|
16
|
+
(super_method(object, variable) || default_value).dup.tap do |instance_var|
|
33
17
|
object.instance_variable_set("@#{variable}", instance_var)
|
34
|
-
else
|
35
|
-
object.instance_variable_set("@#{variable}", duplicate(instance_var))
|
36
18
|
end
|
37
19
|
end
|
38
20
|
|
@@ -49,11 +31,6 @@ module SmoothOperator
|
|
49
31
|
end
|
50
32
|
end
|
51
33
|
|
52
|
-
def plural?(string)
|
53
|
-
string = string.to_s
|
54
|
-
string == string.pluralize
|
55
|
-
end
|
56
|
-
|
57
34
|
def duplicate(object)
|
58
35
|
object.dup rescue object
|
59
36
|
end
|
@@ -62,7 +39,7 @@ module SmoothOperator
|
|
62
39
|
case object
|
63
40
|
when String
|
64
41
|
object.to_s == ''
|
65
|
-
when Array
|
42
|
+
when Array
|
66
43
|
object.empty?
|
67
44
|
else
|
68
45
|
object.nil?
|
@@ -72,14 +49,7 @@ module SmoothOperator
|
|
72
49
|
def present?(object)
|
73
50
|
!blank?(object)
|
74
51
|
end
|
75
|
-
|
76
|
-
def absolute_path?(string)
|
77
|
-
present?(string) && string[0] == '/'
|
78
|
-
end
|
79
|
-
|
80
|
-
def remove_initial_slash(string)
|
81
|
-
string[1..-1]
|
82
|
-
end
|
83
|
-
|
52
|
+
|
84
53
|
end
|
85
|
-
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'smooth_operator/type_converter'
|
2
|
+
|
3
|
+
module SmoothOperator
|
4
|
+
|
5
|
+
class InternalAttribute
|
6
|
+
|
7
|
+
attr_reader :original_name, :original_value, :first_value, :value, :type, :turn_unknown_hash_to_open_struct
|
8
|
+
|
9
|
+
def initialize(name, value, type, turn_to_open_struct = nil)
|
10
|
+
@original_name, @original_value, @type = name, value, type
|
11
|
+
|
12
|
+
@turn_unknown_hash_to_open_struct = turn_to_open_struct.nil? ? true : turn_to_open_struct
|
13
|
+
|
14
|
+
@first_value = set_value(value)
|
15
|
+
end
|
16
|
+
|
17
|
+
def set_value(new_value)
|
18
|
+
@value = cast_to_type(new_value)
|
19
|
+
end
|
20
|
+
|
21
|
+
def changed?
|
22
|
+
@first_value != @value
|
23
|
+
end
|
24
|
+
|
25
|
+
def was
|
26
|
+
@first_value
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
protected ######################## PROTECTED #####################
|
31
|
+
|
32
|
+
def cast_to_type(_value)
|
33
|
+
case _value
|
34
|
+
when Array
|
35
|
+
_value.map { |array_entry| InternalAttribute.new(original_name, array_entry, type, turn_unknown_hash_to_open_struct).value }
|
36
|
+
when Hash
|
37
|
+
if turn_unknown_hash_to_open_struct
|
38
|
+
(type || OpenStruct).new(_value)
|
39
|
+
else
|
40
|
+
type.nil? ? _value : type.new(_value)
|
41
|
+
end
|
42
|
+
else
|
43
|
+
TypeConverter.convert(_value, type)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|