active_data 0.3.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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