active_data 0.3.0 → 1.0.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 (142) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.rspec +0 -1
  4. data/.rvmrc +1 -1
  5. data/.travis.yml +13 -6
  6. data/Appraisals +7 -0
  7. data/Gemfile +1 -5
  8. data/Guardfile +68 -15
  9. data/README.md +144 -2
  10. data/active_data.gemspec +19 -11
  11. data/gemfiles/rails.4.0.gemfile +14 -0
  12. data/gemfiles/rails.4.1.gemfile +14 -0
  13. data/gemfiles/rails.4.2.gemfile +14 -0
  14. data/gemfiles/rails.5.0.gemfile +14 -0
  15. data/lib/active_data.rb +120 -3
  16. data/lib/active_data/active_record/associations.rb +50 -0
  17. data/lib/active_data/active_record/nested_attributes.rb +24 -0
  18. data/lib/active_data/config.rb +40 -0
  19. data/lib/active_data/errors.rb +93 -0
  20. data/lib/active_data/extensions.rb +33 -0
  21. data/lib/active_data/model.rb +16 -74
  22. data/lib/active_data/model/associations.rb +84 -15
  23. data/lib/active_data/model/associations/base.rb +79 -0
  24. data/lib/active_data/model/associations/collection/embedded.rb +12 -0
  25. data/lib/active_data/model/associations/collection/proxy.rb +32 -0
  26. data/lib/active_data/model/associations/collection/referenced.rb +26 -0
  27. data/lib/active_data/model/associations/embeds_many.rb +124 -18
  28. data/lib/active_data/model/associations/embeds_one.rb +90 -15
  29. data/lib/active_data/model/associations/nested_attributes.rb +180 -0
  30. data/lib/active_data/model/associations/references_many.rb +96 -0
  31. data/lib/active_data/model/associations/references_one.rb +83 -0
  32. data/lib/active_data/model/associations/reflections/base.rb +100 -0
  33. data/lib/active_data/model/associations/reflections/embeds_many.rb +25 -0
  34. data/lib/active_data/model/associations/reflections/embeds_one.rb +49 -0
  35. data/lib/active_data/model/associations/reflections/reference_reflection.rb +45 -0
  36. data/lib/active_data/model/associations/reflections/references_many.rb +28 -0
  37. data/lib/active_data/model/associations/reflections/references_one.rb +28 -0
  38. data/lib/active_data/model/associations/validations.rb +63 -0
  39. data/lib/active_data/model/attributes.rb +247 -0
  40. data/lib/active_data/model/attributes/attribute.rb +73 -0
  41. data/lib/active_data/model/attributes/base.rb +116 -0
  42. data/lib/active_data/model/attributes/collection.rb +17 -0
  43. data/lib/active_data/model/attributes/dictionary.rb +26 -0
  44. data/lib/active_data/model/attributes/localized.rb +42 -0
  45. data/lib/active_data/model/attributes/reference_many.rb +21 -0
  46. data/lib/active_data/model/attributes/reference_one.rb +42 -0
  47. data/lib/active_data/model/attributes/reflections/attribute.rb +55 -0
  48. data/lib/active_data/model/attributes/reflections/base.rb +62 -0
  49. data/lib/active_data/model/attributes/reflections/collection.rb +10 -0
  50. data/lib/active_data/model/attributes/reflections/dictionary.rb +13 -0
  51. data/lib/active_data/model/attributes/reflections/localized.rb +43 -0
  52. data/lib/active_data/model/attributes/reflections/reference_many.rb +10 -0
  53. data/lib/active_data/model/attributes/reflections/reference_one.rb +58 -0
  54. data/lib/active_data/model/attributes/reflections/represents.rb +55 -0
  55. data/lib/active_data/model/attributes/represents.rb +64 -0
  56. data/lib/active_data/model/callbacks.rb +71 -0
  57. data/lib/active_data/model/conventions.rb +35 -0
  58. data/lib/active_data/model/dirty.rb +77 -0
  59. data/lib/active_data/model/lifecycle.rb +307 -0
  60. data/lib/active_data/model/localization.rb +21 -0
  61. data/lib/active_data/model/persistence.rb +57 -0
  62. data/lib/active_data/model/primary.rb +51 -0
  63. data/lib/active_data/model/scopes.rb +77 -0
  64. data/lib/active_data/model/validations.rb +27 -0
  65. data/lib/active_data/model/validations/associated.rb +19 -0
  66. data/lib/active_data/model/validations/nested.rb +39 -0
  67. data/lib/active_data/railtie.rb +7 -0
  68. data/lib/active_data/version.rb +1 -1
  69. data/spec/lib/active_data/active_record/associations_spec.rb +149 -0
  70. data/spec/lib/active_data/active_record/nested_attributes_spec.rb +16 -0
  71. data/spec/lib/active_data/config_spec.rb +44 -0
  72. data/spec/lib/active_data/model/associations/embeds_many_spec.rb +362 -52
  73. data/spec/lib/active_data/model/associations/embeds_one_spec.rb +250 -31
  74. data/spec/lib/active_data/model/associations/nested_attributes_spec.rb +23 -0
  75. data/spec/lib/active_data/model/associations/references_many_spec.rb +196 -0
  76. data/spec/lib/active_data/model/associations/references_one_spec.rb +134 -0
  77. data/spec/lib/active_data/model/associations/reflections/embeds_many_spec.rb +144 -0
  78. data/spec/lib/active_data/model/associations/reflections/embeds_one_spec.rb +116 -0
  79. data/spec/lib/active_data/model/associations/reflections/references_many_spec.rb +255 -0
  80. data/spec/lib/active_data/model/associations/reflections/references_one_spec.rb +208 -0
  81. data/spec/lib/active_data/model/associations/validations_spec.rb +153 -0
  82. data/spec/lib/active_data/model/associations_spec.rb +189 -0
  83. data/spec/lib/active_data/model/attributes/attribute_spec.rb +144 -0
  84. data/spec/lib/active_data/model/attributes/base_spec.rb +82 -0
  85. data/spec/lib/active_data/model/attributes/collection_spec.rb +73 -0
  86. data/spec/lib/active_data/model/attributes/dictionary_spec.rb +93 -0
  87. data/spec/lib/active_data/model/attributes/localized_spec.rb +88 -33
  88. data/spec/lib/active_data/model/attributes/reflections/attribute_spec.rb +72 -0
  89. data/spec/lib/active_data/model/attributes/reflections/base_spec.rb +56 -0
  90. data/spec/lib/active_data/model/attributes/reflections/collection_spec.rb +37 -0
  91. data/spec/lib/active_data/model/attributes/reflections/dictionary_spec.rb +43 -0
  92. data/spec/lib/active_data/model/attributes/reflections/localized_spec.rb +37 -0
  93. data/spec/lib/active_data/model/attributes/reflections/represents_spec.rb +70 -0
  94. data/spec/lib/active_data/model/attributes/represents_spec.rb +153 -0
  95. data/spec/lib/active_data/model/attributes_spec.rb +243 -0
  96. data/spec/lib/active_data/model/callbacks_spec.rb +338 -0
  97. data/spec/lib/active_data/model/conventions_spec.rb +12 -0
  98. data/spec/lib/active_data/model/dirty_spec.rb +75 -0
  99. data/spec/lib/active_data/model/lifecycle_spec.rb +330 -0
  100. data/spec/lib/active_data/model/nested_attributes.rb +202 -0
  101. data/spec/lib/active_data/model/persistence_spec.rb +47 -0
  102. data/spec/lib/active_data/model/primary_spec.rb +84 -0
  103. data/spec/lib/active_data/model/scopes_spec.rb +88 -0
  104. data/spec/lib/active_data/model/typecasting_spec.rb +192 -0
  105. data/spec/lib/active_data/model/validations/associated_spec.rb +94 -0
  106. data/spec/lib/active_data/model/validations/nested_spec.rb +93 -0
  107. data/spec/lib/active_data/model/validations_spec.rb +31 -0
  108. data/spec/lib/active_data/model_spec.rb +1 -32
  109. data/spec/lib/active_data_spec.rb +12 -0
  110. data/spec/spec_helper.rb +39 -0
  111. data/spec/support/model_helpers.rb +10 -0
  112. metadata +246 -54
  113. data/gemfiles/Gemfile.rails-3 +0 -14
  114. data/lib/active_data/attributes/base.rb +0 -69
  115. data/lib/active_data/attributes/localized.rb +0 -42
  116. data/lib/active_data/model/associations/association.rb +0 -30
  117. data/lib/active_data/model/attributable.rb +0 -122
  118. data/lib/active_data/model/collectionizable.rb +0 -55
  119. data/lib/active_data/model/collectionizable/proxy.rb +0 -42
  120. data/lib/active_data/model/extensions.rb +0 -9
  121. data/lib/active_data/model/extensions/array.rb +0 -24
  122. data/lib/active_data/model/extensions/big_decimal.rb +0 -17
  123. data/lib/active_data/model/extensions/boolean.rb +0 -38
  124. data/lib/active_data/model/extensions/date.rb +0 -17
  125. data/lib/active_data/model/extensions/date_time.rb +0 -17
  126. data/lib/active_data/model/extensions/float.rb +0 -17
  127. data/lib/active_data/model/extensions/hash.rb +0 -22
  128. data/lib/active_data/model/extensions/integer.rb +0 -17
  129. data/lib/active_data/model/extensions/localized.rb +0 -22
  130. data/lib/active_data/model/extensions/object.rb +0 -17
  131. data/lib/active_data/model/extensions/string.rb +0 -17
  132. data/lib/active_data/model/extensions/time.rb +0 -17
  133. data/lib/active_data/model/localizable.rb +0 -31
  134. data/lib/active_data/model/nested_attributes.rb +0 -58
  135. data/lib/active_data/model/parameterizable.rb +0 -29
  136. data/lib/active_data/validations.rb +0 -7
  137. data/lib/active_data/validations/associated.rb +0 -17
  138. data/spec/lib/active_data/model/attributable_spec.rb +0 -191
  139. data/spec/lib/active_data/model/collectionizable_spec.rb +0 -60
  140. data/spec/lib/active_data/model/nested_attributes_spec.rb +0 -67
  141. data/spec/lib/active_data/model/type_cast_spec.rb +0 -116
  142. data/spec/lib/active_data/validations/associated_spec.rb +0 -88
@@ -0,0 +1,243 @@
1
+ # encoding: UTF-8
2
+ require 'spec_helper'
3
+
4
+ describe ActiveData::Model::Attributes do
5
+ let(:model) do
6
+ stub_model do
7
+ include ActiveData::Model::Associations
8
+ include ActiveData::Model::Localization
9
+
10
+ attribute :id, Integer
11
+ attribute :full_name, String
12
+ alias_attribute :name, :full_name
13
+
14
+ localized :t, String
15
+ alias_attribute :title, :t
16
+
17
+ embeds_one(:author) {}
18
+ embeds_many(:projects) {}
19
+ end
20
+ end
21
+
22
+ describe '.reflect_on_attribute' do
23
+ specify { expect(model.reflect_on_attribute(:full_name).name).to eq('full_name') }
24
+ specify { expect(model.reflect_on_attribute('full_name').name).to eq('full_name') }
25
+ specify { expect(model.reflect_on_attribute(:name).name).to eq('full_name') }
26
+ specify { expect(model.reflect_on_attribute(:foobar)).to be_nil }
27
+ end
28
+
29
+ describe '.has_attribute?' do
30
+ specify { expect(model.has_attribute?(:full_name)).to eq(true) }
31
+ specify { expect(model.has_attribute?('full_name')).to eq(true) }
32
+ specify { expect(model.has_attribute?(:name)).to eq(true) }
33
+ specify { expect(model.has_attribute?(:foobar)).to eq(false) }
34
+ end
35
+
36
+ describe '.attribute_names' do
37
+ specify { expect(stub_model.attribute_names).to eq([]) }
38
+ specify { expect(model.attribute_names).to eq(%w[id full_name t author projects]) }
39
+ specify { expect(model.attribute_names(false)).to eq(%w[id full_name t]) }
40
+ end
41
+
42
+ describe '.inspect' do
43
+ specify { expect(stub_model.inspect).to match(/#<Class:0x\w+>\(no attributes\)/) }
44
+ specify { expect(stub_model(:user).inspect).to eq('User(no attributes)') }
45
+ specify { expect(stub_model {
46
+ include ActiveData::Model::Primary
47
+ primary :count, Integer
48
+ attribute :object, Object
49
+ }.inspect).to match(/#<Class:0x\w+>\(\*count: Integer, object: Object\)/) }
50
+ specify { expect(stub_model(:user) {
51
+ include ActiveData::Model::Primary
52
+ primary :count, Integer
53
+ attribute :object, Object
54
+ }.inspect).to match('User(*count: Integer, object: Object)') }
55
+ end
56
+
57
+ describe '#==' do
58
+ let(:model) do
59
+ stub_model do
60
+ attribute :name, String
61
+ attribute :count, Float, default: 0
62
+ end
63
+ end
64
+ subject { model.new name: 'hello', count: 42 }
65
+
66
+ it { is_expected.not_to eq(nil) }
67
+ it { is_expected.not_to eq('hello') }
68
+ it { is_expected.not_to eq(Object.new) }
69
+ it { is_expected.not_to eq(model.new) }
70
+ it { is_expected.not_to eq(model.new(name: 'hello1', count: 42)) }
71
+ it { is_expected.not_to eq(model.new(name: 'hello', count: 42.1)) }
72
+ it { is_expected.to eq(model.new(name: 'hello', count: 42)) }
73
+
74
+ it { is_expected.not_to eql(nil) }
75
+ it { is_expected.not_to eql('hello') }
76
+ it { is_expected.not_to eql(Object.new) }
77
+ it { is_expected.not_to eql(model.new) }
78
+ it { is_expected.not_to eql(model.new(name: 'hello1', count: 42)) }
79
+ it { is_expected.not_to eql(model.new(name: 'hello', count: 42.1)) }
80
+ it { is_expected.to eql(model.new(name: 'hello', count: 42)) }
81
+ end
82
+
83
+ describe '#attribute' do
84
+ let(:instance) { model.new }
85
+ specify { expect(instance.attribute(:full_name).reflection.name).to eq('full_name') }
86
+ specify { expect(instance.attribute('full_name').reflection.name).to eq('full_name') }
87
+ specify { expect(instance.attribute(:name).reflection.name).to eq('full_name') }
88
+ specify { expect(instance.attribute(:foobar)).to be_nil }
89
+
90
+ specify { expect(instance.attribute('full_name')).to equal(instance.attribute(:name)) }
91
+ end
92
+
93
+ describe '#has_attribute?' do
94
+ specify { expect(model.new.has_attribute?(:full_name)).to eq(true) }
95
+ specify { expect(model.new.has_attribute?('full_name')).to eq(true) }
96
+ specify { expect(model.new.has_attribute?(:name)).to eq(true) }
97
+ specify { expect(model.new.has_attribute?(:foobar)).to eq(false) }
98
+ end
99
+
100
+ describe '#attribute_names' do
101
+ specify { expect(stub_model.new.attribute_names).to eq([]) }
102
+ specify { expect(model.new.attribute_names).to eq(%w[id full_name t author projects]) }
103
+ specify { expect(model.new.attribute_names(false)).to eq(%w[id full_name t]) }
104
+ end
105
+
106
+ describe '#attribute_present?' do
107
+ specify { expect(model.new.attribute_present?(:name)).to be(false) }
108
+ specify { expect(model.new(name: '').attribute_present?(:name)).to be(false) }
109
+ specify { expect(model.new(name: 'Name').attribute_present?(:name)).to be(true) }
110
+ end
111
+
112
+ describe '#attributes' do
113
+ specify { expect(stub_model.new.attributes).to eq({}) }
114
+ specify { expect(model.new(name: 'Name').attributes)
115
+ .to match({'id' => nil, 'full_name' => 'Name', 't' => {}, 'author' => nil, 'projects' => nil}) }
116
+ specify { expect(model.new(name: 'Name').attributes(false))
117
+ .to match({'id' => nil, 'full_name' => 'Name', 't' => {}}) }
118
+ end
119
+
120
+ describe '#assign_attributes' do
121
+ let(:attributes) { { id: 42, full_name: 'Name', missed: 'value' } }
122
+ subject { model.new }
123
+
124
+ specify { expect { subject.assign_attributes(attributes) }.to change { subject.id }.to(42) }
125
+ specify { expect { subject.assign_attributes(attributes) }.to change { subject.full_name }.to('Name') }
126
+ end
127
+
128
+ describe '#inspect' do
129
+ specify { expect(stub_model.new.inspect).to match(/#<#<Class:0x\w+> \(no attributes\)>/) }
130
+ specify { expect(stub_model(:user).new.inspect).to match(/#<User \(no attributes\)>/) }
131
+ specify { expect(stub_model {
132
+ include ActiveData::Model::Primary
133
+ primary :count, Integer
134
+ attribute :object, Object
135
+ }.new(object: 'String').inspect).to match(/#<#<Class:0x\w+> \*count: nil, object: "String">/) }
136
+ specify { expect(stub_model(:user) {
137
+ include ActiveData::Model::Primary
138
+ primary :count, Integer
139
+ attribute :object, Object
140
+ }.new.inspect).to match(/#<User \*count: nil, object: nil>/) }
141
+ end
142
+
143
+ context 'attributes integration' do
144
+ let(:model) do
145
+ stub_class do
146
+ include ActiveData::Model::Attributes
147
+ include ActiveData::Model::Associations
148
+ attr_accessor :name
149
+
150
+ attribute :id, Integer
151
+ attribute :hello, Object
152
+ attribute :string, String, default: ->(record){ record.name }
153
+ attribute :count, Integer, default: '10'
154
+ attribute(:calc, Integer) { 2 + 3 }
155
+ attribute :enum, Integer, enum: [1, 2, 3]
156
+ attribute :enum_with_default, Integer, enum: [1, 2, 3], default: '2'
157
+ attribute :foo, Boolean, default: false
158
+ collection :array, Integer, enum: [1, 2, 3], default: 7
159
+
160
+ def initialize name = nil
161
+ super()
162
+ @name = name
163
+ end
164
+ end
165
+ end
166
+
167
+ subject { model.new('world') }
168
+
169
+ its(:enum_values) { should == [1, 2, 3] }
170
+ its(:string_default) { should == 'world' }
171
+ its(:count_default) { should == '10' }
172
+ its(:name) { should == 'world' }
173
+ its(:hello) { should eq(nil) }
174
+ its(:hello?) { should eq(false) }
175
+ its(:count) { should == 10 }
176
+ its(:count_before_type_cast) { should == '10' }
177
+ its(:count?) { should eq(true) }
178
+ its(:calc) { should == 5 }
179
+ its(:enum?) { should eq(false) }
180
+ its(:enum_with_default?) { should eq(true) }
181
+ specify { expect { subject.hello = 'worlds' }.to change { subject.hello }.from(nil).to('worlds') }
182
+ specify { expect { subject.count = 20 }.to change { subject.count }.from(10).to(20) }
183
+ specify { expect { subject.calc = 15 }.to change { subject.calc }.from(5).to(15) }
184
+
185
+ context 'enums' do
186
+ specify { subject.enum = 3; expect(subject.enum).to eq(3) }
187
+ specify { subject.enum = '3'; expect(subject.enum).to eq(3) }
188
+ specify { subject.enum = 10; expect(subject.enum).to eq(nil) }
189
+ specify { subject.enum = 'hello'; expect(subject.enum).to eq(nil) }
190
+ specify { subject.enum_with_default = 3; expect(subject.enum_with_default).to eq(3) }
191
+ specify { subject.enum_with_default = 10; expect(subject.enum_with_default).to be_nil }
192
+ end
193
+
194
+ context 'array' do
195
+ specify { subject.array = [2, 4]; expect(subject.array).to eq([2, nil]) }
196
+ specify { subject.array = [2, 4]; expect(subject.array?).to eq(true) }
197
+ specify { subject.array = [2, 4]; expect(subject.array_values).to eq([1, 2, 3]) }
198
+ specify { subject.array = [2, 4]; expect(subject.array_default).to eq(7) }
199
+ end
200
+
201
+ context 'attribute caching' do
202
+ before do
203
+ subject.hello = 'blabla'
204
+ subject.hello
205
+ subject.hello = 'newnewnew'
206
+ end
207
+
208
+ specify { expect(subject.hello).to eq('newnewnew') }
209
+ end
210
+ end
211
+
212
+ context 'inheritance' do
213
+ let!(:ancestor) do
214
+ Class.new do
215
+ include ActiveData::Model::Attributes
216
+ attribute :foo, String
217
+ end
218
+ end
219
+
220
+ let!(:descendant1) do
221
+ Class.new ancestor do
222
+ attribute :bar, String
223
+ end
224
+ end
225
+
226
+ let!(:descendant2) do
227
+ Class.new ancestor do
228
+ attribute :baz, String
229
+ attribute :moo, String
230
+ end
231
+ end
232
+
233
+ specify { expect(ancestor._attributes.keys).to eq(['foo']) }
234
+ specify { expect(ancestor.instance_methods).to include :foo, :foo= }
235
+ specify { expect(ancestor.instance_methods).not_to include :bar, :bar=, :baz, :baz= }
236
+ specify { expect(descendant1._attributes.keys).to eq(['foo', 'bar']) }
237
+ specify { expect(descendant1.instance_methods).to include :foo, :foo=, :bar, :bar= }
238
+ specify { expect(descendant1.instance_methods).not_to include :baz, :baz= }
239
+ specify { expect(descendant2._attributes.keys).to eq(['foo', 'baz', 'moo']) }
240
+ specify { expect(descendant2.instance_methods).to include :foo, :foo=, :baz, :baz=, :moo, :moo= }
241
+ specify { expect(descendant2.instance_methods).not_to include :bar, :bar= }
242
+ end
243
+ end
@@ -0,0 +1,338 @@
1
+ # encoding: UTF-8
2
+ require 'spec_helper'
3
+
4
+ describe ActiveData::Model::Callbacks do
5
+ before do
6
+ stub_model(:user) do
7
+ include ActiveData::Model::Callbacks
8
+ attribute :actions, Array, default: []
9
+
10
+ def append action
11
+ self.actions = actions + [action]
12
+ end
13
+
14
+ define_create { append :create }
15
+ define_update { append :update }
16
+ define_destroy { append :destroy }
17
+ end
18
+ end
19
+
20
+ describe '.after_initialize' do
21
+ before do
22
+ User.after_initialize { append :after_initialize }
23
+ end
24
+
25
+ specify { expect(User.new.actions).to eq([:after_initialize]) }
26
+ specify { expect(User.create.actions).to eq([:after_initialize, :create]) }
27
+ end
28
+
29
+ describe '.before_save, .after_save' do
30
+ before do
31
+ User.before_save { append :before_save }
32
+ User.after_save { append :after_save }
33
+ end
34
+
35
+ specify { expect(User.create.actions).to eq([:before_save, :create, :after_save]) }
36
+ specify { expect(User.new.tap(&:save).actions).to eq([:before_save, :create, :after_save]) }
37
+ specify { expect(User.new.tap { |u| u.update({}) }.actions).to eq([:before_save, :create, :after_save]) }
38
+ specify { expect(User.create.tap(&:save).actions).to eq([:before_save, :create, :after_save, :before_save, :update, :after_save]) }
39
+ specify { expect(User.create.tap { |u| u.update({}) }.actions).to eq([:before_save, :create, :after_save, :before_save, :update, :after_save]) }
40
+
41
+ specify { expect(User.new.tap { |u| u.save { false } }.actions).to eq([:before_save]) }
42
+ specify { expect(User.create.tap { |u| u.save { false } }.actions).to eq([:before_save, :create, :after_save, :before_save]) }
43
+ end
44
+
45
+ describe '.around_save' do
46
+ before do
47
+ User.around_save do |user, block|
48
+ append :before_around_save
49
+ block.call
50
+ append :after_around_save
51
+ end
52
+ end
53
+
54
+ specify { expect(User.create.actions).to eq([:before_around_save, :create, :after_around_save]) }
55
+ specify { expect(User.new.tap(&:save).actions).to eq([:before_around_save, :create, :after_around_save]) }
56
+ specify { expect(User.new.tap { |u| u.update({}) }.actions).to eq([:before_around_save, :create, :after_around_save]) }
57
+ specify { expect(User.create.tap(&:save).actions).to eq([:before_around_save, :create, :after_around_save, :before_around_save, :update, :after_around_save]) }
58
+ specify { expect(User.create.tap { |u| u.update({}) }.actions).to eq([:before_around_save, :create, :after_around_save, :before_around_save, :update, :after_around_save]) }
59
+
60
+ specify { expect(User.new.tap { |u| u.save { false } }.actions).to eq([:before_around_save, :after_around_save]) }
61
+ specify { expect(User.create.tap { |u| u.save { false } }.actions).to eq([:before_around_save, :create, :after_around_save, :before_around_save, :after_around_save]) }
62
+ end
63
+
64
+ describe '.before_create, .after_create' do
65
+ before do
66
+ User.before_create { append :before_create }
67
+ User.after_create { append :after_create }
68
+ end
69
+
70
+ specify { expect(User.create.actions).to eq([:before_create, :create, :after_create]) }
71
+ specify { expect(User.new.tap(&:save).actions).to eq([:before_create, :create, :after_create]) }
72
+ specify { expect(User.new.tap { |u| u.update({}) }.actions).to eq([:before_create, :create, :after_create]) }
73
+ specify { expect(User.create.tap(&:save).actions).to eq([:before_create, :create, :after_create, :update]) }
74
+ specify { expect(User.create.tap { |u| u.update({}) }.actions).to eq([:before_create, :create, :after_create, :update]) }
75
+
76
+ specify { expect(User.new.tap { |u| u.save { false } }.actions).to eq([:before_create]) }
77
+ end
78
+
79
+ describe '.around_create' do
80
+ before do
81
+ User.around_create do |user, block|
82
+ append :before_around_create
83
+ block.call
84
+ append :after_around_create
85
+ end
86
+ end
87
+
88
+ specify { expect(User.create.actions).to eq([:before_around_create, :create, :after_around_create]) }
89
+ specify { expect(User.new.tap(&:save).actions).to eq([:before_around_create, :create, :after_around_create]) }
90
+ specify { expect(User.new.tap { |u| u.update({}) }.actions).to eq([:before_around_create, :create, :after_around_create]) }
91
+ specify { expect(User.create.tap(&:save).actions).to eq([:before_around_create, :create, :after_around_create, :update]) }
92
+ specify { expect(User.create.tap { |u| u.update({}) }.actions).to eq([:before_around_create, :create, :after_around_create, :update]) }
93
+
94
+ specify { expect(User.new.tap { |u| u.save { false } }.actions).to eq([:before_around_create, :after_around_create]) }
95
+ end
96
+
97
+ describe '.before_update, .after_update' do
98
+ before do
99
+ User.before_update { append :before_update }
100
+ User.after_update { append :after_update }
101
+ end
102
+
103
+ specify { expect(User.create.actions).to eq([:create]) }
104
+ specify { expect(User.new.tap(&:save).actions).to eq([:create]) }
105
+ specify { expect(User.new.tap { |u| u.update({}) }.actions).to eq([:create]) }
106
+ specify { expect(User.create.tap(&:save).actions).to eq([:create, :before_update, :update, :after_update]) }
107
+ specify { expect(User.create.tap { |u| u.update({}) }.actions).to eq([:create, :before_update, :update, :after_update]) }
108
+
109
+ specify { expect(User.create.tap { |u| u.save { false } }.actions).to eq([:create, :before_update]) }
110
+ end
111
+
112
+ describe '.around_update' do
113
+ before do
114
+ User.around_update do |user, block|
115
+ append :before_around_update
116
+ block.call
117
+ append :after_around_update
118
+ end
119
+ end
120
+
121
+ specify { expect(User.create.actions).to eq([:create]) }
122
+ specify { expect(User.new.tap(&:save).actions).to eq([:create]) }
123
+ specify { expect(User.new.tap { |u| u.update({}) }.actions).to eq([:create]) }
124
+ specify { expect(User.create.tap(&:save).actions).to eq([:create, :before_around_update, :update, :after_around_update]) }
125
+ specify { expect(User.create.tap { |u| u.update({}) }.actions).to eq([:create, :before_around_update, :update, :after_around_update]) }
126
+
127
+ specify { expect(User.create.tap { |u| u.save { false } }.actions).to eq([:create, :before_around_update, :after_around_update]) }
128
+ end
129
+
130
+ describe '.before_validation, .after_validation,
131
+ .before_save, .after_save, .around_save,
132
+ .before_create, .after_create, .around_create,
133
+ .before_update, .after_update, .around_update
134
+ .before_destroy, .after_destroy, .around_destroy' do
135
+ before do
136
+ User.before_validation { append :before_validation }
137
+ User.after_validation { append :after_validation }
138
+
139
+ User.before_save { append :before_save }
140
+ User.after_save { append :after_save }
141
+ User.around_save do |user, block|
142
+ append :before_around_save
143
+ block.call
144
+ append :after_around_save
145
+ end
146
+
147
+ User.before_create { append :before_create }
148
+ User.after_create { append :after_create }
149
+ User.around_create do |user, block|
150
+ append :before_around_create
151
+ block.call
152
+ append :after_around_create
153
+ end
154
+
155
+ User.before_update { append :before_update }
156
+ User.after_update { append :after_update }
157
+ User.around_update do |user, block|
158
+ append :before_around_update
159
+ block.call
160
+ append :after_around_update
161
+ end
162
+
163
+ User.before_destroy { append :before_destroy }
164
+ User.after_destroy { append :after_destroy }
165
+ User.around_destroy do |user, block|
166
+ append :before_around_destroy
167
+ block.call
168
+ append :after_around_destroy
169
+ end
170
+ end
171
+
172
+ specify { expect(User.create.tap(&:save).destroy.actions).to eq([
173
+ :before_validation, :after_validation,
174
+ :before_save, :before_around_save,
175
+ :before_create, :before_around_create,
176
+ :create,
177
+ :after_around_create, :after_create,
178
+ :after_around_save, :after_save,
179
+
180
+ :before_validation, :after_validation,
181
+ :before_save, :before_around_save,
182
+ :before_update, :before_around_update,
183
+ :update,
184
+ :after_around_update, :after_update,
185
+ :after_around_save, :after_save,
186
+
187
+ :before_destroy, :before_around_destroy,
188
+ :destroy,
189
+ :after_around_destroy, :after_destroy
190
+ ]) }
191
+ end
192
+
193
+ describe '.before_destroy, .after_destroy' do
194
+ before do
195
+ User.before_destroy { append :before_destroy }
196
+ User.after_destroy { append :after_destroy }
197
+ end
198
+
199
+ specify { expect(User.new.destroy.actions).to eq([:before_destroy, :destroy, :after_destroy]) }
200
+ specify { expect(User.create.destroy.actions).to eq([:create, :before_destroy, :destroy, :after_destroy]) }
201
+
202
+ specify { expect(User.new.destroy { false }.actions).to eq([:before_destroy]) }
203
+ specify { expect(User.create.destroy { false }.actions).to eq([:create, :before_destroy]) }
204
+ end
205
+
206
+ describe '.around_destroy' do
207
+ before do
208
+ User.around_destroy do |user, block|
209
+ append :before_around_destroy
210
+ block.call
211
+ append :after_around_destroy
212
+ end
213
+ end
214
+
215
+ specify { expect(User.new.destroy.actions).to eq([:before_around_destroy, :destroy, :after_around_destroy]) }
216
+ specify { expect(User.create.destroy.actions).to eq([:create, :before_around_destroy, :destroy, :after_around_destroy]) }
217
+
218
+ specify { expect(User.new.destroy { false }.actions).to eq([:before_around_destroy, :after_around_destroy]) }
219
+ specify { expect(User.create.destroy { false }.actions).to eq([:create, :before_around_destroy, :after_around_destroy]) }
220
+ end
221
+
222
+ context 'unsavable, undestroyable' do
223
+ before do
224
+ stub_model(:user) do
225
+ include ActiveData::Model::Callbacks
226
+
227
+ attribute :actions, Array, default: []
228
+ attribute :validated, Boolean, default: false
229
+
230
+ validates :validated, presence: true
231
+
232
+ def append action
233
+ self.actions = actions + [action]
234
+ end
235
+ end
236
+ end
237
+
238
+ before do
239
+ User.before_validation { append :before_validation }
240
+ User.after_validation { append :after_validation }
241
+
242
+ User.before_save { append :before_save }
243
+ User.after_save { append :after_save }
244
+ User.around_save do |&block|
245
+ append :before_around_save
246
+ block.call
247
+ append :after_around_save
248
+ end
249
+
250
+ User.before_create { append :before_create }
251
+ User.after_create { append :after_create }
252
+ User.around_create do |&block|
253
+ append :before_around_create
254
+ block.call
255
+ append :after_around_create
256
+ end
257
+
258
+ User.before_update { append :before_update }
259
+ User.after_update { append :after_update }
260
+ User.around_update do |&block|
261
+ append :before_around_update
262
+ block.call
263
+ append :after_around_update
264
+ end
265
+
266
+ User.before_destroy { append :before_destroy }
267
+ User.after_destroy { append :after_destroy }
268
+ User.around_destroy do |&block|
269
+ append :before_around_destroy
270
+ block.call
271
+ append :after_around_destroy
272
+ end
273
+ end
274
+
275
+ let(:user) { User.new }
276
+
277
+ specify do
278
+ begin
279
+ user.save
280
+ rescue ActiveData::UnsavableObject
281
+ expect(user.actions).to eq([])
282
+ end
283
+ end
284
+
285
+ specify do
286
+ begin
287
+ user.save!
288
+ rescue ActiveData::UnsavableObject
289
+ expect(user.actions).to eq([])
290
+ end
291
+ end
292
+
293
+ specify do
294
+ user.save { true }
295
+ expect(user.actions).to eq([:before_validation, :after_validation])
296
+ end
297
+
298
+ specify do
299
+ begin
300
+ user.save! { true }
301
+ rescue ActiveData::ValidationError
302
+ expect(user.actions).to eq([:before_validation, :after_validation])
303
+ end
304
+ end
305
+
306
+ specify do
307
+ begin
308
+ user.update({})
309
+ rescue ActiveData::UnsavableObject
310
+ expect(user.actions).to eq([])
311
+ end
312
+ end
313
+
314
+ specify do
315
+ begin
316
+ user.update!({})
317
+ rescue ActiveData::UnsavableObject
318
+ expect(user.actions).to eq([])
319
+ end
320
+ end
321
+
322
+ specify do
323
+ begin
324
+ user.destroy
325
+ rescue ActiveData::UndestroyableObject
326
+ expect(user.actions).to eq([])
327
+ end
328
+ end
329
+
330
+ specify do
331
+ begin
332
+ user.destroy!
333
+ rescue ActiveData::UndestroyableObject
334
+ expect(user.actions).to eq([])
335
+ end
336
+ end
337
+ end
338
+ end