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
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
M2EyMTBiMWExYzQ4Mjc0ZDM3M2IyMGRkZmFjMTEzYmVjYzg5NDJkMw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YmZjYzA1YWM0ZjJmYzMwOWZjN2ZmMzVkMjRiNDFlYzc5MjVmYzNlNQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
Mzg4ZGRhNDA4NWJjNmEzNDkzMWNjYjZhZTM5YTFiMGRiMmUzZWNmOWFmMzg4
|
10
|
+
NjFiMGVjMDJhZGRkNTExNzdhNTAzOTU4MjQxNmVmZTBiMzIxM2Q5Y2I5MzZh
|
11
|
+
MTlhYTZiYWYxNWU1OTZjZmM0YjQ0ZjFlMTYxMjIxZjE5NWMzMmE=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ODljN2NlMTBlZDM1NWYwMzhlZmJjMDBkNDM3ZGEwOTYzZmNmZGFmNDQwMjUy
|
14
|
+
OWFhNjNmODRlNmUxYmI3MzdlZWQzZGEzZjg1MzE3ZmZkZDY2NmI5YjZiMDNj
|
15
|
+
OTdhNTA0OWNlMTk5NmM2OTNkZTlkZTlkODZhNDZiODhhNmVhZjc=
|
data/README.md
CHANGED
@@ -139,7 +139,7 @@ page.save # will make a http PATCH call to 'http://myblog.com/api/v0/pages/2'
|
|
139
139
|
remote_call = Page.find(:all) # Will make a GET call to 'http://myblog.com/api/v0/pages'
|
140
140
|
# and will return a SmoothOperator::RemoteCall instance
|
141
141
|
|
142
|
-
pages = remote_call.
|
142
|
+
pages = remote_call.data
|
143
143
|
|
144
144
|
# If the server response is positive (http code between 200 and 299):
|
145
145
|
remote_call.ok? # true
|
@@ -179,7 +179,7 @@ pages = remote_call.objects # 'pages = remote_call.data' also works
|
|
179
179
|
remote_call = Page.find(2) # Will make a GET call to 'http://myblog.com/api/v0/pages/2'
|
180
180
|
# and will return a SmoothOperator::RemoteCall instance
|
181
181
|
|
182
|
-
page = remote_call.
|
182
|
+
page = remote_call.data
|
183
183
|
```
|
184
184
|
|
185
185
|
---
|
@@ -1,22 +1,34 @@
|
|
1
1
|
module SmoothOperator
|
2
|
-
class ArrayWithMetaData <
|
2
|
+
class ArrayWithMetaData < SimpleDelegator
|
3
3
|
|
4
4
|
attr_reader :meta_data, :internal_array
|
5
5
|
|
6
6
|
def initialize(attributes, object_class)
|
7
|
-
|
7
|
+
resources_name = object_class.resources_name
|
8
8
|
|
9
|
-
@internal_array = [*
|
10
|
-
|
9
|
+
@internal_array = [*attributes[resources_name]].map do |array_entry|
|
10
|
+
object_class.new(array_entry)
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
+
attributes.delete(resources_name)
|
14
|
+
|
15
|
+
@meta_data = attributes
|
16
|
+
|
17
|
+
define_metada_methods
|
13
18
|
|
14
19
|
super(@internal_array)
|
15
20
|
end
|
16
21
|
|
17
|
-
|
18
|
-
|
19
|
-
|
22
|
+
protected ############# PROTECTED ###################
|
23
|
+
|
24
|
+
def define_metada_methods
|
25
|
+
@meta_data.keys.each do |method|
|
26
|
+
instance_eval <<-RUBY, __FILE__, __LINE__ + 1
|
27
|
+
def #{method}
|
28
|
+
@meta_data['#{method}']
|
29
|
+
end
|
30
|
+
RUBY
|
31
|
+
end
|
20
32
|
end
|
21
33
|
|
22
34
|
end
|
@@ -1,61 +1,18 @@
|
|
1
|
-
require 'smooth_operator/attributes/base'
|
2
|
-
require 'smooth_operator/attributes/dirty'
|
3
|
-
require 'smooth_operator/attributes/normal'
|
4
|
-
|
5
1
|
module SmoothOperator
|
6
2
|
module AttributeAssignment
|
7
3
|
|
8
|
-
def self.included(base)
|
9
|
-
base.extend(ClassMethods)
|
10
|
-
end
|
11
|
-
|
12
|
-
module ClassMethods
|
13
|
-
|
14
|
-
attr_writer :unknown_hash_class
|
15
|
-
|
16
|
-
def unknown_hash_class
|
17
|
-
Helpers.get_instance_variable(self, :unknown_hash_class, ::OpenStruct)
|
18
|
-
end
|
19
|
-
|
20
|
-
def attributes_white_list
|
21
|
-
Helpers.get_instance_variable(self, :attributes_white_list, Set.new)
|
22
|
-
end
|
23
|
-
|
24
|
-
def attributes_black_list
|
25
|
-
Helpers.get_instance_variable(self, :attributes_black_list, Set.new)
|
26
|
-
end
|
27
|
-
|
28
|
-
def attributes_white_list_add(*getters)
|
29
|
-
attributes_white_list.merge getters.map(&:to_s)
|
30
|
-
end
|
31
|
-
|
32
|
-
def attributes_black_list_add(*getters)
|
33
|
-
attributes_black_list.merge getters.map(&:to_s)
|
34
|
-
end
|
35
|
-
|
36
|
-
def dirty_attributes
|
37
|
-
@dirty_attributes = true
|
38
|
-
end
|
39
|
-
|
40
|
-
def dirty_attributes?
|
41
|
-
@dirty_attributes
|
42
|
-
end
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
4
|
def initialize(attributes = {}, options = {})
|
47
5
|
@_options = {}
|
48
6
|
|
49
7
|
before_initialize(attributes, options)
|
50
8
|
|
51
|
-
assign_attributes
|
9
|
+
assign_attributes(attributes, options)
|
52
10
|
|
53
11
|
after_initialize(attributes, options)
|
54
12
|
end
|
55
13
|
|
56
14
|
attr_reader :_options, :_meta_data
|
57
15
|
|
58
|
-
|
59
16
|
def assign_attributes(_attributes = {}, options = {})
|
60
17
|
return nil unless _attributes.is_a?(Hash)
|
61
18
|
|
@@ -66,22 +23,22 @@ module SmoothOperator
|
|
66
23
|
@_meta_data = _attributes
|
67
24
|
end
|
68
25
|
|
69
|
-
|
26
|
+
@_internal_errors = attributes.delete(self.class.errors_key)
|
70
27
|
|
71
|
-
|
72
|
-
end
|
28
|
+
options.each { |key, value| @_options[key] = value } if options.is_a? Hash
|
73
29
|
|
74
|
-
|
75
|
-
|
76
|
-
end
|
30
|
+
attributes.each do |name, value|
|
31
|
+
next unless allowed_attribute(name)
|
77
32
|
|
78
|
-
|
79
|
-
|
33
|
+
internal_data_push(name, value)
|
34
|
+
end
|
80
35
|
end
|
81
36
|
|
82
|
-
|
37
|
+
def _parent_object
|
38
|
+
_options[:parent_object]
|
39
|
+
end
|
83
40
|
|
84
|
-
protected
|
41
|
+
protected ################# PROTECTED METHODS DOWN BELOW ###################
|
85
42
|
|
86
43
|
def before_initialize(attributes, options); end
|
87
44
|
|
@@ -97,5 +54,35 @@ module SmoothOperator
|
|
97
54
|
end
|
98
55
|
end
|
99
56
|
|
57
|
+
def self.included(base)
|
58
|
+
base.extend(ClassMethods)
|
59
|
+
end
|
60
|
+
|
61
|
+
module ClassMethods
|
62
|
+
|
63
|
+
attr_writer :unknown_hash_class
|
64
|
+
|
65
|
+
def unknown_hash_class
|
66
|
+
Helpers.get_instance_variable(self, :unknown_hash_class, ::OpenStruct)
|
67
|
+
end
|
68
|
+
|
69
|
+
def attributes_white_list
|
70
|
+
Helpers.get_instance_variable(self, :attributes_white_list, Set.new)
|
71
|
+
end
|
72
|
+
|
73
|
+
def attributes_black_list
|
74
|
+
Helpers.get_instance_variable(self, :attributes_black_list, Set.new)
|
75
|
+
end
|
76
|
+
|
77
|
+
def attributes_white_list_add(*getters)
|
78
|
+
attributes_white_list.merge getters.map(&:to_s)
|
79
|
+
end
|
80
|
+
|
81
|
+
def attributes_black_list_add(*getters)
|
82
|
+
attributes_black_list.merge getters.map(&:to_s)
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
100
87
|
end
|
101
88
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
module SmoothOperator
|
2
|
-
|
3
2
|
module Delegation
|
4
3
|
|
5
4
|
def respond_to?(method, include_private = false)
|
@@ -7,48 +6,30 @@ module SmoothOperator
|
|
7
6
|
end
|
8
7
|
|
9
8
|
def method_missing(method, *args, &block)
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
get_internal_data(method_name, :changed?)
|
17
|
-
when :setter
|
18
|
-
return push_to_internal_data(method_name, args.first)
|
9
|
+
method_name = method.to_s
|
10
|
+
|
11
|
+
if !! ((method.to_s) =~ /=$/) #setter method
|
12
|
+
internal_data_push(method_name[0..-2], args.first)
|
13
|
+
elsif !self.class.strict_behaviour || known_attribute?(method_name)
|
14
|
+
internal_data_get(method_name)
|
19
15
|
else
|
20
|
-
|
21
|
-
return get_internal_data(method_name)
|
22
|
-
end
|
16
|
+
super
|
23
17
|
end
|
24
|
-
|
25
|
-
result.nil? ? super : result
|
26
18
|
end
|
27
19
|
|
20
|
+
def self.included(base)
|
21
|
+
base.extend(ClassMethods)
|
22
|
+
end
|
28
23
|
|
29
|
-
|
30
|
-
|
31
|
-
def parse_method(method)
|
32
|
-
method = method.to_s
|
24
|
+
module ClassMethods
|
33
25
|
|
34
|
-
|
35
|
-
|
36
|
-
elsif method?(method, /_was$/)
|
37
|
-
[:was, method[0..-5]]
|
38
|
-
elsif method?(method, /_changed\?$/)
|
39
|
-
[:changed, method[0..-10]]
|
40
|
-
else
|
41
|
-
[nil, method]
|
26
|
+
def strict_behaviour
|
27
|
+
Helpers.get_instance_variable(self, :strict_behaviour, false)
|
42
28
|
end
|
43
|
-
end
|
44
29
|
|
30
|
+
attr_writer :strict_behaviour
|
45
31
|
|
46
|
-
private #################### PRIVATE ################
|
47
|
-
|
48
|
-
def method?(method, regex)
|
49
|
-
!! ((method.to_s) =~ regex)
|
50
32
|
end
|
51
33
|
|
52
34
|
end
|
53
|
-
|
54
35
|
end
|
@@ -1,43 +1,52 @@
|
|
1
1
|
require 'smooth_operator/array_with_meta_data'
|
2
2
|
|
3
3
|
module SmoothOperator
|
4
|
-
|
5
4
|
module FinderMethods
|
6
5
|
|
7
6
|
def find(relative_path, data = {}, options = {})
|
8
7
|
relative_path = '' if relative_path == :all
|
9
8
|
|
10
9
|
get(relative_path, data, options) do |remote_call|
|
11
|
-
|
10
|
+
if remote_call.ok?
|
11
|
+
remote_call.object = HelperMethods
|
12
|
+
.build_object(self, remote_call.parsed_response, options)
|
13
|
+
end
|
12
14
|
|
13
15
|
block_given? ? yield(remote_call) : remote_call
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|
19
|
+
module HelperMethods
|
17
20
|
|
18
|
-
|
21
|
+
extend self
|
19
22
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
ArrayWithMetaData.new(parsed_response, object_class)
|
23
|
+
def build_object(object, parsed_response, options, from_array = false)
|
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)
|
26
28
|
else
|
27
|
-
|
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)
|
28
36
|
end
|
29
|
-
else
|
30
|
-
parsed_response
|
31
37
|
end
|
32
|
-
end
|
33
38
|
|
39
|
+
def parse_hash(object, parsed_response, options, from_array)
|
40
|
+
object_class ||= object.class == Class ? object : object.class
|
34
41
|
|
35
|
-
|
42
|
+
if parsed_response.include?(object_class.resources_name) && !from_array
|
43
|
+
ArrayWithMetaData.new(parsed_response.dup, object_class)
|
44
|
+
else
|
45
|
+
object_class.new(parsed_response, data_from_server: true)
|
46
|
+
end
|
47
|
+
end
|
36
48
|
|
37
|
-
def object_class
|
38
|
-
@object_class ||= self.class == Class ? self : self.class
|
39
49
|
end
|
40
50
|
|
41
51
|
end
|
42
|
-
|
43
52
|
end
|
@@ -4,16 +4,18 @@ module SmoothOperator
|
|
4
4
|
|
5
5
|
extend self
|
6
6
|
|
7
|
-
def
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
7
|
+
def primary_key(object)
|
8
|
+
object.internal_data_get(object.class.primary_key)
|
9
|
+
end
|
10
|
+
|
11
|
+
def has_primary_key?(object)
|
12
|
+
blank? primary_key(object)
|
13
13
|
end
|
14
14
|
|
15
15
|
def super_method(object, method_name, *args)
|
16
|
-
|
16
|
+
if object.superclass.respond_to?(method_name)
|
17
|
+
object.superclass.send(method_name, *args)
|
18
|
+
end
|
17
19
|
end
|
18
20
|
|
19
21
|
def get_instance_variable(object, variable, default_value)
|
@@ -56,7 +58,7 @@ module SmoothOperator
|
|
56
58
|
case object
|
57
59
|
when String
|
58
60
|
object.to_s == ''
|
59
|
-
when Array
|
61
|
+
when Array, Hash
|
60
62
|
object.empty?
|
61
63
|
else
|
62
64
|
object.nil?
|
@@ -0,0 +1,45 @@
|
|
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,38 +1,20 @@
|
|
1
|
-
require "smooth_operator/model_name"
|
2
1
|
require "smooth_operator/delegation"
|
3
2
|
require "smooth_operator/validations"
|
3
|
+
require "smooth_operator/resource_name"
|
4
4
|
require "smooth_operator/serialization"
|
5
|
-
require "smooth_operator/
|
5
|
+
require "smooth_operator/internal_data"
|
6
6
|
require "smooth_operator/attribute_assignment"
|
7
7
|
|
8
8
|
module SmoothOperator
|
9
|
-
|
9
|
+
class OpenStruct
|
10
10
|
|
11
|
-
|
11
|
+
extend ResourceName
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
include AttributeMethods
|
19
|
-
include AttributeAssignment
|
20
|
-
|
21
|
-
def self.strict_behaviour=(value)
|
22
|
-
@strict_behaviour = value
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.strict_behaviour
|
26
|
-
Helpers.get_instance_variable(self, :strict_behaviour, false)
|
27
|
-
end
|
28
|
-
|
29
|
-
end
|
30
|
-
|
31
|
-
class Dirty < Base
|
32
|
-
|
33
|
-
dirty_attributes
|
34
|
-
|
35
|
-
end
|
13
|
+
include Delegation
|
14
|
+
include Validations
|
15
|
+
include InternalData
|
16
|
+
include Serialization
|
17
|
+
include AttributeAssignment
|
36
18
|
|
37
19
|
end
|
38
20
|
end
|