granite-form 0.1.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 (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