granite-form 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +13 -0
  3. data/.github/workflows/ci.yml +35 -0
  4. data/.github/workflows/main.yml +29 -0
  5. data/.gitignore +21 -0
  6. data/.rspec +2 -0
  7. data/.rubocop.yml +64 -0
  8. data/.rubocop_todo.yml +48 -0
  9. data/Appraisals +8 -0
  10. data/CHANGELOG.md +73 -0
  11. data/Gemfile +8 -0
  12. data/Guardfile +77 -0
  13. data/LICENSE +22 -0
  14. data/README.md +429 -0
  15. data/Rakefile +6 -0
  16. data/gemfiles/rails.4.2.gemfile +15 -0
  17. data/gemfiles/rails.5.0.gemfile +15 -0
  18. data/gemfiles/rails.5.1.gemfile +15 -0
  19. data/gemfiles/rails.5.2.gemfile +15 -0
  20. data/gemfiles/rails.6.0.gemfile +14 -0
  21. data/gemfiles/rails.6.1.gemfile +14 -0
  22. data/gemfiles/rails.7.0.gemfile +14 -0
  23. data/granite-form.gemspec +31 -0
  24. data/lib/granite/form/active_record/associations.rb +57 -0
  25. data/lib/granite/form/active_record/nested_attributes.rb +20 -0
  26. data/lib/granite/form/base.rb +15 -0
  27. data/lib/granite/form/config.rb +42 -0
  28. data/lib/granite/form/errors.rb +111 -0
  29. data/lib/granite/form/extensions.rb +36 -0
  30. data/lib/granite/form/model/associations/base.rb +97 -0
  31. data/lib/granite/form/model/associations/collection/embedded.rb +14 -0
  32. data/lib/granite/form/model/associations/collection/proxy.rb +35 -0
  33. data/lib/granite/form/model/associations/embeds_any.rb +19 -0
  34. data/lib/granite/form/model/associations/embeds_many.rb +152 -0
  35. data/lib/granite/form/model/associations/embeds_one.rb +112 -0
  36. data/lib/granite/form/model/associations/nested_attributes.rb +215 -0
  37. data/lib/granite/form/model/associations/persistence_adapters/active_record/referenced_proxy.rb +33 -0
  38. data/lib/granite/form/model/associations/persistence_adapters/active_record.rb +68 -0
  39. data/lib/granite/form/model/associations/persistence_adapters/base.rb +55 -0
  40. data/lib/granite/form/model/associations/references_any.rb +43 -0
  41. data/lib/granite/form/model/associations/references_many.rb +113 -0
  42. data/lib/granite/form/model/associations/references_one.rb +88 -0
  43. data/lib/granite/form/model/associations/reflections/base.rb +92 -0
  44. data/lib/granite/form/model/associations/reflections/embeds_any.rb +52 -0
  45. data/lib/granite/form/model/associations/reflections/embeds_many.rb +17 -0
  46. data/lib/granite/form/model/associations/reflections/embeds_one.rb +19 -0
  47. data/lib/granite/form/model/associations/reflections/references_any.rb +65 -0
  48. data/lib/granite/form/model/associations/reflections/references_many.rb +30 -0
  49. data/lib/granite/form/model/associations/reflections/references_one.rb +32 -0
  50. data/lib/granite/form/model/associations/reflections/singular.rb +37 -0
  51. data/lib/granite/form/model/associations/validations.rb +41 -0
  52. data/lib/granite/form/model/associations.rb +120 -0
  53. data/lib/granite/form/model/attributes/attribute.rb +75 -0
  54. data/lib/granite/form/model/attributes/base.rb +134 -0
  55. data/lib/granite/form/model/attributes/collection.rb +19 -0
  56. data/lib/granite/form/model/attributes/dictionary.rb +28 -0
  57. data/lib/granite/form/model/attributes/localized.rb +44 -0
  58. data/lib/granite/form/model/attributes/reference_many.rb +21 -0
  59. data/lib/granite/form/model/attributes/reference_one.rb +52 -0
  60. data/lib/granite/form/model/attributes/reflections/attribute.rb +61 -0
  61. data/lib/granite/form/model/attributes/reflections/base.rb +62 -0
  62. data/lib/granite/form/model/attributes/reflections/collection.rb +12 -0
  63. data/lib/granite/form/model/attributes/reflections/dictionary.rb +15 -0
  64. data/lib/granite/form/model/attributes/reflections/localized.rb +45 -0
  65. data/lib/granite/form/model/attributes/reflections/reference_many.rb +12 -0
  66. data/lib/granite/form/model/attributes/reflections/reference_one.rb +49 -0
  67. data/lib/granite/form/model/attributes/reflections/represents.rb +56 -0
  68. data/lib/granite/form/model/attributes/represents.rb +67 -0
  69. data/lib/granite/form/model/attributes.rb +204 -0
  70. data/lib/granite/form/model/callbacks.rb +72 -0
  71. data/lib/granite/form/model/conventions.rb +40 -0
  72. data/lib/granite/form/model/dirty.rb +84 -0
  73. data/lib/granite/form/model/lifecycle.rb +309 -0
  74. data/lib/granite/form/model/localization.rb +26 -0
  75. data/lib/granite/form/model/persistence.rb +59 -0
  76. data/lib/granite/form/model/primary.rb +59 -0
  77. data/lib/granite/form/model/representation.rb +101 -0
  78. data/lib/granite/form/model/scopes.rb +118 -0
  79. data/lib/granite/form/model/validations/associated.rb +22 -0
  80. data/lib/granite/form/model/validations/nested.rb +56 -0
  81. data/lib/granite/form/model/validations.rb +29 -0
  82. data/lib/granite/form/model.rb +33 -0
  83. data/lib/granite/form/railtie.rb +9 -0
  84. data/lib/granite/form/undefined_class.rb +11 -0
  85. data/lib/granite/form/version.rb +5 -0
  86. data/lib/granite/form.rb +163 -0
  87. data/spec/lib/granite/form/active_record/associations_spec.rb +211 -0
  88. data/spec/lib/granite/form/active_record/nested_attributes_spec.rb +15 -0
  89. data/spec/lib/granite/form/config_spec.rb +66 -0
  90. data/spec/lib/granite/form/model/associations/embeds_many_spec.rb +706 -0
  91. data/spec/lib/granite/form/model/associations/embeds_one_spec.rb +533 -0
  92. data/spec/lib/granite/form/model/associations/nested_attributes_spec.rb +119 -0
  93. data/spec/lib/granite/form/model/associations/persistence_adapters/active_record_spec.rb +58 -0
  94. data/spec/lib/granite/form/model/associations/references_many_spec.rb +572 -0
  95. data/spec/lib/granite/form/model/associations/references_one_spec.rb +445 -0
  96. data/spec/lib/granite/form/model/associations/reflections/embeds_any_spec.rb +42 -0
  97. data/spec/lib/granite/form/model/associations/reflections/embeds_many_spec.rb +145 -0
  98. data/spec/lib/granite/form/model/associations/reflections/embeds_one_spec.rb +117 -0
  99. data/spec/lib/granite/form/model/associations/reflections/references_many_spec.rb +303 -0
  100. data/spec/lib/granite/form/model/associations/reflections/references_one_spec.rb +287 -0
  101. data/spec/lib/granite/form/model/associations/validations_spec.rb +137 -0
  102. data/spec/lib/granite/form/model/associations_spec.rb +198 -0
  103. data/spec/lib/granite/form/model/attributes/attribute_spec.rb +186 -0
  104. data/spec/lib/granite/form/model/attributes/base_spec.rb +97 -0
  105. data/spec/lib/granite/form/model/attributes/collection_spec.rb +72 -0
  106. data/spec/lib/granite/form/model/attributes/dictionary_spec.rb +100 -0
  107. data/spec/lib/granite/form/model/attributes/localized_spec.rb +103 -0
  108. data/spec/lib/granite/form/model/attributes/reflections/attribute_spec.rb +72 -0
  109. data/spec/lib/granite/form/model/attributes/reflections/base_spec.rb +56 -0
  110. data/spec/lib/granite/form/model/attributes/reflections/collection_spec.rb +37 -0
  111. data/spec/lib/granite/form/model/attributes/reflections/dictionary_spec.rb +43 -0
  112. data/spec/lib/granite/form/model/attributes/reflections/localized_spec.rb +37 -0
  113. data/spec/lib/granite/form/model/attributes/reflections/represents_spec.rb +70 -0
  114. data/spec/lib/granite/form/model/attributes/represents_spec.rb +85 -0
  115. data/spec/lib/granite/form/model/attributes_spec.rb +350 -0
  116. data/spec/lib/granite/form/model/callbacks_spec.rb +337 -0
  117. data/spec/lib/granite/form/model/conventions_spec.rb +11 -0
  118. data/spec/lib/granite/form/model/dirty_spec.rb +84 -0
  119. data/spec/lib/granite/form/model/lifecycle_spec.rb +356 -0
  120. data/spec/lib/granite/form/model/persistence_spec.rb +46 -0
  121. data/spec/lib/granite/form/model/primary_spec.rb +84 -0
  122. data/spec/lib/granite/form/model/representation_spec.rb +139 -0
  123. data/spec/lib/granite/form/model/scopes_spec.rb +86 -0
  124. data/spec/lib/granite/form/model/typecasting_spec.rb +193 -0
  125. data/spec/lib/granite/form/model/validations/associated_spec.rb +102 -0
  126. data/spec/lib/granite/form/model/validations/nested_spec.rb +164 -0
  127. data/spec/lib/granite/form/model/validations_spec.rb +31 -0
  128. data/spec/lib/granite/form/model_spec.rb +10 -0
  129. data/spec/lib/granite/form_spec.rb +11 -0
  130. data/spec/shared/nested_attribute_examples.rb +332 -0
  131. data/spec/spec_helper.rb +50 -0
  132. data/spec/support/model_helpers.rb +10 -0
  133. data/spec/support/muffle_helper.rb +7 -0
  134. metadata +403 -0
@@ -0,0 +1,337 @@
1
+ require 'spec_helper'
2
+
3
+ describe Granite::Form::Model::Callbacks do
4
+ before do
5
+ stub_model(:user) do
6
+ include Granite::Form::Model::Callbacks
7
+ attribute :actions, Array, default: []
8
+
9
+ def append(action)
10
+ self.actions = actions + [action]
11
+ end
12
+
13
+ define_create { append :create }
14
+ define_update { append :update }
15
+ define_destroy { append :destroy }
16
+ end
17
+ end
18
+
19
+ describe '.after_initialize' do
20
+ before do
21
+ User.after_initialize { append :after_initialize }
22
+ end
23
+
24
+ specify { expect(User.new.actions).to eq([:after_initialize]) }
25
+ specify { expect(User.create.actions).to eq(%i[after_initialize create]) }
26
+ end
27
+
28
+ describe '.before_save, .after_save' do
29
+ before do
30
+ User.before_save { append :before_save }
31
+ User.after_save { append :after_save }
32
+ end
33
+
34
+ specify { expect(User.create.actions).to eq(%i[before_save create after_save]) }
35
+ specify { expect(User.new.tap(&:save).actions).to eq(%i[before_save create after_save]) }
36
+ specify { expect(User.new.tap { |u| u.update({}) }.actions).to eq(%i[before_save create after_save]) }
37
+ specify { expect(User.create.tap(&:save).actions).to eq(%i[before_save create after_save before_save update after_save]) }
38
+ specify { expect(User.create.tap { |u| u.update({}) }.actions).to eq(%i[before_save create after_save before_save update after_save]) }
39
+
40
+ specify { expect(User.new.tap { |u| u.save { false } }.actions).to eq([:before_save]) }
41
+ specify { expect(User.create.tap { |u| u.save { false } }.actions).to eq(%i[before_save create after_save before_save]) }
42
+ end
43
+
44
+ describe '.around_save' do
45
+ before do
46
+ User.around_save do |_, block|
47
+ append :before_around_save
48
+ block.call
49
+ append :after_around_save
50
+ end
51
+ end
52
+
53
+ specify { expect(User.create.actions).to eq(%i[before_around_save create after_around_save]) }
54
+ specify { expect(User.new.tap(&:save).actions).to eq(%i[before_around_save create after_around_save]) }
55
+ specify { expect(User.new.tap { |u| u.update({}) }.actions).to eq(%i[before_around_save create after_around_save]) }
56
+ specify { expect(User.create.tap(&:save).actions).to eq(%i[before_around_save create after_around_save before_around_save update after_around_save]) }
57
+ specify { expect(User.create.tap { |u| u.update({}) }.actions).to eq(%i[before_around_save create after_around_save before_around_save update after_around_save]) }
58
+
59
+ specify { expect(User.new.tap { |u| u.save { false } }.actions).to eq(%i[before_around_save after_around_save]) }
60
+ specify { expect(User.create.tap { |u| u.save { false } }.actions).to eq(%i[before_around_save create after_around_save before_around_save after_around_save]) }
61
+ end
62
+
63
+ describe '.before_create, .after_create' do
64
+ before do
65
+ User.before_create { append :before_create }
66
+ User.after_create { append :after_create }
67
+ end
68
+
69
+ specify { expect(User.create.actions).to eq(%i[before_create create after_create]) }
70
+ specify { expect(User.new.tap(&:save).actions).to eq(%i[before_create create after_create]) }
71
+ specify { expect(User.new.tap { |u| u.update({}) }.actions).to eq(%i[before_create create after_create]) }
72
+ specify { expect(User.create.tap(&:save).actions).to eq(%i[before_create create after_create update]) }
73
+ specify { expect(User.create.tap { |u| u.update({}) }.actions).to eq(%i[before_create create after_create update]) }
74
+
75
+ specify { expect(User.new.tap { |u| u.save { false } }.actions).to eq([:before_create]) }
76
+ end
77
+
78
+ describe '.around_create' do
79
+ before do
80
+ User.around_create do |_, block|
81
+ append :before_around_create
82
+ block.call
83
+ append :after_around_create
84
+ end
85
+ end
86
+
87
+ specify { expect(User.create.actions).to eq(%i[before_around_create create after_around_create]) }
88
+ specify { expect(User.new.tap(&:save).actions).to eq(%i[before_around_create create after_around_create]) }
89
+ specify { expect(User.new.tap { |u| u.update({}) }.actions).to eq(%i[before_around_create create after_around_create]) }
90
+ specify { expect(User.create.tap(&:save).actions).to eq(%i[before_around_create create after_around_create update]) }
91
+ specify { expect(User.create.tap { |u| u.update({}) }.actions).to eq(%i[before_around_create create after_around_create update]) }
92
+
93
+ specify { expect(User.new.tap { |u| u.save { false } }.actions).to eq(%i[before_around_create after_around_create]) }
94
+ end
95
+
96
+ describe '.before_update, .after_update' do
97
+ before do
98
+ User.before_update { append :before_update }
99
+ User.after_update { append :after_update }
100
+ end
101
+
102
+ specify { expect(User.create.actions).to eq([:create]) }
103
+ specify { expect(User.new.tap(&:save).actions).to eq([:create]) }
104
+ specify { expect(User.new.tap { |u| u.update({}) }.actions).to eq([:create]) }
105
+ specify { expect(User.create.tap(&:save).actions).to eq(%i[create before_update update after_update]) }
106
+ specify { expect(User.create.tap { |u| u.update({}) }.actions).to eq(%i[create before_update update after_update]) }
107
+
108
+ specify { expect(User.create.tap { |u| u.save { false } }.actions).to eq(%i[create before_update]) }
109
+ end
110
+
111
+ describe '.around_update' do
112
+ before do
113
+ User.around_update do |_, block|
114
+ append :before_around_update
115
+ block.call
116
+ append :after_around_update
117
+ end
118
+ end
119
+
120
+ specify { expect(User.create.actions).to eq([:create]) }
121
+ specify { expect(User.new.tap(&:save).actions).to eq([:create]) }
122
+ specify { expect(User.new.tap { |u| u.update({}) }.actions).to eq([:create]) }
123
+ specify { expect(User.create.tap(&:save).actions).to eq(%i[create before_around_update update after_around_update]) }
124
+ specify { expect(User.create.tap { |u| u.update({}) }.actions).to eq(%i[create before_around_update update after_around_update]) }
125
+
126
+ specify { expect(User.create.tap { |u| u.save { false } }.actions).to eq(%i[create before_around_update after_around_update]) }
127
+ end
128
+
129
+ describe '.before_validation, .after_validation,
130
+ .before_save, .after_save, .around_save,
131
+ .before_create, .after_create, .around_create,
132
+ .before_update, .after_update, .around_update
133
+ .before_destroy, .after_destroy, .around_destroy' do
134
+ before do
135
+ User.before_validation { append :before_validation }
136
+ User.after_validation { append :after_validation }
137
+
138
+ User.before_save { append :before_save }
139
+ User.after_save { append :after_save }
140
+ User.around_save do |_, block|
141
+ append :before_around_save
142
+ block.call
143
+ append :after_around_save
144
+ end
145
+
146
+ User.before_create { append :before_create }
147
+ User.after_create { append :after_create }
148
+ User.around_create do |_, block|
149
+ append :before_around_create
150
+ block.call
151
+ append :after_around_create
152
+ end
153
+
154
+ User.before_update { append :before_update }
155
+ User.after_update { append :after_update }
156
+ User.around_update do |_, block|
157
+ append :before_around_update
158
+ block.call
159
+ append :after_around_update
160
+ end
161
+
162
+ User.before_destroy { append :before_destroy }
163
+ User.after_destroy { append :after_destroy }
164
+ User.around_destroy do |_, block|
165
+ append :before_around_destroy
166
+ block.call
167
+ append :after_around_destroy
168
+ end
169
+ end
170
+
171
+ specify do
172
+ expect(User.create.tap(&:save).destroy.actions).to eq(%i[
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
+ before_validation after_validation
180
+ before_save before_around_save
181
+ before_update before_around_update
182
+ update
183
+ after_around_update after_update
184
+ after_around_save after_save
185
+ before_destroy before_around_destroy
186
+ destroy
187
+ after_around_destroy after_destroy
188
+ ])
189
+ end
190
+ end
191
+
192
+ describe '.before_destroy, .after_destroy' do
193
+ before do
194
+ User.before_destroy { append :before_destroy }
195
+ User.after_destroy { append :after_destroy }
196
+ end
197
+
198
+ specify { expect(User.new.destroy.actions).to eq(%i[before_destroy destroy after_destroy]) }
199
+ specify { expect(User.create.destroy.actions).to eq(%i[create before_destroy destroy after_destroy]) }
200
+
201
+ specify { expect(User.new.destroy { false }.actions).to eq([:before_destroy]) }
202
+ specify { expect(User.create.destroy { false }.actions).to eq(%i[create before_destroy]) }
203
+ end
204
+
205
+ describe '.around_destroy' do
206
+ before do
207
+ User.around_destroy do |_, block|
208
+ append :before_around_destroy
209
+ block.call
210
+ append :after_around_destroy
211
+ end
212
+ end
213
+
214
+ specify { expect(User.new.destroy.actions).to eq(%i[before_around_destroy destroy after_around_destroy]) }
215
+ specify { expect(User.create.destroy.actions).to eq(%i[create before_around_destroy destroy after_around_destroy]) }
216
+
217
+ specify { expect(User.new.destroy { false }.actions).to eq(%i[before_around_destroy after_around_destroy]) }
218
+ specify { expect(User.create.destroy { false }.actions).to eq(%i[create before_around_destroy after_around_destroy]) }
219
+ end
220
+
221
+ context 'unsavable, undestroyable' do
222
+ before do
223
+ stub_model(:user) do
224
+ include Granite::Form::Model::Callbacks
225
+
226
+ attribute :actions, Array, default: []
227
+ attribute :validated, Boolean, default: false
228
+
229
+ validates :validated, presence: true
230
+
231
+ def append(action)
232
+ self.actions = actions + [action]
233
+ end
234
+ end
235
+ end
236
+
237
+ before do
238
+ User.before_validation { append :before_validation }
239
+ User.after_validation { append :after_validation }
240
+
241
+ User.before_save { append :before_save }
242
+ User.after_save { append :after_save }
243
+ User.around_save do |&block|
244
+ append :before_around_save
245
+ block.call
246
+ append :after_around_save
247
+ end
248
+
249
+ User.before_create { append :before_create }
250
+ User.after_create { append :after_create }
251
+ User.around_create do |&block|
252
+ append :before_around_create
253
+ block.call
254
+ append :after_around_create
255
+ end
256
+
257
+ User.before_update { append :before_update }
258
+ User.after_update { append :after_update }
259
+ User.around_update do |&block|
260
+ append :before_around_update
261
+ block.call
262
+ append :after_around_update
263
+ end
264
+
265
+ User.before_destroy { append :before_destroy }
266
+ User.after_destroy { append :after_destroy }
267
+ User.around_destroy do |&block|
268
+ append :before_around_destroy
269
+ block.call
270
+ append :after_around_destroy
271
+ end
272
+ end
273
+
274
+ let(:user) { User.new }
275
+
276
+ specify do
277
+ begin
278
+ user.save
279
+ rescue Granite::Form::UnsavableObject
280
+ expect(user.actions).to eq([])
281
+ end
282
+ end
283
+
284
+ specify do
285
+ begin
286
+ user.save!
287
+ rescue Granite::Form::UnsavableObject
288
+ expect(user.actions).to eq([])
289
+ end
290
+ end
291
+
292
+ specify do
293
+ user.save { true }
294
+ expect(user.actions).to eq(%i[before_validation after_validation])
295
+ end
296
+
297
+ specify do
298
+ begin
299
+ user.save! { true }
300
+ rescue Granite::Form::ValidationError
301
+ expect(user.actions).to eq(%i[before_validation after_validation])
302
+ end
303
+ end
304
+
305
+ specify do
306
+ begin
307
+ user.update({})
308
+ rescue Granite::Form::UnsavableObject
309
+ expect(user.actions).to eq([])
310
+ end
311
+ end
312
+
313
+ specify do
314
+ begin
315
+ user.update!({})
316
+ rescue Granite::Form::UnsavableObject
317
+ expect(user.actions).to eq([])
318
+ end
319
+ end
320
+
321
+ specify do
322
+ begin
323
+ user.destroy
324
+ rescue Granite::Form::UndestroyableObject
325
+ expect(user.actions).to eq([])
326
+ end
327
+ end
328
+
329
+ specify do
330
+ begin
331
+ user.destroy!
332
+ rescue Granite::Form::UndestroyableObject
333
+ expect(user.actions).to eq([])
334
+ end
335
+ end
336
+ end
337
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Granite::Form::Model::Conventions do
4
+ let(:model) { stub_model }
5
+
6
+ specify { expect([model].flatten).to eq([model]) }
7
+ specify { expect(model.i18n_scope).to eq(:granite) }
8
+ specify { expect(model.new).not_to be_persisted }
9
+ specify { expect(model.new).to be_new_record }
10
+ specify { expect(model.new).to be_new_object }
11
+ end
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+
3
+ describe Granite::Form::Model::Dirty do
4
+ before do
5
+ stub_class(:author, ActiveRecord::Base) {}
6
+ stub_model :premodel do
7
+ include Granite::Form::Model::Persistence
8
+ include Granite::Form::Model::Localization
9
+ include Granite::Form::Model::Associations
10
+
11
+ attribute :age, Integer, default: 33
12
+ alias_attribute :a, :age
13
+ end
14
+ stub_model :model, Premodel do
15
+ include Granite::Form::Model::Dirty
16
+
17
+ references_one :author
18
+ references_many :authors
19
+ embeds_one :something do
20
+ attribute :value, String
21
+ end
22
+ attribute :name, String
23
+ alias_attribute :n, :name
24
+ collection :numbers, Integer
25
+ localized :title, String
26
+ end
27
+ end
28
+
29
+ let(:author) { Author.create!(name: 'Name') }
30
+ let(:other_author) { Author.create!(name: 'Other') }
31
+
32
+ specify { expect(Model.new.changes).to eq({}) }
33
+ specify { expect(Model.new.tap { |m| m.create_something(value: 'Value') }.changes).to eq({}) }
34
+
35
+ specify { expect(Model.new(author: author).changes).to eq('author_id' => [nil, author.id]) }
36
+ specify { expect(Model.new(author_id: author.id).changes).to eq('author_id' => [nil, author.id]) }
37
+ specify { expect(Model.new(authors: [author]).changes).to eq('author_ids' => [[], [author.id]]) }
38
+ specify { expect(Model.new(author_ids: [author.id]).changes).to eq('author_ids' => [[], [author.id]]) }
39
+
40
+ specify do
41
+ expect(Model.new(author: author, name: 'Name2').changes)
42
+ .to eq('author_id' => [nil, author.id], 'name' => [nil, 'Name2'])
43
+ end
44
+
45
+ specify do
46
+ expect(Model.instantiate(author_id: other_author.id)
47
+ .tap { |m| m.update(author_id: author.id) }.changes)
48
+ .to eq('author_id' => [other_author.id, author.id])
49
+ end
50
+ specify do
51
+ expect(Model.instantiate(author_id: other_author.id)
52
+ .tap { |m| m.update(author: author) }.changes)
53
+ .to eq('author_id' => [other_author.id, author.id])
54
+ end
55
+ specify do
56
+ expect(Model.instantiate(author_ids: [other_author.id])
57
+ .tap { |m| m.update(author_ids: [author.id]) }.changes)
58
+ .to eq('author_ids' => [[other_author.id], [author.id]])
59
+ end
60
+ specify do
61
+ expect(Model.instantiate(author_ids: [other_author.id])
62
+ .tap { |m| m.update(authors: [author]) }.changes)
63
+ .to eq('author_ids' => [[other_author.id], [author.id]])
64
+ end
65
+
66
+ specify { expect(Model.new(a: 'blabla').changes).to eq('age' => [33, nil]) }
67
+ specify { expect(Model.new(a: '42').changes).to eq('age' => [33, 42]) }
68
+ specify { expect(Model.instantiate(age: '42').changes).to eq({}) }
69
+ specify { expect(Model.instantiate(age: '42').tap { |m| m.update(a: '43') }.changes).to eq('age' => [42, 43]) }
70
+ specify { expect(Model.new(a: '42').tap { |m| m.update(a: '43') }.changes).to eq('age' => [33, 43]) }
71
+ specify { expect(Model.new(numbers: '42').changes).to eq('numbers' => [[], [42]]) }
72
+
73
+ # Have no idea how should it work right now
74
+ specify { expect(Model.new(title: 'Hello').changes).to eq('title' => [nil, 'Hello']) }
75
+ specify { expect(Model.new(title_translations: {en: 'Hello'}).changes).to eq('title' => [nil, 'Hello']) }
76
+
77
+ specify { expect(Model.new).not_to respond_to :something_changed? }
78
+ specify { expect(Model.new).to respond_to :n_changed? }
79
+
80
+ specify { expect(Model.new(a: '42')).to be_age_changed }
81
+ specify { expect(Model.new(a: '42')).to be_a_changed }
82
+ specify { expect(Model.new(a: '42').age_change).to eq([33, 42]) }
83
+ specify { expect(Model.new(a: '42').a_change).to eq([33, 42]) }
84
+ end