smooth_operator 1.2.9 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +8 -8
  2. data/README.md +78 -22
  3. data/console.rb +2 -0
  4. data/lib/smooth_operator/array_with_meta_data.rb +20 -8
  5. data/lib/smooth_operator/{relation → associations}/association_reflection.rb +8 -8
  6. data/lib/smooth_operator/{relation/array_relation.rb → associations/has_many_relation.rb} +3 -13
  7. data/lib/smooth_operator/{relation → associations}/reflection.rb +2 -2
  8. data/lib/smooth_operator/associations.rb +110 -0
  9. data/lib/smooth_operator/attribute_assignment.rb +52 -60
  10. data/lib/smooth_operator/cookie_jar.rb +21 -0
  11. data/lib/smooth_operator/delegation.rb +13 -34
  12. data/lib/smooth_operator/finder_methods.rb +26 -17
  13. data/lib/smooth_operator/helpers.rb +14 -8
  14. data/lib/smooth_operator/http_methods.rb +17 -0
  15. data/lib/smooth_operator/internal_data.rb +45 -0
  16. data/lib/smooth_operator/open_struct.rb +11 -26
  17. data/lib/smooth_operator/operator.rb +65 -59
  18. data/lib/smooth_operator/operators/connection_wrapper.rb +15 -0
  19. data/lib/smooth_operator/operators/faraday.rb +6 -6
  20. data/lib/smooth_operator/operators/typhoeus.rb +22 -12
  21. data/lib/smooth_operator/options.rb +30 -0
  22. data/lib/smooth_operator/persistence.rb +64 -61
  23. data/lib/smooth_operator/remote_call/base.rb +7 -6
  24. data/lib/smooth_operator/resource_name.rb +46 -0
  25. data/lib/smooth_operator/schema.rb +21 -0
  26. data/lib/smooth_operator/serialization.rb +80 -36
  27. data/lib/smooth_operator/translation.rb +21 -12
  28. data/lib/smooth_operator/type_casting.rb +127 -0
  29. data/lib/smooth_operator/validations.rb +25 -3
  30. data/lib/smooth_operator/version.rb +1 -1
  31. data/lib/smooth_operator.rb +55 -5
  32. data/smooth_operator.gemspec +5 -5
  33. data/spec/smooth_operator/attribute_assignment_spec.rb +5 -14
  34. data/spec/smooth_operator/finder_methods_spec.rb +4 -9
  35. data/spec/smooth_operator/persistence_spec.rb +27 -19
  36. data/spec/smooth_operator/remote_call_spec.rb +104 -84
  37. data/spec/smooth_operator/{model_schema_spec.rb → resource_name_spec.rb} +1 -1
  38. data/spec/support/models/address.rb +8 -10
  39. data/spec/support/models/comment.rb +2 -0
  40. data/spec/support/models/post.rb +7 -7
  41. data/spec/support/models/user.rb +10 -13
  42. data/spec/support/models/user_with_address_and_posts.rb +9 -17
  43. data/spec/support/test_server.rb +7 -7
  44. metadata +25 -25
  45. data/lib/smooth_operator/attribute_methods.rb +0 -78
  46. data/lib/smooth_operator/attributes/base.rb +0 -107
  47. data/lib/smooth_operator/attributes/dirty.rb +0 -29
  48. data/lib/smooth_operator/attributes/normal.rb +0 -15
  49. data/lib/smooth_operator/blank_slate.rb +0 -7
  50. data/lib/smooth_operator/model_schema.rb +0 -81
  51. data/lib/smooth_operator/relation/associations.rb +0 -102
  52. 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.2.9
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-05-30 00:00:00.000000000 Z
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: '0'
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: '0'
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.9
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.9
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.8
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.8
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/attribute_methods.rb
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/model_schema.rb
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.1.10
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,15 +0,0 @@
1
- module SmoothOperator
2
- module Attributes
3
-
4
- class Normal < Base
5
-
6
- attr_reader :value
7
-
8
- def initialize(name, value, parent_object)
9
- @value = cast_to_type(name, value, parent_object)
10
- end
11
-
12
- end
13
-
14
- end
15
- end
@@ -1,7 +0,0 @@
1
- # THANKS tdantas! https://github.com/tdantas
2
-
3
- module SmoothOperator
4
- class BlankSlate
5
- instance_methods.each { |m| undef_method m unless m =~ /^__|object_id/ }
6
- end
7
- 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