smooth_operator 1.20.10 → 1.21.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/README.md +2 -2
- data/lib/smooth_operator/array_with_meta_data.rb +20 -8
- data/lib/smooth_operator/attribute_assignment.rb +41 -54
- data/lib/smooth_operator/delegation.rb +14 -33
- data/lib/smooth_operator/finder_methods.rb +26 -17
- data/lib/smooth_operator/helpers.rb +10 -8
- data/lib/smooth_operator/internal_data.rb +45 -0
- data/lib/smooth_operator/open_struct.rb +9 -27
- data/lib/smooth_operator/operator.rb +11 -12
- data/lib/smooth_operator/persistence.rb +52 -41
- data/lib/smooth_operator/relation/array_relation.rb +2 -12
- data/lib/smooth_operator/relation/association_reflection.rb +2 -6
- data/lib/smooth_operator/relation/associations.rb +3 -3
- data/lib/smooth_operator/remote_call/base.rb +0 -4
- data/lib/smooth_operator/{model_name.rb → resource_name.rb} +2 -2
- data/lib/smooth_operator/schema.rb +9 -20
- data/lib/smooth_operator/serialization.rb +11 -11
- data/lib/smooth_operator/translation.rb +21 -12
- data/lib/smooth_operator/type_casting.rb +127 -0
- data/lib/smooth_operator/validations.rb +19 -3
- data/lib/smooth_operator/version.rb +1 -1
- data/lib/smooth_operator.rb +24 -3
- data/spec/smooth_operator/attribute_assignment_spec.rb +4 -13
- data/spec/smooth_operator/finder_methods_spec.rb +4 -9
- data/spec/smooth_operator/persistence_spec.rb +3 -15
- data/spec/smooth_operator/{model_name_spec.rb → resource_name_spec.rb} +1 -1
- data/spec/support/models/address.rb +0 -2
- data/spec/support/models/user.rb +3 -3
- data/spec/support/models/user_with_address_and_posts.rb +6 -14
- metadata +7 -12
- data/lib/smooth_operator/attribute_methods.rb +0 -92
- data/lib/smooth_operator/attributes/base.rb +0 -107
- data/lib/smooth_operator/attributes/dirty.rb +0 -29
- data/lib/smooth_operator/attributes/normal.rb +0 -15
- data/lib/smooth_operator/blank_slate.rb +0 -7
- data/spec/smooth_operator/attributes_dirty_spec.rb +0 -53
@@ -12,8 +12,10 @@ module SmoothOperator
|
|
12
12
|
|
13
13
|
relative_path = resource_path(relative_path)
|
14
14
|
|
15
|
-
if !
|
16
|
-
|
15
|
+
if !_parent_object.nil? && options[:ignore_parent] != true
|
16
|
+
id = Helpers.primary_key(_parent_object)
|
17
|
+
|
18
|
+
options[:resources_name] ||= "#{_parent_object.class.resources_name}/#{id}/#{self.class.resources_name}"
|
17
19
|
end
|
18
20
|
|
19
21
|
self.class.make_the_call(http_verb, relative_path, data, options) do |remote_call|
|
@@ -27,12 +29,18 @@ module SmoothOperator
|
|
27
29
|
if Helpers.absolute_path?(relative_path)
|
28
30
|
Helpers.remove_initial_slash(relative_path)
|
29
31
|
elsif persisted?
|
30
|
-
Helpers.
|
32
|
+
id = Helpers.primary_key(self)
|
33
|
+
|
34
|
+
Helpers.present?(relative_path) ? "#{id}/#{relative_path}" : id.to_s
|
31
35
|
else
|
32
36
|
relative_path
|
33
37
|
end
|
34
38
|
end
|
35
39
|
|
40
|
+
def self.included(base)
|
41
|
+
base.extend(ClassMethods)
|
42
|
+
end
|
43
|
+
|
36
44
|
########################### MODULES BELLOW ###############################
|
37
45
|
|
38
46
|
module HttpMethods
|
@@ -67,7 +75,6 @@ module SmoothOperator
|
|
67
75
|
|
68
76
|
attr_writer :headers
|
69
77
|
|
70
|
-
|
71
78
|
def make_the_call(http_verb, relative_path = '', data = {}, options = {})
|
72
79
|
operator_args = operator_method_args(http_verb, relative_path, data, options)
|
73
80
|
|
@@ -127,13 +134,5 @@ module SmoothOperator
|
|
127
134
|
end
|
128
135
|
end
|
129
136
|
|
130
|
-
include HttpMethods
|
131
|
-
|
132
|
-
def self.included(base)
|
133
|
-
base.extend(ClassMethods)
|
134
|
-
base.extend(HttpMethods)
|
135
|
-
end
|
136
|
-
|
137
137
|
end
|
138
|
-
|
139
138
|
end
|
@@ -7,28 +7,20 @@ module SmoothOperator
|
|
7
7
|
|
8
8
|
attr_reader :last_remote_call
|
9
9
|
|
10
|
-
def
|
11
|
-
|
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))
|
10
|
+
def new_record?(ignore_cache = false)
|
11
|
+
return @new_record if !ignore_cache && defined?(@new_record)
|
16
12
|
|
17
|
-
|
18
|
-
block_given? ? yield(remote_call) : remote_call.status
|
19
|
-
end
|
13
|
+
@new_record = Helpers.has_primary_key?(self)
|
20
14
|
end
|
21
15
|
|
22
|
-
def
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
end
|
16
|
+
def marked_for_destruction?(ignore_cache = false)
|
17
|
+
if !ignore_cache && defined?(@marked_for_destruction)
|
18
|
+
return @marked_for_destruction
|
19
|
+
end
|
27
20
|
|
28
|
-
|
29
|
-
return @marked_for_destruction if !bypass_cache && defined?(@marked_for_destruction)
|
21
|
+
_destroy = internal_data_get(self.class.destroy_key)
|
30
22
|
|
31
|
-
@marked_for_destruction =
|
23
|
+
@marked_for_destruction = TypeCasting::TRUE_VALUES.include?(_destroy)
|
32
24
|
end
|
33
25
|
|
34
26
|
def destroyed?
|
@@ -41,13 +33,28 @@ module SmoothOperator
|
|
41
33
|
!(new_record? || destroyed?)
|
42
34
|
end
|
43
35
|
|
36
|
+
def known_attribute?(attribute)
|
37
|
+
super ||
|
38
|
+
[self.class.primary_key, self.class.destroy_key].include?(attribute.to_s)
|
39
|
+
end
|
40
|
+
|
41
|
+
def reload(relative_path = nil, data = {}, options = {})
|
42
|
+
if Helpers.blank?(relative_path) && Helpers.has_primary_key?(self)
|
43
|
+
raise 'UnknownPath'
|
44
|
+
end
|
45
|
+
|
46
|
+
_persistence_call(:reload, relative_path, data, options) do |remote_call|
|
47
|
+
block_given? ? yield(remote_call) : remote_call.status
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
44
51
|
def save(relative_path = nil, data = {}, options = {})
|
45
|
-
data =
|
52
|
+
data = resource_attributes(data, options)
|
53
|
+
|
54
|
+
method = new_record? ? :create : :update
|
46
55
|
|
47
|
-
|
48
|
-
|
49
|
-
else
|
50
|
-
update(relative_path, data, options) { |remote_call| block_given? ? yield(remote_call) : remote_call.status }
|
56
|
+
send(method, relative_path, data, options) do |remote_call|
|
57
|
+
block_given? ? yield(remote_call) : remote_call.status
|
51
58
|
end
|
52
59
|
end
|
53
60
|
|
@@ -60,18 +67,17 @@ module SmoothOperator
|
|
60
67
|
def destroy(relative_path = nil, data = {}, options = {})
|
61
68
|
return false unless persisted?
|
62
69
|
|
63
|
-
|
70
|
+
_persistence_call(:destroy, relative_path, data, options) do |remote_call|
|
64
71
|
@destroyed = true if remote_call.status
|
65
72
|
|
66
73
|
block_given? ? yield(remote_call) : remote_call.status
|
67
74
|
end
|
68
75
|
end
|
69
76
|
|
70
|
-
|
71
77
|
protected ######################### PROTECTED ##################
|
72
78
|
|
73
79
|
def create(relative_path, data, options)
|
74
|
-
|
80
|
+
_persistence_call(:create, relative_path, data, options) do |remote_call|
|
75
81
|
@new_record = false if remote_call.status
|
76
82
|
|
77
83
|
block_given? ? yield(remote_call) : remote_call
|
@@ -79,12 +85,24 @@ module SmoothOperator
|
|
79
85
|
end
|
80
86
|
|
81
87
|
def update(relative_path, data, options)
|
82
|
-
|
88
|
+
_persistence_call(:update, relative_path, data, options) do |remote_call|
|
83
89
|
block_given? ? yield(remote_call) : remote_call
|
84
90
|
end
|
85
91
|
end
|
86
92
|
|
87
|
-
def
|
93
|
+
def resource_attributes(data, options)
|
94
|
+
data = Helpers.stringify_keys(data)
|
95
|
+
|
96
|
+
hash = serializable_hash(options[:serializable_options]).dup
|
97
|
+
|
98
|
+
hash.delete(self.class.primary_key)
|
99
|
+
|
100
|
+
{ self.class.resource_name => hash }.merge(data)
|
101
|
+
end
|
102
|
+
|
103
|
+
private ##################### PRIVATE ##################
|
104
|
+
|
105
|
+
def _persistence_call(method, relative_path, data, options)
|
88
106
|
options ||= {}
|
89
107
|
|
90
108
|
http_verb = options[:http_verb] || self.class.methods_vs_http_verbs[method]
|
@@ -93,24 +111,13 @@ module SmoothOperator
|
|
93
111
|
@last_remote_call = remote_call
|
94
112
|
|
95
113
|
if !@last_remote_call.error? && @last_remote_call.parsed_response.is_a?(Hash)
|
96
|
-
assign_attributes @last_remote_call.parsed_response,
|
114
|
+
assign_attributes @last_remote_call.parsed_response, data_from_server: true
|
97
115
|
end
|
98
116
|
|
99
117
|
yield(remote_call)
|
100
118
|
end
|
101
119
|
end
|
102
120
|
|
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
121
|
module ClassMethods
|
115
122
|
|
116
123
|
METHODS_VS_HTTP_VERBS = { reload: :get, create: :post, update: :put, destroy: :delete }
|
@@ -132,11 +139,15 @@ module SmoothOperator
|
|
132
139
|
attr_writer :destroy_key
|
133
140
|
|
134
141
|
METHODS_VS_HTTP_VERBS.keys.each do |method|
|
135
|
-
define_method("#{method}_http_verb=")
|
142
|
+
define_method("#{method}_http_verb=") do |http_verb|
|
143
|
+
methods_vs_http_verbs[method] = http_verb
|
144
|
+
end
|
136
145
|
end
|
137
146
|
|
138
147
|
def create(attributes = nil, relative_path = nil, data = {}, options = {})
|
139
|
-
new(attributes).tap
|
148
|
+
new(attributes).tap do |object|
|
149
|
+
object.save(relative_path, data, options)
|
150
|
+
end
|
140
151
|
end
|
141
152
|
|
142
153
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module SmoothOperator
|
2
2
|
module Relation
|
3
|
-
class ArrayRelation <
|
3
|
+
class ArrayRelation < SimpleDelegator
|
4
4
|
|
5
5
|
attr_reader :object, :association
|
6
6
|
|
@@ -30,18 +30,8 @@ module SmoothOperator
|
|
30
30
|
|
31
31
|
protected ############### PROTECTED ###############
|
32
32
|
|
33
|
-
# def method_missing(method, *args, &block)
|
34
|
-
# if get_array.respond_to?(method)
|
35
|
-
# puts "if true #{method} - #{args}"
|
36
|
-
# get_array.send(method, *args)
|
37
|
-
# else
|
38
|
-
# puts "if else #{method}"
|
39
|
-
# super
|
40
|
-
# end
|
41
|
-
# end
|
42
|
-
|
43
33
|
def get_array
|
44
|
-
data = object.
|
34
|
+
data = object.internal_data_get(association.to_s)
|
45
35
|
|
46
36
|
data.nil? ? [] : [*data]
|
47
37
|
end
|
@@ -8,8 +8,8 @@ module SmoothOperator
|
|
8
8
|
|
9
9
|
def initialize(association, related_reflection, options)
|
10
10
|
super(association, options)
|
11
|
-
|
12
|
-
@related_reflection = related_reflection
|
11
|
+
|
12
|
+
@related_reflection, @macro = related_reflection, options[:macro]
|
13
13
|
end
|
14
14
|
|
15
15
|
def primary_key
|
@@ -62,10 +62,6 @@ module SmoothOperator
|
|
62
62
|
|
63
63
|
private ################################# private
|
64
64
|
|
65
|
-
def macro_default(association)
|
66
|
-
Helpers.plural?(association) ? :has_many : :belongs_to
|
67
|
-
end
|
68
|
-
|
69
65
|
def foreign_key_default
|
70
66
|
if has_many? || has_one?
|
71
67
|
"#{related_reflection.single_name}_id"
|
@@ -70,12 +70,12 @@ module SmoothOperator
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def define_single_association_method(reflection, association)
|
73
|
-
define_method(association) {
|
73
|
+
define_method(association) { internal_data_get(association.to_s) }
|
74
74
|
|
75
75
|
define_method("build_#{association}") do |attributes = {}|
|
76
76
|
new_instance = reflection.klass.new(attributes)
|
77
77
|
|
78
|
-
|
78
|
+
internal_data_push(association, new_instance)
|
79
79
|
|
80
80
|
new_instance
|
81
81
|
end
|
@@ -87,7 +87,7 @@ module SmoothOperator
|
|
87
87
|
|
88
88
|
attributes = attributes.values if reflection.has_many?
|
89
89
|
|
90
|
-
|
90
|
+
internal_data_push(association.to_s, attributes)
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module SmoothOperator
|
2
|
-
module
|
2
|
+
module ResourceName
|
3
3
|
|
4
4
|
def resources_name(default_bypass = nil)
|
5
5
|
return @resources_name if defined?(@resources_name)
|
@@ -40,7 +40,7 @@ module SmoothOperator
|
|
40
40
|
end
|
41
41
|
|
42
42
|
ActiveModel::Name.new(self, namespace, @_model_name).tap do |model_name|
|
43
|
-
def model_name.human(options = {});
|
43
|
+
def model_name.human(options = {}); SmoothOperator::Translation::HelperMethods.translate("models.#{i18n_key}", options); end
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
@@ -1,32 +1,21 @@
|
|
1
1
|
module SmoothOperator
|
2
2
|
module Schema
|
3
3
|
|
4
|
-
def
|
5
|
-
|
4
|
+
def schema(structure)
|
5
|
+
internal_structure.merge! Helpers.stringify_keys(structure)
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
9
|
-
self
|
8
|
+
def internal_structure
|
9
|
+
Helpers.get_instance_variable(self, :internal_structure,
|
10
|
+
{ primary_key => nil })
|
10
11
|
end
|
11
12
|
|
12
|
-
def
|
13
|
-
|
13
|
+
def known_attribute?(attribute)
|
14
|
+
internal_structure.has_key?(attribute.to_s)
|
14
15
|
end
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
attr_writer :resource_name
|
19
|
-
|
20
|
-
def schema(structure)
|
21
|
-
internal_structure.merge! Helpers.stringify_keys(structure)
|
22
|
-
|
23
|
-
known_attributes.merge internal_structure.keys
|
24
|
-
end
|
25
|
-
|
26
|
-
def internal_structure
|
27
|
-
Helpers.get_instance_variable(self, :internal_structure, { "errors" => nil, primary_key => nil, destroy_key => nil })
|
28
|
-
end
|
29
|
-
|
17
|
+
def attribute_type(attribute)
|
18
|
+
internal_structure[attribute.to_s]
|
30
19
|
end
|
31
20
|
|
32
21
|
end
|
@@ -5,13 +5,13 @@ module SmoothOperator
|
|
5
5
|
def to_hash(options = nil)
|
6
6
|
Helpers.symbolyze_keys(serializable_hash(options) || {})
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
# alias :attributes :to_hash
|
10
10
|
def attributes; to_hash; end
|
11
|
-
|
11
|
+
|
12
12
|
def to_json(options = nil)
|
13
13
|
require 'json' unless defined? JSON
|
14
|
-
|
14
|
+
|
15
15
|
JSON(serializable_hash(options) || {})
|
16
16
|
end
|
17
17
|
|
@@ -23,8 +23,8 @@ module SmoothOperator
|
|
23
23
|
hash = {}
|
24
24
|
options ||= {}
|
25
25
|
|
26
|
-
|
27
|
-
hash[attribute_name] =
|
26
|
+
_attribute_names(options).each do |attribute_name|
|
27
|
+
hash[attribute_name] = _read_attribute_for_hashing(attribute_name, options)
|
28
28
|
end
|
29
29
|
|
30
30
|
method_names(options).each do |method_name|
|
@@ -36,9 +36,9 @@ module SmoothOperator
|
|
36
36
|
|
37
37
|
|
38
38
|
protected ##################### PROTECTED ###################
|
39
|
-
|
39
|
+
|
40
40
|
# TODO: COMPLEX METHOD
|
41
|
-
def
|
41
|
+
def _attribute_names(options)
|
42
42
|
attribute_names = internal_data.keys.sort
|
43
43
|
|
44
44
|
if only = options[:only]
|
@@ -54,19 +54,19 @@ module SmoothOperator
|
|
54
54
|
[*options[:methods]].select { |n| respond_to?(n) }
|
55
55
|
end
|
56
56
|
|
57
|
-
def
|
57
|
+
def _read_attribute_for_hashing(attribute_name, options)
|
58
58
|
object = read_attribute_for_serialization(attribute_name)
|
59
59
|
|
60
60
|
_options = options[attribute_name] || options[attribute_name.to_sym]
|
61
61
|
|
62
62
|
if object.is_a?(Array)
|
63
|
-
object.map { |array_entry|
|
63
|
+
object.map { |array_entry| _attribute_to_hash(array_entry, _options) }
|
64
64
|
else
|
65
|
-
|
65
|
+
_attribute_to_hash(object, _options)
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
-
def
|
69
|
+
def _attribute_to_hash(object, options = nil)
|
70
70
|
if object.respond_to?(:serializable_hash)
|
71
71
|
Helpers.symbolyze_keys(object.serializable_hash(options))
|
72
72
|
else
|
@@ -2,23 +2,32 @@ module SmoothOperator
|
|
2
2
|
module Translation
|
3
3
|
|
4
4
|
def human_attribute_name(attribute_key_name, options = {})
|
5
|
-
|
5
|
+
HelperMethods.translate(
|
6
|
+
"attributes.#{model_name.i18n_key}.#{attribute_key_name}",
|
7
|
+
options
|
8
|
+
)
|
6
9
|
end
|
7
10
|
|
8
|
-
|
11
|
+
module HelperMethods
|
9
12
|
|
10
|
-
|
11
|
-
no_translation = "-- no translation --"
|
13
|
+
extend self
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
def translate(namespace = '', options = {})
|
16
|
+
no_translation = "-- no translation --"
|
17
|
+
|
18
|
+
defaults = ["smooth_operator.#{namespace}".to_sym]
|
19
|
+
defaults << "activerecord.#{namespace}".to_sym
|
20
|
+
defaults << options[:default] if options[:default]
|
21
|
+
defaults.flatten!
|
22
|
+
defaults << no_translation
|
23
|
+
|
24
|
+
options = { count: 1, default: defaults }
|
25
|
+
.merge!(options.except(:default))
|
26
|
+
|
27
|
+
I18n.translate(defaults.shift, options)
|
28
|
+
end
|
18
29
|
|
19
|
-
options = { count: 1, default: defaults }.merge!(options.except(:default))
|
20
|
-
I18n.translate(defaults.shift, options)
|
21
30
|
end
|
22
31
|
|
23
32
|
end
|
24
|
-
end
|
33
|
+
end
|