smooth_operator 1.11.2 → 1.20.9
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/console.rb +4 -1
- data/lib/smooth_operator/array_with_meta_data.rb +3 -14
- data/lib/smooth_operator/attribute_assignment.rb +1 -65
- data/lib/smooth_operator/attribute_methods.rb +78 -0
- data/lib/smooth_operator/attributes/base.rb +3 -3
- data/lib/smooth_operator/blank_slate.rb +7 -0
- data/lib/smooth_operator/delegation.rb +6 -4
- data/lib/smooth_operator/helpers.rb +15 -3
- data/lib/smooth_operator/model_schema.rb +9 -9
- data/lib/smooth_operator/open_struct.rb +3 -1
- data/lib/smooth_operator/operator.rb +7 -13
- data/lib/smooth_operator/persistence.rb +19 -11
- data/lib/smooth_operator/relation/array_relation.rb +55 -0
- data/lib/smooth_operator/relation/association_reflection.rb +79 -0
- data/lib/smooth_operator/relation/associations.rb +102 -0
- data/lib/smooth_operator/relation/reflection.rb +41 -0
- data/lib/smooth_operator/remote_call/base.rb +2 -7
- data/lib/smooth_operator/translation.rb +2 -5
- data/lib/smooth_operator/version.rb +1 -1
- data/lib/smooth_operator.rb +18 -0
- data/smooth_operator.gemspec +5 -5
- data/spec/smooth_operator/attribute_assignment_spec.rb +7 -7
- data/spec/support/models/address.rb +1 -1
- data/spec/support/models/comment.rb +3 -0
- data/spec/support/models/post.rb +5 -1
- metadata +19 -11
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZDBhM2U5NjlkNjVmMzk4MGQxNTVkNTBiZDBhODI5NDlkMjRkZGQ2OQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZTg1N2IwOTY0ZDlmMmVjMTVjNGFmMzNjM2YxZjE5MGFlMTNiMDk3Mg==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MWQzYjFkMGNmNDY2NmU2MzFjOThjMWQzYWZjMjNiNjNjYTQwZDZkNGVlYzdm
|
10
|
+
YzIxODAyNWI4YTZiNjVhYjk2NzgzMGNjYjc1MGVhNWY0ZGRiNWNiZDQ5MGFl
|
11
|
+
Y2E3NGM2ZDNiNWFiYTg2YjMzNTVhMmNkODM0MTYxZTg2YzBmMTU=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
OGYwYjBiY2U2NWUzMThhZGIwOTZiOWMzOWZkYzM2NDZiODE4NmFkYWJmNzhj
|
14
|
+
NTI3MWU4NDVjOTU0ZTdkNTU1MWRiOTk3NzRmYmFjOGJkNjgyNzhlOTFjMzMx
|
15
|
+
NTgxNzUzZjQ1MDQ3MzNkNTJiYzNlM2E2NjUyN2ZiZWI3YjRmMmQ=
|
data/console.rb
CHANGED
@@ -27,5 +27,8 @@ LocalhostServer.new(TestServer.new, 4567)
|
|
27
27
|
|
28
28
|
# "[{\"patient_id\"=>33, \"messages\"=>[{\"id\"=>\"53722c20cb38247c36000003\", \"title\"=>\"Joao Goncalves\", \"created_at\"=>\"2014-05-13T14:28:48Z\"}, {\"id\"=>\"53722bfccb382485d5000002\", \"title\"=>\"Joao Goncalves\", \"created_at\"=>\"2014-05-13T14:28:12Z\"}, {\"id\"=>\"53722b91cb3824e913000001\", \"title\"=>\"Joao Goncalves\", \"created_at\"=>\"2014-05-13T14:26:25Z\"}]}]"
|
29
29
|
|
30
|
-
|
30
|
+
post = Post.new(comments: [{ id: 1, name: '1' }, { id: 2, name: '2' }], address: { id: 1, name: 'address' })
|
31
|
+
|
32
|
+
comments_attributes = { "0" => { id: 1, name: '3' }, "1" => { name: '4' } }
|
31
33
|
|
34
|
+
binding.pry
|
@@ -1,15 +1,8 @@
|
|
1
1
|
module SmoothOperator
|
2
|
-
|
3
|
-
class ArrayWithMetaData < OpenStruct::Base
|
4
|
-
|
5
|
-
extend Forwardable
|
6
|
-
|
7
|
-
include Enumerable
|
2
|
+
class ArrayWithMetaData < ::SimpleDelegator
|
8
3
|
|
9
4
|
attr_reader :meta_data, :internal_array
|
10
5
|
|
11
|
-
def_delegators :internal_array, :length, :<<, :[]
|
12
|
-
|
13
6
|
def initialize(attributes, object_class)
|
14
7
|
_attributes, _resources_name = attributes.dup, object_class.resources_name
|
15
8
|
|
@@ -17,18 +10,14 @@ module SmoothOperator
|
|
17
10
|
_attributes.delete(_resources_name)
|
18
11
|
|
19
12
|
@meta_data = _attributes
|
20
|
-
end
|
21
13
|
|
22
|
-
|
23
|
-
def each
|
24
|
-
internal_array.each { |array_entry| yield array_entry }
|
14
|
+
super(@internal_array)
|
25
15
|
end
|
26
|
-
|
16
|
+
|
27
17
|
def method_missing(method, *args, &block)
|
28
18
|
_method = method.to_s
|
29
19
|
meta_data.include?(_method) ? meta_data[_method] : super
|
30
20
|
end
|
31
21
|
|
32
22
|
end
|
33
|
-
|
34
23
|
end
|
@@ -3,7 +3,6 @@ require 'smooth_operator/attributes/dirty'
|
|
3
3
|
require 'smooth_operator/attributes/normal'
|
4
4
|
|
5
5
|
module SmoothOperator
|
6
|
-
|
7
6
|
module AttributeAssignment
|
8
7
|
|
9
8
|
def self.included(base)
|
@@ -44,7 +43,6 @@ module SmoothOperator
|
|
44
43
|
|
45
44
|
end
|
46
45
|
|
47
|
-
|
48
46
|
def initialize(attributes = {}, options = {})
|
49
47
|
@_options = {}
|
50
48
|
|
@@ -70,7 +68,7 @@ module SmoothOperator
|
|
70
68
|
|
71
69
|
options.each { |key, value| @_options[key] = value } if options.is_a?(Hash)
|
72
70
|
|
73
|
-
attributes.each { |name, value| push_to_internal_data(name, value
|
71
|
+
attributes.each { |name, value| push_to_internal_data(name, value) }
|
74
72
|
end
|
75
73
|
|
76
74
|
def parent_object
|
@@ -83,40 +81,6 @@ module SmoothOperator
|
|
83
81
|
|
84
82
|
alias :from_server :has_data_from_server
|
85
83
|
|
86
|
-
def internal_data
|
87
|
-
@internal_data ||= {}
|
88
|
-
end
|
89
|
-
|
90
|
-
def get_internal_data(field, method = :value)
|
91
|
-
result = internal_data[field]
|
92
|
-
|
93
|
-
if result.nil?
|
94
|
-
nil
|
95
|
-
elsif method == :value
|
96
|
-
result.is_a?(Attributes::Dirty) ? internal_data[field].send(method) : internal_data[field]
|
97
|
-
else
|
98
|
-
internal_data[field].send(method)
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def push_to_internal_data(attribute_name, attribute_value, cast = false)
|
103
|
-
attribute_name = attribute_name.to_s
|
104
|
-
|
105
|
-
return nil unless allowed_attribute(attribute_name)
|
106
|
-
|
107
|
-
known_attributes.add attribute_name
|
108
|
-
|
109
|
-
if internal_data[attribute_name].nil?
|
110
|
-
initiate_internal_data(attribute_name, attribute_value, cast)
|
111
|
-
else
|
112
|
-
update_internal_data(attribute_name, attribute_value, cast)
|
113
|
-
end
|
114
|
-
|
115
|
-
if self.class.respond_to?(:smooth_operator?) && attribute_name == self.class.primary_key
|
116
|
-
new_record?(true)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
84
|
protected #################### PROTECTED METHODS DOWN BELOW ######################
|
121
85
|
|
122
86
|
def before_initialize(attributes, options); end
|
@@ -133,33 +97,5 @@ module SmoothOperator
|
|
133
97
|
end
|
134
98
|
end
|
135
99
|
|
136
|
-
|
137
|
-
private ######################## PRIVATE #############################
|
138
|
-
|
139
|
-
def initiate_internal_data(attribute_name, attribute_value, cast)
|
140
|
-
if cast
|
141
|
-
internal_data[attribute_name] = new_attribute_object(attribute_name, attribute_value)
|
142
|
-
|
143
|
-
internal_data[attribute_name] = internal_data[attribute_name].value unless self.class.dirty_attributes?
|
144
|
-
else
|
145
|
-
internal_data[attribute_name] = attribute_value
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
def update_internal_data(attribute_name, attribute_value, cast)
|
150
|
-
if self.class.dirty_attributes?
|
151
|
-
internal_data[attribute_name].set_value(attribute_value, self)
|
152
|
-
else
|
153
|
-
internal_data[attribute_name] = cast ? new_attribute_object(attribute_name, attribute_value).value : attribute_value
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
def new_attribute_object(attribute_name, attribute_value)
|
158
|
-
attribute_class = self.class.dirty_attributes? ? Attributes::Dirty : Attributes::Normal
|
159
|
-
|
160
|
-
attribute_class.new(attribute_name, attribute_value, self)
|
161
|
-
end
|
162
|
-
|
163
100
|
end
|
164
|
-
|
165
101
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module SmoothOperator
|
2
|
+
module AttributeMethods
|
3
|
+
|
4
|
+
def internal_data
|
5
|
+
@internal_data ||= {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def get_internal_data(field, method = :value)
|
9
|
+
result = internal_data[field]
|
10
|
+
|
11
|
+
if result.nil?
|
12
|
+
nil
|
13
|
+
elsif method == :value
|
14
|
+
result.is_a?(Attributes::Dirty) ? internal_data[field].send(method) : internal_data[field]
|
15
|
+
else
|
16
|
+
internal_data[field].send(method)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_attribute_type(attribute)
|
21
|
+
self.class.internal_structure[attribute.to_s]
|
22
|
+
end
|
23
|
+
|
24
|
+
def push_to_internal_data(attribute_name, attribute_value)
|
25
|
+
attribute_name = attribute_name.to_s
|
26
|
+
|
27
|
+
return nil unless allowed_attribute(attribute_name)
|
28
|
+
|
29
|
+
known_attributes.add attribute_name
|
30
|
+
|
31
|
+
initiate_or_update_internal_data(attribute_name, attribute_value)
|
32
|
+
|
33
|
+
new_record_or_mark_for_destruction?(attribute_name, attribute_value)
|
34
|
+
end
|
35
|
+
|
36
|
+
protected #################### PROTECTED METHODS DOWN BELOW ######################
|
37
|
+
|
38
|
+
def initiate_or_update_internal_data(attribute_name, attribute_value)
|
39
|
+
if internal_data[attribute_name].nil?
|
40
|
+
initiate_internal_data(attribute_name, attribute_value)
|
41
|
+
else
|
42
|
+
update_internal_data(attribute_name, attribute_value)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def new_record_or_mark_for_destruction?(attribute_name, attribute_value)
|
47
|
+
return nil unless self.class.respond_to?(:smooth_operator?)
|
48
|
+
|
49
|
+
marked_for_destruction?(attribute_value) if attribute_name == self.class.destroy_key
|
50
|
+
|
51
|
+
new_record?(true) if attribute_name == self.class.primary_key
|
52
|
+
end
|
53
|
+
|
54
|
+
private ######################## PRIVATE #############################
|
55
|
+
|
56
|
+
def initiate_internal_data(attribute_name, attribute_value)
|
57
|
+
internal_data[attribute_name] = new_attribute_object(attribute_name, attribute_value)
|
58
|
+
|
59
|
+
internal_data[attribute_name] = internal_data[attribute_name].value unless self.class.dirty_attributes?
|
60
|
+
end
|
61
|
+
|
62
|
+
def update_internal_data(attribute_name, attribute_value)
|
63
|
+
if self.class.dirty_attributes?
|
64
|
+
internal_data[attribute_name].set_value(attribute_value, self)
|
65
|
+
else
|
66
|
+
internal_data[attribute_name] = new_attribute_object(attribute_name, attribute_value).value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def new_attribute_object(attribute_name, attribute_value)
|
71
|
+
attribute_class = self.class.dirty_attributes? ? Attributes::Dirty : Attributes::Normal
|
72
|
+
|
73
|
+
attribute_class.new(attribute_name, attribute_value, self)
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -6,7 +6,7 @@ module SmoothOperator
|
|
6
6
|
protected ##################### PROTECTED ########################
|
7
7
|
|
8
8
|
def cast_to_type(name, value, parent_object)
|
9
|
-
known_by_schema, type, unknown_hash_class = 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
10
|
|
11
11
|
return Helpers.duplicate(value) if known_by_schema && type.nil?
|
12
12
|
|
@@ -25,7 +25,7 @@ module SmoothOperator
|
|
25
25
|
|
26
26
|
when :string, :text, String
|
27
27
|
value.to_s
|
28
|
-
|
28
|
+
|
29
29
|
when :int, :integer, Integer, Fixnum
|
30
30
|
to_int(value)
|
31
31
|
|
@@ -74,7 +74,7 @@ module SmoothOperator
|
|
74
74
|
return string if string.is_a?(Float)
|
75
75
|
|
76
76
|
return 0 if string.nil? || !(string.is_a?(String) || string.is_a?(Fixnum))
|
77
|
-
|
77
|
+
|
78
78
|
value = string.to_s.gsub(',', '.').scan(/-*\d+[.]*\d*/).flatten.map(&:to_f).first
|
79
79
|
|
80
80
|
value.nil? ? 0 : value
|
@@ -2,8 +2,8 @@ module SmoothOperator
|
|
2
2
|
|
3
3
|
module Delegation
|
4
4
|
|
5
|
-
def respond_to?(method)
|
6
|
-
|
5
|
+
def respond_to?(method, include_private = false)
|
6
|
+
known_attribute?(method) ? true : super
|
7
7
|
end
|
8
8
|
|
9
9
|
def method_missing(method, *args, &block)
|
@@ -17,7 +17,9 @@ module SmoothOperator
|
|
17
17
|
when :setter
|
18
18
|
return push_to_internal_data(method_name, args.first)
|
19
19
|
else
|
20
|
-
|
20
|
+
if !self.class.strict_behaviour || known_attribute?(method_name)
|
21
|
+
return get_internal_data(method_name)
|
22
|
+
end
|
21
23
|
end
|
22
24
|
|
23
25
|
result.nil? ? super : result
|
@@ -28,7 +30,7 @@ module SmoothOperator
|
|
28
30
|
|
29
31
|
def parse_method(method)
|
30
32
|
method = method.to_s
|
31
|
-
|
33
|
+
|
32
34
|
if method?(method, /=$/)
|
33
35
|
[:setter, method[0..-2]]
|
34
36
|
elsif method?(method, /_was$/)
|
@@ -3,7 +3,15 @@ module SmoothOperator
|
|
3
3
|
module Helpers
|
4
4
|
|
5
5
|
extend self
|
6
|
-
|
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
|
+
|
7
15
|
def super_method(object, method_name, *args)
|
8
16
|
object.superclass.send(method_name, *args) if object.superclass.respond_to?(method_name)
|
9
17
|
end
|
@@ -35,6 +43,11 @@ module SmoothOperator
|
|
35
43
|
end
|
36
44
|
end
|
37
45
|
|
46
|
+
def plural?(string)
|
47
|
+
string = string.to_s
|
48
|
+
string == string.pluralize
|
49
|
+
end
|
50
|
+
|
38
51
|
def duplicate(object)
|
39
52
|
object.dup rescue object
|
40
53
|
end
|
@@ -61,7 +74,6 @@ module SmoothOperator
|
|
61
74
|
def remove_initial_slash(string)
|
62
75
|
string[1..-1]
|
63
76
|
end
|
64
|
-
|
77
|
+
|
65
78
|
end
|
66
|
-
|
67
79
|
end
|
@@ -1,22 +1,24 @@
|
|
1
1
|
module SmoothOperator
|
2
|
-
|
3
2
|
module ModelSchema
|
4
3
|
|
5
4
|
def self.included(base)
|
6
5
|
base.extend(ClassMethods)
|
7
6
|
end
|
8
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
|
+
|
9
16
|
def known_attributes
|
10
17
|
@known_attributes ||= self.class.known_attributes.dup
|
11
18
|
end
|
12
19
|
|
13
|
-
def internal_structure
|
14
|
-
@internal_structure ||= self.class.internal_structure.dup
|
15
|
-
end
|
16
|
-
|
17
|
-
|
18
20
|
module ClassMethods
|
19
|
-
|
21
|
+
|
20
22
|
def resources_name(default_bypass = nil)
|
21
23
|
return @resources_name if defined?(@resources_name)
|
22
24
|
|
@@ -58,7 +60,6 @@ module SmoothOperator
|
|
58
60
|
def model_name=(name)
|
59
61
|
@_model_name = name
|
60
62
|
end
|
61
|
-
|
62
63
|
|
63
64
|
protected ############## PROTECTED #############
|
64
65
|
|
@@ -77,5 +78,4 @@ module SmoothOperator
|
|
77
78
|
end
|
78
79
|
|
79
80
|
end
|
80
|
-
|
81
81
|
end
|
@@ -2,6 +2,7 @@ require "smooth_operator/delegation"
|
|
2
2
|
require "smooth_operator/validations"
|
3
3
|
require "smooth_operator/model_schema"
|
4
4
|
require "smooth_operator/serialization"
|
5
|
+
require "smooth_operator/attribute_methods"
|
5
6
|
require "smooth_operator/attribute_assignment"
|
6
7
|
|
7
8
|
module SmoothOperator
|
@@ -13,6 +14,7 @@ module SmoothOperator
|
|
13
14
|
include Validations
|
14
15
|
include ModelSchema
|
15
16
|
include Serialization
|
17
|
+
include AttributeMethods
|
16
18
|
include AttributeAssignment
|
17
19
|
|
18
20
|
def self.strict_behaviour=(value)
|
@@ -28,7 +30,7 @@ module SmoothOperator
|
|
28
30
|
class Dirty < Base
|
29
31
|
|
30
32
|
dirty_attributes
|
31
|
-
|
33
|
+
|
32
34
|
end
|
33
35
|
|
34
36
|
end
|
@@ -5,18 +5,17 @@ require "smooth_operator/remote_call/errors/timeout"
|
|
5
5
|
require "smooth_operator/remote_call/errors/connection_failed"
|
6
6
|
|
7
7
|
module SmoothOperator
|
8
|
-
|
9
8
|
module Operator
|
10
9
|
|
11
10
|
def make_the_call(http_verb, relative_path = '', data = {}, options = {})
|
12
11
|
options ||= {}
|
13
|
-
|
12
|
+
|
14
13
|
relative_path = resource_path(relative_path)
|
15
|
-
|
14
|
+
|
16
15
|
if !parent_object.nil? && options[:ignore_parent] != true
|
17
16
|
options[:resources_name] ||= "#{parent_object.class.resources_name}/#{parent_object.get_primary_key}/#{self.class.resources_name}"
|
18
17
|
end
|
19
|
-
|
18
|
+
|
20
19
|
self.class.make_the_call(http_verb, relative_path, data, options) do |remote_call|
|
21
20
|
yield(remote_call)
|
22
21
|
end
|
@@ -34,13 +33,12 @@ module SmoothOperator
|
|
34
33
|
end
|
35
34
|
end
|
36
35
|
|
37
|
-
|
38
36
|
########################### MODULES BELLOW ###############################
|
39
37
|
|
40
38
|
module HttpMethods
|
41
39
|
|
42
40
|
HTTP_VERBS = %w[get post put patch delete]
|
43
|
-
|
41
|
+
|
44
42
|
HTTP_VERBS.each do |method|
|
45
43
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
46
44
|
def #{method}(relative_path = '', params = {}, options = {})
|
@@ -78,7 +76,7 @@ module SmoothOperator
|
|
78
76
|
else
|
79
77
|
operator_call = Operators::Faraday
|
80
78
|
end
|
81
|
-
|
79
|
+
|
82
80
|
operator_call.make_the_call(*operator_args) do |remote_call|
|
83
81
|
block_given? ? yield(remote_call) : remote_call
|
84
82
|
end
|
@@ -88,7 +86,6 @@ module SmoothOperator
|
|
88
86
|
params
|
89
87
|
end
|
90
88
|
|
91
|
-
|
92
89
|
protected #################### PROTECTED ##################
|
93
90
|
|
94
91
|
def operator_method_args(http_verb, relative_path, data, options)
|
@@ -97,7 +94,6 @@ module SmoothOperator
|
|
97
94
|
[http_verb, resource_path(relative_path, options), *strip_params(http_verb, data), options]
|
98
95
|
end
|
99
96
|
|
100
|
-
|
101
97
|
private #################### PRIVATE ##################
|
102
98
|
|
103
99
|
def populate_options(options)
|
@@ -106,7 +102,7 @@ module SmoothOperator
|
|
106
102
|
OPTIONS.each { |option| options[option] ||= send(option) }
|
107
103
|
|
108
104
|
options[:headers] = headers.merge(options[:headers] || {})
|
109
|
-
|
105
|
+
|
110
106
|
options
|
111
107
|
end
|
112
108
|
|
@@ -122,17 +118,15 @@ module SmoothOperator
|
|
122
118
|
|
123
119
|
def strip_params(http_verb, data)
|
124
120
|
data ||= {}
|
125
|
-
|
121
|
+
|
126
122
|
if [:get, :head, :delete].include?(http_verb)
|
127
123
|
[query_string(data), nil]
|
128
124
|
else
|
129
125
|
[query_string({}), data]
|
130
126
|
end
|
131
127
|
end
|
132
|
-
|
133
128
|
end
|
134
129
|
|
135
|
-
|
136
130
|
include HttpMethods
|
137
131
|
|
138
132
|
def self.included(base)
|
@@ -1,5 +1,4 @@
|
|
1
1
|
module SmoothOperator
|
2
|
-
|
3
2
|
module Persistence
|
4
3
|
|
5
4
|
def self.included(base)
|
@@ -8,7 +7,6 @@ module SmoothOperator
|
|
8
7
|
|
9
8
|
attr_reader :last_remote_call
|
10
9
|
|
11
|
-
|
12
10
|
def get_primary_key
|
13
11
|
get_internal_data(self.class.primary_key)
|
14
12
|
end
|
@@ -27,6 +25,12 @@ module SmoothOperator
|
|
27
25
|
@new_record = Helpers.blank?(get_primary_key)
|
28
26
|
end
|
29
27
|
|
28
|
+
def marked_for_destruction?(bypass_cache = false)
|
29
|
+
return @marked_for_destruction if !bypass_cache && defined?(@marked_for_destruction)
|
30
|
+
|
31
|
+
@marked_for_destruction = ["true", "1", true].include?(get_internal_data(self.class.destroy_key))
|
32
|
+
end
|
33
|
+
|
30
34
|
def destroyed?
|
31
35
|
return @destroyed if defined?(@destroyed)
|
32
36
|
|
@@ -105,32 +109,36 @@ module SmoothOperator
|
|
105
109
|
|
106
110
|
{ self.class.resource_name => hash }.merge(data)
|
107
111
|
end
|
108
|
-
|
109
|
-
|
112
|
+
|
113
|
+
|
110
114
|
module ClassMethods
|
111
|
-
|
115
|
+
|
112
116
|
METHODS_VS_HTTP_VERBS = { reload: :get, create: :post, update: :put, destroy: :delete }
|
113
|
-
|
117
|
+
|
114
118
|
def methods_vs_http_verbs
|
115
119
|
Helpers.get_instance_variable(self, :methods_vs_http_verbs, METHODS_VS_HTTP_VERBS.dup)
|
116
120
|
end
|
117
|
-
|
121
|
+
|
118
122
|
def primary_key
|
119
123
|
Helpers.get_instance_variable(self, :primary_key, 'id')
|
120
124
|
end
|
121
125
|
|
122
126
|
attr_writer :primary_key
|
123
127
|
|
128
|
+
def destroy_key
|
129
|
+
Helpers.get_instance_variable(self, :destroy_key, '_destroy')
|
130
|
+
end
|
131
|
+
|
132
|
+
attr_writer :destroy_key
|
133
|
+
|
124
134
|
METHODS_VS_HTTP_VERBS.keys.each do |method|
|
125
135
|
define_method("#{method}_http_verb=") { |http_verb| methods_vs_http_verbs[method] = http_verb }
|
126
136
|
end
|
127
|
-
|
137
|
+
|
128
138
|
def create(attributes = nil, relative_path = nil, data = {}, options = {})
|
129
139
|
new(attributes).tap { |object| object.save(relative_path, data, options) }
|
130
140
|
end
|
131
|
-
|
132
|
-
end
|
133
141
|
|
142
|
+
end
|
134
143
|
end
|
135
|
-
|
136
144
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module SmoothOperator
|
2
|
+
module Relation
|
3
|
+
class ArrayRelation < ::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 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
|
+
def get_array
|
44
|
+
data = object.get_internal_data(association.to_s)
|
45
|
+
|
46
|
+
data.nil? ? [] : [*data]
|
47
|
+
end
|
48
|
+
|
49
|
+
def refresh
|
50
|
+
__setobj__ get_array
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require "smooth_operator/relation/reflection"
|
2
|
+
|
3
|
+
module SmoothOperator
|
4
|
+
module Relation
|
5
|
+
class AssociationReflection < Reflection
|
6
|
+
|
7
|
+
attr_reader :related_reflection, :macro
|
8
|
+
|
9
|
+
def initialize(association, related_reflection, options)
|
10
|
+
super(association, options)
|
11
|
+
@macro = options[:macro] || macro_default(association)
|
12
|
+
@related_reflection = related_reflection
|
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
|
+
private ################################# private
|
64
|
+
|
65
|
+
def macro_default(association)
|
66
|
+
Helpers.plural?(association) ? :has_many : :belongs_to
|
67
|
+
end
|
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
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require "smooth_operator/relation/array_relation"
|
2
|
+
require "smooth_operator/relation/association_reflection"
|
3
|
+
|
4
|
+
module SmoothOperator
|
5
|
+
module Relation
|
6
|
+
module Associations
|
7
|
+
|
8
|
+
def has_many(nested_object_name, options = {})
|
9
|
+
accepts_nested_objects(nested_object_name, :has_many, options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def has_one(nested_object_name, options = {})
|
13
|
+
accepts_nested_objects(nested_object_name, :has_one, options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def belongs_to(nested_object_name, options = {})
|
17
|
+
accepts_nested_objects(nested_object_name, :belongs_to, options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def reflections
|
21
|
+
Helpers.get_instance_variable(self, :reflections, {})
|
22
|
+
end
|
23
|
+
|
24
|
+
def reflect_on_association(association)
|
25
|
+
reflections[association]
|
26
|
+
end
|
27
|
+
|
28
|
+
def reflect_on_all_associations(macro = nil)
|
29
|
+
macro ? reflections.values.select { |reflection| reflection.macro == macro } : reflections.values
|
30
|
+
end
|
31
|
+
|
32
|
+
protected ###################### PROTECTED ###################
|
33
|
+
|
34
|
+
def accepts_nested_objects(association, macro, options = {})
|
35
|
+
options = parse_options(options, { macro: macro })
|
36
|
+
|
37
|
+
reflection = AssociationReflection.new(association, Reflection.new(name, {}), options)
|
38
|
+
|
39
|
+
schema(association => reflection.klass)
|
40
|
+
|
41
|
+
reflections.merge!(association => reflection)
|
42
|
+
|
43
|
+
if reflection.has_many?
|
44
|
+
define_has_many_association_method(reflection, association)
|
45
|
+
else
|
46
|
+
define_single_association_method(reflection, association)
|
47
|
+
end
|
48
|
+
|
49
|
+
self.send(:attr_reader, "#{association}_attributes".to_sym)
|
50
|
+
|
51
|
+
define_attributes_setter_methods(reflection, association)
|
52
|
+
end
|
53
|
+
|
54
|
+
private ####################### PRIVATE ######################
|
55
|
+
|
56
|
+
def define_has_many_association_method(reflection, association)
|
57
|
+
define_method(association) do
|
58
|
+
array_relation = instance_variable_get("@#{association}")
|
59
|
+
|
60
|
+
if array_relation.nil?
|
61
|
+
array_relation = ArrayRelation.new(self, association)
|
62
|
+
|
63
|
+
instance_variable_set("@#{association}", array_relation)
|
64
|
+
end
|
65
|
+
|
66
|
+
array_relation.send(:refresh)
|
67
|
+
|
68
|
+
array_relation
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def define_single_association_method(reflection, association)
|
73
|
+
define_method(association) { get_internal_data(association.to_s) }
|
74
|
+
|
75
|
+
define_method("build_#{association}") do |attributes = {}|
|
76
|
+
new_instance = reflection.klass.new(attributes)
|
77
|
+
|
78
|
+
push_to_internal_data(association, new_instance)
|
79
|
+
|
80
|
+
new_instance
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def define_attributes_setter_methods(reflection, association)
|
85
|
+
define_method("#{association}_attributes=") do |attributes|
|
86
|
+
instance_variable_set("@#{association}_attributes", attributes)
|
87
|
+
|
88
|
+
attributes = attributes.values if reflection.has_many?
|
89
|
+
|
90
|
+
push_to_internal_data(association.to_s, attributes)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def parse_options(options, default_options)
|
95
|
+
options = options.is_a?(Hash) ? options.merge(default_options) : default_options
|
96
|
+
|
97
|
+
Helpers.symbolyze_keys(options)
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module SmoothOperator
|
2
|
+
module Relation
|
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
|
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
|
@@ -14,7 +14,6 @@ module SmoothOperator
|
|
14
14
|
@response = response
|
15
15
|
end
|
16
16
|
|
17
|
-
|
18
17
|
def ok?
|
19
18
|
http_status.between?(200, 299) || http_status == 304
|
20
19
|
end
|
@@ -35,7 +34,6 @@ module SmoothOperator
|
|
35
34
|
http_status.between?(500, 599) || http_status == 0
|
36
35
|
end
|
37
36
|
|
38
|
-
|
39
37
|
def not_found?
|
40
38
|
http_status == 404
|
41
39
|
end
|
@@ -48,12 +46,11 @@ module SmoothOperator
|
|
48
46
|
false
|
49
47
|
end
|
50
48
|
|
51
|
-
|
52
49
|
def parsed_response
|
53
50
|
return nil if body.nil?
|
54
|
-
|
51
|
+
|
55
52
|
require 'json' unless defined? JSON
|
56
|
-
|
53
|
+
|
57
54
|
begin
|
58
55
|
JSON.parse(body)
|
59
56
|
rescue JSON::ParserError
|
@@ -74,7 +71,5 @@ module SmoothOperator
|
|
74
71
|
end
|
75
72
|
|
76
73
|
end
|
77
|
-
|
78
74
|
end
|
79
|
-
|
80
75
|
end
|
@@ -1,27 +1,24 @@
|
|
1
1
|
module SmoothOperator
|
2
|
-
|
3
2
|
module Translation
|
4
3
|
|
5
4
|
def human_attribute_name(attribute_key_name, options = {})
|
6
5
|
_translate("attributes.#{model_name.i18n_key}.#{attribute_key_name}", options = {})
|
7
6
|
end
|
8
7
|
|
9
|
-
|
10
8
|
private ###################### PRIVATE #########################
|
11
9
|
|
12
10
|
def _translate(namespace = '', options = {})
|
13
11
|
no_translation = "-- no translation --"
|
14
|
-
|
12
|
+
|
15
13
|
defaults = ["smooth_operator.#{namespace}".to_sym]
|
16
14
|
defaults << "activerecord.#{namespace}".to_sym
|
17
15
|
defaults << options[:default] if options[:default]
|
18
16
|
defaults.flatten!
|
19
17
|
defaults << no_translation
|
20
|
-
|
18
|
+
|
21
19
|
options = { count: 1, default: defaults }.merge!(options.except(:default))
|
22
20
|
I18n.translate(defaults.shift, options)
|
23
21
|
end
|
24
22
|
|
25
23
|
end
|
26
|
-
|
27
24
|
end
|
data/lib/smooth_operator.rb
CHANGED
@@ -5,11 +5,13 @@ require "smooth_operator/persistence"
|
|
5
5
|
require "smooth_operator/translation"
|
6
6
|
require "smooth_operator/open_struct"
|
7
7
|
require "smooth_operator/finder_methods"
|
8
|
+
require "smooth_operator/relation/associations"
|
8
9
|
|
9
10
|
module SmoothOperator
|
10
11
|
class Base < OpenStruct::Base
|
11
12
|
|
12
13
|
extend FinderMethods
|
14
|
+
extend Relation::Associations
|
13
15
|
extend Translation if defined? I18n
|
14
16
|
|
15
17
|
include Operator
|
@@ -23,4 +25,20 @@ module SmoothOperator
|
|
23
25
|
end
|
24
26
|
|
25
27
|
end
|
28
|
+
|
29
|
+
if defined?(ActiveModel)
|
30
|
+
class Rails < Base
|
31
|
+
|
32
|
+
include ActiveModel::Validations
|
33
|
+
include ActiveModel::Validations::Callbacks
|
34
|
+
include ActiveModel::Conversion
|
35
|
+
|
36
|
+
def column_for_attribute(attribute_name)
|
37
|
+
type = get_attribute_type(attribute_name)
|
38
|
+
|
39
|
+
ActiveRecord::ConnectionAdapters::Column.new(attribute_name.to_sym, type, type)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
26
44
|
end
|
data/smooth_operator.gemspec
CHANGED
@@ -20,12 +20,12 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
21
21
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
22
22
|
spec.require_paths = ["lib"]
|
23
|
-
|
23
|
+
|
24
24
|
spec.add_development_dependency "bundler", "~> 1.3"
|
25
|
-
|
26
|
-
spec.add_dependency "json"
|
27
|
-
spec.add_dependency "faraday", "~> 0.8
|
28
|
-
spec.add_dependency "typhoeus", "~> 0.6
|
25
|
+
|
26
|
+
spec.add_dependency "json", '~> 1.8'
|
27
|
+
spec.add_dependency "faraday", "~> 0.8"
|
28
|
+
spec.add_dependency "typhoeus", "~> 0.6"
|
29
29
|
|
30
30
|
# this is necessary if you want to typhoeus to correctly encode arrays
|
31
31
|
# spec.add_dependency "ethon", :git => 'https://github.com/goncalvesjoao/ethon'
|
@@ -4,7 +4,7 @@ require "spec_helper"
|
|
4
4
|
describe SmoothOperator::AttributeAssignment do
|
5
5
|
|
6
6
|
describe "#assign_attributes" do
|
7
|
-
|
7
|
+
|
8
8
|
describe "receiving data from server" do
|
9
9
|
subject { User::Base.new }
|
10
10
|
|
@@ -70,7 +70,7 @@ describe SmoothOperator::AttributeAssignment do
|
|
70
70
|
end
|
71
71
|
|
72
72
|
context "when one of the attribute's value, is an hash and is unknown to the schema" do
|
73
|
-
context "when the .unknown_hash_class is unused" do
|
73
|
+
context "when the .unknown_hash_class is unused", current: true do
|
74
74
|
subject { User::Base.new(address: { street: 'something', postal_code: { code: '123' } }) }
|
75
75
|
|
76
76
|
it "a new instance of OpenStruct will be initialized with that hash" do
|
@@ -83,7 +83,7 @@ describe SmoothOperator::AttributeAssignment do
|
|
83
83
|
expect(address.postal_code.code).to eq('123')
|
84
84
|
end
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
context "when the .unknown_hash_class is set to SmoothOperator::OpenStruct::Base" do
|
88
88
|
subject { User::UnknownHashClass::OpenStructBase.new(address: { street: 'something', postal_code: { code: '123' } }) }
|
89
89
|
|
@@ -246,7 +246,7 @@ describe SmoothOperator::AttributeAssignment do
|
|
246
246
|
it "when the attributes's value is 'false', should be converted to false" do
|
247
247
|
expect(subject.new(manager: 'false').manager).to be(false)
|
248
248
|
end
|
249
|
-
|
249
|
+
|
250
250
|
it "when the attributes's value is '1', should be converted to true" do
|
251
251
|
expect(subject.new(manager: '1').manager).to be(true)
|
252
252
|
end
|
@@ -264,7 +264,7 @@ describe SmoothOperator::AttributeAssignment do
|
|
264
264
|
end
|
265
265
|
|
266
266
|
end
|
267
|
-
|
267
|
+
|
268
268
|
context "that is declared (in schema) as an existing class" do
|
269
269
|
|
270
270
|
it "if the attribute's value is an hash a new instance of that class will be initialized with that hash" do
|
@@ -280,12 +280,12 @@ describe SmoothOperator::AttributeAssignment do
|
|
280
280
|
|
281
281
|
it "if the attribute's value is an array, a new instance of that class will be initialized for each array entry" do
|
282
282
|
posts = subject.new(posts: [{ body: 'post1' }, { body: 'post2' }]).posts
|
283
|
-
|
283
|
+
|
284
284
|
expect(posts.length).to be(2)
|
285
285
|
|
286
286
|
expect(posts[0]).to be_instance_of(Post)
|
287
287
|
expect(posts[0].body).to eq('post1')
|
288
|
-
|
288
|
+
|
289
289
|
expect(posts[1]).to be_instance_of(Post)
|
290
290
|
expect(posts[1].body).to eq('post2')
|
291
291
|
end
|
data/spec/support/models/post.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smooth_operator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.20.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- João Gonçalves
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-05-
|
11
|
+
date: 2014-05-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -28,44 +28,44 @@ dependencies:
|
|
28
28
|
name: json
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ~>
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '1.8'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ~>
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '1.8'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: faraday
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ~>
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 0.8
|
47
|
+
version: '0.8'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0.8
|
54
|
+
version: '0.8'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: typhoeus
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 0.6
|
61
|
+
version: '0.6'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - ~>
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 0.6
|
68
|
+
version: '0.6'
|
69
69
|
description: ActiveResource alternative
|
70
70
|
email:
|
71
71
|
- goncalves.joao@gmail.com
|
@@ -83,9 +83,11 @@ files:
|
|
83
83
|
- lib/smooth_operator.rb
|
84
84
|
- lib/smooth_operator/array_with_meta_data.rb
|
85
85
|
- lib/smooth_operator/attribute_assignment.rb
|
86
|
+
- lib/smooth_operator/attribute_methods.rb
|
86
87
|
- lib/smooth_operator/attributes/base.rb
|
87
88
|
- lib/smooth_operator/attributes/dirty.rb
|
88
89
|
- lib/smooth_operator/attributes/normal.rb
|
90
|
+
- lib/smooth_operator/blank_slate.rb
|
89
91
|
- lib/smooth_operator/delegation.rb
|
90
92
|
- lib/smooth_operator/finder_methods.rb
|
91
93
|
- lib/smooth_operator/helpers.rb
|
@@ -95,6 +97,10 @@ files:
|
|
95
97
|
- lib/smooth_operator/operators/faraday.rb
|
96
98
|
- lib/smooth_operator/operators/typhoeus.rb
|
97
99
|
- lib/smooth_operator/persistence.rb
|
100
|
+
- lib/smooth_operator/relation/array_relation.rb
|
101
|
+
- lib/smooth_operator/relation/association_reflection.rb
|
102
|
+
- lib/smooth_operator/relation/associations.rb
|
103
|
+
- lib/smooth_operator/relation/reflection.rb
|
98
104
|
- lib/smooth_operator/remote_call/base.rb
|
99
105
|
- lib/smooth_operator/remote_call/errors/connection_failed.rb
|
100
106
|
- lib/smooth_operator/remote_call/errors/timeout.rb
|
@@ -121,6 +127,7 @@ files:
|
|
121
127
|
- spec/support/helpers/persistence_helper.rb
|
122
128
|
- spec/support/localhost_server.rb
|
123
129
|
- spec/support/models/address.rb
|
130
|
+
- spec/support/models/comment.rb
|
124
131
|
- spec/support/models/post.rb
|
125
132
|
- spec/support/models/user.rb
|
126
133
|
- spec/support/models/user_with_address_and_posts.rb
|
@@ -145,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
145
152
|
version: '0'
|
146
153
|
requirements: []
|
147
154
|
rubyforge_project:
|
148
|
-
rubygems_version: 2.
|
155
|
+
rubygems_version: 2.2.2
|
149
156
|
signing_key:
|
150
157
|
specification_version: 4
|
151
158
|
summary: Simple and fully customizable alternative to ActiveResource, using faraday
|
@@ -167,6 +174,7 @@ test_files:
|
|
167
174
|
- spec/support/helpers/persistence_helper.rb
|
168
175
|
- spec/support/localhost_server.rb
|
169
176
|
- spec/support/models/address.rb
|
177
|
+
- spec/support/models/comment.rb
|
170
178
|
- spec/support/models/post.rb
|
171
179
|
- spec/support/models/user.rb
|
172
180
|
- spec/support/models/user_with_address_and_posts.rb
|