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.
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