smooth_operator 1.2.9 → 1.3.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 +78 -22
- data/console.rb +2 -0
- data/lib/smooth_operator/array_with_meta_data.rb +20 -8
- data/lib/smooth_operator/{relation → associations}/association_reflection.rb +8 -8
- data/lib/smooth_operator/{relation/array_relation.rb → associations/has_many_relation.rb} +3 -13
- data/lib/smooth_operator/{relation → associations}/reflection.rb +2 -2
- data/lib/smooth_operator/associations.rb +110 -0
- data/lib/smooth_operator/attribute_assignment.rb +52 -60
- data/lib/smooth_operator/cookie_jar.rb +21 -0
- data/lib/smooth_operator/delegation.rb +13 -34
- data/lib/smooth_operator/finder_methods.rb +26 -17
- data/lib/smooth_operator/helpers.rb +14 -8
- data/lib/smooth_operator/http_methods.rb +17 -0
- data/lib/smooth_operator/internal_data.rb +45 -0
- data/lib/smooth_operator/open_struct.rb +11 -26
- data/lib/smooth_operator/operator.rb +65 -59
- data/lib/smooth_operator/operators/connection_wrapper.rb +15 -0
- data/lib/smooth_operator/operators/faraday.rb +6 -6
- data/lib/smooth_operator/operators/typhoeus.rb +22 -12
- data/lib/smooth_operator/options.rb +30 -0
- data/lib/smooth_operator/persistence.rb +64 -61
- data/lib/smooth_operator/remote_call/base.rb +7 -6
- data/lib/smooth_operator/resource_name.rb +46 -0
- data/lib/smooth_operator/schema.rb +21 -0
- data/lib/smooth_operator/serialization.rb +80 -36
- data/lib/smooth_operator/translation.rb +21 -12
- data/lib/smooth_operator/type_casting.rb +127 -0
- data/lib/smooth_operator/validations.rb +25 -3
- data/lib/smooth_operator/version.rb +1 -1
- data/lib/smooth_operator.rb +55 -5
- data/smooth_operator.gemspec +5 -5
- data/spec/smooth_operator/attribute_assignment_spec.rb +5 -14
- data/spec/smooth_operator/finder_methods_spec.rb +4 -9
- data/spec/smooth_operator/persistence_spec.rb +27 -19
- data/spec/smooth_operator/remote_call_spec.rb +104 -84
- data/spec/smooth_operator/{model_schema_spec.rb → resource_name_spec.rb} +1 -1
- data/spec/support/models/address.rb +8 -10
- data/spec/support/models/comment.rb +2 -0
- data/spec/support/models/post.rb +7 -7
- data/spec/support/models/user.rb +10 -13
- data/spec/support/models/user_with_address_and_posts.rb +9 -17
- data/spec/support/test_server.rb +7 -7
- metadata +25 -25
- data/lib/smooth_operator/attribute_methods.rb +0 -78
- 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/lib/smooth_operator/model_schema.rb +0 -81
- data/lib/smooth_operator/relation/associations.rb +0 -102
- data/spec/smooth_operator/attributes_dirty_spec.rb +0 -53
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.3.0
|
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-
|
11
|
+
date: 2014-07-22 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.5'
|
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.5'
|
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
|
@@ -82,45 +82,46 @@ files:
|
|
82
82
|
- console.rb
|
83
83
|
- lib/smooth_operator.rb
|
84
84
|
- lib/smooth_operator/array_with_meta_data.rb
|
85
|
+
- lib/smooth_operator/associations.rb
|
86
|
+
- lib/smooth_operator/associations/association_reflection.rb
|
87
|
+
- lib/smooth_operator/associations/has_many_relation.rb
|
88
|
+
- lib/smooth_operator/associations/reflection.rb
|
85
89
|
- lib/smooth_operator/attribute_assignment.rb
|
86
|
-
- lib/smooth_operator/
|
87
|
-
- lib/smooth_operator/attributes/base.rb
|
88
|
-
- lib/smooth_operator/attributes/dirty.rb
|
89
|
-
- lib/smooth_operator/attributes/normal.rb
|
90
|
-
- lib/smooth_operator/blank_slate.rb
|
90
|
+
- lib/smooth_operator/cookie_jar.rb
|
91
91
|
- lib/smooth_operator/delegation.rb
|
92
92
|
- lib/smooth_operator/finder_methods.rb
|
93
93
|
- lib/smooth_operator/helpers.rb
|
94
|
-
- lib/smooth_operator/
|
94
|
+
- lib/smooth_operator/http_methods.rb
|
95
|
+
- lib/smooth_operator/internal_data.rb
|
95
96
|
- lib/smooth_operator/open_struct.rb
|
96
97
|
- lib/smooth_operator/operator.rb
|
98
|
+
- lib/smooth_operator/operators/connection_wrapper.rb
|
97
99
|
- lib/smooth_operator/operators/faraday.rb
|
98
100
|
- lib/smooth_operator/operators/typhoeus.rb
|
101
|
+
- lib/smooth_operator/options.rb
|
99
102
|
- 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
|
104
103
|
- lib/smooth_operator/remote_call/base.rb
|
105
104
|
- lib/smooth_operator/remote_call/errors/connection_failed.rb
|
106
105
|
- lib/smooth_operator/remote_call/errors/timeout.rb
|
107
106
|
- lib/smooth_operator/remote_call/faraday.rb
|
108
107
|
- lib/smooth_operator/remote_call/typhoeus.rb
|
108
|
+
- lib/smooth_operator/resource_name.rb
|
109
|
+
- lib/smooth_operator/schema.rb
|
109
110
|
- lib/smooth_operator/serialization.rb
|
110
111
|
- lib/smooth_operator/translation.rb
|
112
|
+
- lib/smooth_operator/type_casting.rb
|
111
113
|
- lib/smooth_operator/validations.rb
|
112
114
|
- lib/smooth_operator/version.rb
|
113
115
|
- smooth_operator.gemspec
|
114
116
|
- spec/factories/user_factory.rb
|
115
117
|
- spec/require_helper.rb
|
116
118
|
- spec/smooth_operator/attribute_assignment_spec.rb
|
117
|
-
- spec/smooth_operator/attributes_dirty_spec.rb
|
118
119
|
- spec/smooth_operator/delegation_spec.rb
|
119
120
|
- spec/smooth_operator/finder_methods_spec.rb
|
120
|
-
- spec/smooth_operator/model_schema_spec.rb
|
121
121
|
- spec/smooth_operator/operator_spec.rb
|
122
122
|
- spec/smooth_operator/persistence_spec.rb
|
123
123
|
- spec/smooth_operator/remote_call_spec.rb
|
124
|
+
- spec/smooth_operator/resource_name_spec.rb
|
124
125
|
- spec/smooth_operator/serialization_spec.rb
|
125
126
|
- spec/smooth_operator/validations_spec.rb
|
126
127
|
- spec/spec_helper.rb
|
@@ -152,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
152
153
|
version: '0'
|
153
154
|
requirements: []
|
154
155
|
rubyforge_project:
|
155
|
-
rubygems_version: 2.
|
156
|
+
rubygems_version: 2.2.2
|
156
157
|
signing_key:
|
157
158
|
specification_version: 4
|
158
159
|
summary: Simple and fully customizable alternative to ActiveResource, using faraday
|
@@ -161,13 +162,12 @@ test_files:
|
|
161
162
|
- spec/factories/user_factory.rb
|
162
163
|
- spec/require_helper.rb
|
163
164
|
- spec/smooth_operator/attribute_assignment_spec.rb
|
164
|
-
- spec/smooth_operator/attributes_dirty_spec.rb
|
165
165
|
- spec/smooth_operator/delegation_spec.rb
|
166
166
|
- spec/smooth_operator/finder_methods_spec.rb
|
167
|
-
- spec/smooth_operator/model_schema_spec.rb
|
168
167
|
- spec/smooth_operator/operator_spec.rb
|
169
168
|
- spec/smooth_operator/persistence_spec.rb
|
170
169
|
- spec/smooth_operator/remote_call_spec.rb
|
170
|
+
- spec/smooth_operator/resource_name_spec.rb
|
171
171
|
- spec/smooth_operator/serialization_spec.rb
|
172
172
|
- spec/smooth_operator/validations_spec.rb
|
173
173
|
- spec/spec_helper.rb
|
@@ -1,78 +0,0 @@
|
|
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
|
@@ -1,107 +0,0 @@
|
|
1
|
-
module SmoothOperator
|
2
|
-
module Attributes
|
3
|
-
|
4
|
-
class Base
|
5
|
-
|
6
|
-
protected ##################### PROTECTED ########################
|
7
|
-
|
8
|
-
def cast_to_type(name, value, 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
|
-
|
11
|
-
return Helpers.duplicate(value) if known_by_schema && type.nil?
|
12
|
-
|
13
|
-
case value
|
14
|
-
when Array
|
15
|
-
value.map { |array_entry| self.class.new(name, array_entry, parent_object).value }
|
16
|
-
when Hash
|
17
|
-
type.nil? ? new_unknown_hash(value, unknown_hash_class, parent_object) : type.new(value, parent_object: parent_object)
|
18
|
-
else
|
19
|
-
convert(value, type)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def convert(value, type)
|
24
|
-
case type
|
25
|
-
|
26
|
-
when :string, :text, String
|
27
|
-
value.to_s
|
28
|
-
|
29
|
-
when :int, :integer, Integer, Fixnum
|
30
|
-
to_int(value)
|
31
|
-
|
32
|
-
when :date, Date
|
33
|
-
to_date(value)
|
34
|
-
|
35
|
-
when :float, Float
|
36
|
-
to_float(value)
|
37
|
-
|
38
|
-
when :bool, :boolean
|
39
|
-
to_boolean(value)
|
40
|
-
|
41
|
-
when :datetime, :date_time, DateTime
|
42
|
-
to_datetime(value)
|
43
|
-
|
44
|
-
else
|
45
|
-
Helpers.duplicate(value)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def to_date(string)
|
50
|
-
return string if string.is_a?(Date)
|
51
|
-
|
52
|
-
Date.parse(string) rescue nil
|
53
|
-
end
|
54
|
-
|
55
|
-
def to_datetime(string)
|
56
|
-
return string if string.is_a?(DateTime)
|
57
|
-
|
58
|
-
DateTime.parse(string) rescue nil
|
59
|
-
end
|
60
|
-
|
61
|
-
def to_boolean(string)
|
62
|
-
value = string.to_s.downcase
|
63
|
-
|
64
|
-
['1', 'true'].include?(value) ? true : ['0', 'false'].include?(value) ? false : nil
|
65
|
-
end
|
66
|
-
|
67
|
-
def to_int(string)
|
68
|
-
return string if string.is_a?(Fixnum)
|
69
|
-
|
70
|
-
to_float(string).to_i
|
71
|
-
end
|
72
|
-
|
73
|
-
def to_float(string)
|
74
|
-
return string if string.is_a?(Float)
|
75
|
-
|
76
|
-
return 0 if string.nil? || !(string.is_a?(String) || string.is_a?(Fixnum))
|
77
|
-
|
78
|
-
value = string.to_s.gsub(',', '.').scan(/-*\d+[.]*\d*/).flatten.map(&:to_f).first
|
79
|
-
|
80
|
-
value.nil? ? 0 : value
|
81
|
-
end
|
82
|
-
|
83
|
-
def new_unknown_hash(hash, unknown_hash_class, parent_object)
|
84
|
-
if unknown_hash_class == :none
|
85
|
-
hash
|
86
|
-
else
|
87
|
-
unknown_hash_class.new(cast_params(hash, unknown_hash_class, parent_object))
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
|
92
|
-
private ################### PRIVATE #####################
|
93
|
-
|
94
|
-
def cast_params(attributes, unknown_hash_class, parent_object)
|
95
|
-
hash = {}
|
96
|
-
|
97
|
-
attributes.each do |key, value|
|
98
|
-
hash[key] = cast_to_type(key, value, parent_object)
|
99
|
-
end
|
100
|
-
|
101
|
-
hash
|
102
|
-
end
|
103
|
-
|
104
|
-
end
|
105
|
-
|
106
|
-
end
|
107
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
module SmoothOperator
|
2
|
-
module Attributes
|
3
|
-
|
4
|
-
class Dirty < Base
|
5
|
-
|
6
|
-
attr_reader :original_name, :original_value, :first_value, :value
|
7
|
-
|
8
|
-
def initialize(name, value, parent_object)
|
9
|
-
@original_name, @original_value = name, value
|
10
|
-
|
11
|
-
@first_value = set_value(value, parent_object)
|
12
|
-
end
|
13
|
-
|
14
|
-
def set_value(new_value, parent_object)
|
15
|
-
@value = cast_to_type(original_name, new_value, parent_object)
|
16
|
-
end
|
17
|
-
|
18
|
-
def changed?
|
19
|
-
@first_value != @value
|
20
|
-
end
|
21
|
-
|
22
|
-
def was
|
23
|
-
@first_value
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
end
|
29
|
-
end
|
@@ -1,81 +0,0 @@
|
|
1
|
-
module SmoothOperator
|
2
|
-
module ModelSchema
|
3
|
-
|
4
|
-
def self.included(base)
|
5
|
-
base.extend(ClassMethods)
|
6
|
-
end
|
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
|
-
|
16
|
-
def known_attributes
|
17
|
-
@known_attributes ||= self.class.known_attributes.dup
|
18
|
-
end
|
19
|
-
|
20
|
-
module ClassMethods
|
21
|
-
|
22
|
-
def resources_name(default_bypass = nil)
|
23
|
-
return @resources_name if defined?(@resources_name)
|
24
|
-
|
25
|
-
(Helpers.super_method(self, :resources_name, true) || (default_bypass ? nil : self.resource_name.pluralize))
|
26
|
-
end
|
27
|
-
attr_writer :resources_name
|
28
|
-
|
29
|
-
def resource_name(default_bypass = nil)
|
30
|
-
return @resource_name if defined?(@resource_name)
|
31
|
-
|
32
|
-
(Helpers.super_method(self, :resource_name, true) || (default_bypass ? nil : self.model_name.to_s.underscore))
|
33
|
-
end
|
34
|
-
attr_writer :resource_name
|
35
|
-
|
36
|
-
def schema(structure)
|
37
|
-
internal_structure.merge! Helpers.stringify_keys(structure)
|
38
|
-
|
39
|
-
known_attributes.merge internal_structure.keys
|
40
|
-
end
|
41
|
-
|
42
|
-
def internal_structure
|
43
|
-
Helpers.get_instance_variable(self, :internal_structure, { "errors" => nil })
|
44
|
-
end
|
45
|
-
|
46
|
-
def known_attributes
|
47
|
-
Helpers.get_instance_variable(self, :known_attributes, Set.new)
|
48
|
-
end
|
49
|
-
|
50
|
-
def model_name
|
51
|
-
return '' if @_model_name == :none
|
52
|
-
|
53
|
-
if defined? ActiveModel
|
54
|
-
rails_model_name_method
|
55
|
-
else
|
56
|
-
@_model_name ||= name.split('::').last.underscore.capitalize
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def model_name=(name)
|
61
|
-
@_model_name = name
|
62
|
-
end
|
63
|
-
|
64
|
-
protected ############## PROTECTED #############
|
65
|
-
|
66
|
-
def rails_model_name_method
|
67
|
-
@model_name ||= begin
|
68
|
-
namespace ||= self.parents.detect do |n|
|
69
|
-
n.respond_to?(:use_relative_model_naming?) && n.use_relative_model_naming?
|
70
|
-
end
|
71
|
-
|
72
|
-
ActiveModel::Name.new(self, namespace, @_model_name).tap do |model_name|
|
73
|
-
def model_name.human(options = {}); @klass.send(:_translate, "models.#{i18n_key}", options); end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
end
|
79
|
-
|
80
|
-
end
|
81
|
-
end
|
@@ -1,102 +0,0 @@
|
|
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
|
@@ -1,53 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe SmoothOperator::Attributes::Dirty do
|
4
|
-
|
5
|
-
subject { UserWithAddressAndPosts::DirtyAttributes.new(attributes_for(:user_with_address_and_posts)) }
|
6
|
-
|
7
|
-
context "when no changes are made to an attribute" do
|
8
|
-
it "checking if that attribute is changed, should return false" do
|
9
|
-
expect(subject.first_name_changed?).to be false
|
10
|
-
end
|
11
|
-
|
12
|
-
it "checking that attribute past value, should its original value" do
|
13
|
-
expect(subject.first_name_was).to eq('John')
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
context "when there are changes made to an attribute" do
|
18
|
-
before { subject.first_name = 'nhoJ' }
|
19
|
-
|
20
|
-
it "checking if that attribute is changed, should return true" do
|
21
|
-
expect(subject.first_name_changed?).to be true
|
22
|
-
end
|
23
|
-
|
24
|
-
it "checking that attribute past value, should its original value" do
|
25
|
-
expect(subject.first_name_was).to eq('John')
|
26
|
-
end
|
27
|
-
|
28
|
-
context "when there are changes to the changes made to an attribute" do
|
29
|
-
before { subject.first_name = 'no_name' }
|
30
|
-
|
31
|
-
it "checking if that attribute is changed, should return true" do
|
32
|
-
expect(subject.first_name_changed?).to be true
|
33
|
-
end
|
34
|
-
|
35
|
-
it "checking that attribute past value, should its first original value" do
|
36
|
-
expect(subject.first_name_was).to eq('John')
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
context "when there are changes made to a nested object" do
|
42
|
-
before { subject.address.street = 'my street' }
|
43
|
-
|
44
|
-
it "checking if the nested object as changed, should return false" do
|
45
|
-
expect(subject.address_changed?).to be false
|
46
|
-
end
|
47
|
-
|
48
|
-
it "checking if the nested object's attribute as changed, should return true" do
|
49
|
-
expect(subject.address.street_changed?).to be true
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|