reform 2.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.travis.yml +11 -0
  4. data/CHANGES.md +415 -0
  5. data/Gemfile +19 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +339 -0
  8. data/Rakefile +15 -0
  9. data/TODO.md +45 -0
  10. data/gemfiles/Gemfile.disposable-0.3 +6 -0
  11. data/lib/reform.rb +8 -0
  12. data/lib/reform/contract.rb +77 -0
  13. data/lib/reform/contract/errors.rb +43 -0
  14. data/lib/reform/contract/validate.rb +33 -0
  15. data/lib/reform/form.rb +94 -0
  16. data/lib/reform/form/call.rb +23 -0
  17. data/lib/reform/form/coercion.rb +3 -0
  18. data/lib/reform/form/composition.rb +34 -0
  19. data/lib/reform/form/dry.rb +67 -0
  20. data/lib/reform/form/module.rb +27 -0
  21. data/lib/reform/form/mongoid.rb +37 -0
  22. data/lib/reform/form/orm.rb +26 -0
  23. data/lib/reform/form/populator.rb +123 -0
  24. data/lib/reform/form/prepopulate.rb +24 -0
  25. data/lib/reform/form/validate.rb +60 -0
  26. data/lib/reform/mongoid.rb +4 -0
  27. data/lib/reform/validation.rb +40 -0
  28. data/lib/reform/validation/groups.rb +73 -0
  29. data/lib/reform/version.rb +3 -0
  30. data/reform.gemspec +29 -0
  31. data/test/benchmarking.rb +26 -0
  32. data/test/call_test.rb +23 -0
  33. data/test/changed_test.rb +41 -0
  34. data/test/coercion_test.rb +66 -0
  35. data/test/composition_test.rb +149 -0
  36. data/test/contract_test.rb +77 -0
  37. data/test/default_test.rb +22 -0
  38. data/test/deprecation_test.rb +27 -0
  39. data/test/deserialize_test.rb +104 -0
  40. data/test/errors_test.rb +165 -0
  41. data/test/feature_test.rb +65 -0
  42. data/test/fixtures/dry_error_messages.yml +44 -0
  43. data/test/form_option_test.rb +24 -0
  44. data/test/form_test.rb +57 -0
  45. data/test/from_test.rb +75 -0
  46. data/test/inherit_test.rb +119 -0
  47. data/test/module_test.rb +142 -0
  48. data/test/parse_pipeline_test.rb +15 -0
  49. data/test/populate_test.rb +270 -0
  50. data/test/populator_skip_test.rb +28 -0
  51. data/test/prepopulator_test.rb +112 -0
  52. data/test/read_only_test.rb +3 -0
  53. data/test/readable_test.rb +30 -0
  54. data/test/readonly_test.rb +14 -0
  55. data/test/reform_test.rb +223 -0
  56. data/test/save_test.rb +89 -0
  57. data/test/setup_test.rb +48 -0
  58. data/test/skip_if_test.rb +74 -0
  59. data/test/skip_setter_and_getter_test.rb +54 -0
  60. data/test/test_helper.rb +49 -0
  61. data/test/validate_test.rb +420 -0
  62. data/test/validation/dry_test.rb +60 -0
  63. data/test/validation/dry_validation_test.rb +352 -0
  64. data/test/validation/errors.yml +4 -0
  65. data/test/virtual_test.rb +24 -0
  66. data/test/writeable_test.rb +29 -0
  67. metadata +265 -0
@@ -0,0 +1,48 @@
1
+ require "test_helper"
2
+
3
+ class SetupTest < MiniTest::Spec
4
+ Song = Struct.new(:title, :album, :composer)
5
+ Album = Struct.new(:name, :songs, :artist)
6
+ Artist = Struct.new(:name)
7
+
8
+ class AlbumForm < Reform::Form
9
+ property :name
10
+ collection :songs do
11
+ property :title
12
+
13
+ property :composer do
14
+ property :name
15
+ end
16
+ end
17
+
18
+ property :artist do
19
+ property :name
20
+ end
21
+ end
22
+
23
+ let (:song) { Song.new("Broken") }
24
+ let (:song_with_composer) { Song.new("Resist Stance", nil, composer) }
25
+ let (:composer) { Artist.new("Greg Graffin") }
26
+ let (:artist) { Artist.new("Bad Religion") }
27
+
28
+ describe "with nested objects" do
29
+ let (:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
30
+
31
+ it do
32
+ form = AlbumForm.new(album)
33
+
34
+ form.name.must_equal "The Dissent Of Man"
35
+ form.songs[0].title.must_equal "Broken"
36
+ form.songs[0].composer.must_equal nil
37
+ form.songs[1].title.must_equal "Resist Stance"
38
+ form.songs[1].composer.name.must_equal "Greg Graffin"
39
+ form.artist.name.must_equal "Bad Religion"
40
+
41
+ # make sure all is wrapped in forms.
42
+ form.songs[0].must_be_kind_of Reform::Form
43
+ form.songs[1].must_be_kind_of Reform::Form
44
+ form.songs[1].composer.must_be_kind_of Reform::Form
45
+ form.artist.must_be_kind_of Reform::Form
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,74 @@
1
+ require 'test_helper'
2
+
3
+ class SkipIfTest < BaseTest
4
+
5
+ class AlbumForm < Reform::Form
6
+ property :title
7
+
8
+ property :hit, skip_if: lambda { |options| options[:fragment]["title"]=="" } do
9
+ property :title
10
+ validation do
11
+ key(:title).required
12
+ end
13
+ end
14
+
15
+ collection :songs, skip_if: :skip_song?, populate_if_empty: BaseTest::Song do
16
+ property :title
17
+ end
18
+
19
+ def skip_song?(options)
20
+ options[:fragment]["title"].nil?
21
+ end
22
+ end
23
+
24
+
25
+ let (:hit) { Song.new }
26
+ let (:album) { Album.new(nil, hit, [], nil) }
27
+
28
+ # deserializes when present.
29
+ it do
30
+ form = AlbumForm.new(album)
31
+ form.validate("hit" => {"title" => "Altar Of Sacrifice"}).must_equal true
32
+ form.hit.title.must_equal "Altar Of Sacrifice"
33
+ end
34
+
35
+ # skips deserialization when not present.
36
+ it do
37
+ form = AlbumForm.new(Album.new)
38
+ form.validate("hit" => {"title" => ""}).must_equal true
39
+ form.hit.must_equal nil # hit hasn't been deserialised.
40
+ end
41
+
42
+ # skips deserialization when not present.
43
+ it do
44
+ form = AlbumForm.new(Album.new(nil, nil, []))
45
+ form.validate("songs" => [{"title" => "Waste Of Breath"}, {"title" => nil}]).must_equal true
46
+ form.songs.size.must_equal 1
47
+ form.songs[0].title.must_equal "Waste Of Breath"
48
+ end
49
+ end
50
+
51
+ class SkipIfAllBlankTest < BaseTest
52
+ # skip_if: :all_blank"
53
+ class AlbumForm < Reform::Form
54
+ collection :songs, skip_if: :all_blank, populate_if_empty: BaseTest::Song do
55
+ property :title
56
+ property :length
57
+ end
58
+ end
59
+
60
+ # create only one object.
61
+ it do
62
+ form = AlbumForm.new(OpenStruct.new(songs: []))
63
+ form.validate("songs" => [{"title"=>"Apathy"}, {"title"=>"", "length" => ""}]).must_equal true
64
+ form.songs.size.must_equal 1
65
+ form.songs[0].title.must_equal "Apathy"
66
+ end
67
+
68
+ it do
69
+ form = AlbumForm.new(OpenStruct.new(songs: []))
70
+ form.validate("songs" => [{"title"=>"", "length" => ""}, {"title"=>"Apathy"}]).must_equal true
71
+ form.songs.size.must_equal 1
72
+ form.songs[0].title.must_equal "Apathy"
73
+ end
74
+ end
@@ -0,0 +1,54 @@
1
+ require "test_helper"
2
+
3
+ # Overridden setter won't be called in setup.
4
+ # Overridden getter won't be called in sync.
5
+ class SetupSkipSetterAndGetterTest < MiniTest::Spec
6
+ Song = Struct.new(:title, :album, :composer)
7
+ Album = Struct.new(:title, :artist)
8
+ Artist = Struct.new(:name)
9
+
10
+ class AlbumForm < Reform::Form
11
+ property :title
12
+
13
+ def title
14
+ super.upcase
15
+ end
16
+
17
+ def title=(v)
18
+ super v.reverse
19
+ end
20
+
21
+ property :artist do
22
+ property :name
23
+
24
+ def name
25
+ super.downcase
26
+ end
27
+
28
+ def name=(v)
29
+ super v.chop
30
+ end
31
+ end
32
+ end
33
+
34
+ let (:artist) { Artist.new("Bad Religion") }
35
+
36
+
37
+ it do
38
+ album = Album.new("Greatest Hits", artist)
39
+ form = AlbumForm.new(album)
40
+
41
+ form.title.must_equal "GREATEST HITS"
42
+ form.artist.name.must_equal "bad religion"
43
+
44
+ form.validate("title" => "Resiststance", "artist" => {"name" => "Greg Graffin"})
45
+
46
+ form.title.must_equal "ECNATSTSISER" # first, setter called, then getter.
47
+ form.artist.name.must_equal "greg graffi"
48
+
49
+ form.sync
50
+
51
+ album.title.must_equal "ecnatstsiseR" # setter called, but not getter.
52
+ album.artist.name.must_equal "Greg Graffi"
53
+ end
54
+ end
@@ -0,0 +1,49 @@
1
+ require "reform"
2
+ require 'minitest/autorun'
3
+ require "representable/debug"
4
+ require "declarative/testing"
5
+ require "pp"
6
+
7
+ class BaseTest < MiniTest::Spec
8
+ class AlbumForm < Reform::Form
9
+ property :title
10
+
11
+ property :hit do
12
+ property :title
13
+ end
14
+
15
+ collection :songs do
16
+ property :title
17
+ end
18
+ end
19
+
20
+ Song = Struct.new(:title, :length)
21
+ Album = Struct.new(:title, :hit, :songs, :band)
22
+ Band = Struct.new(:label)
23
+ Label = Struct.new(:name)
24
+ Length = Struct.new(:minutes, :seconds)
25
+
26
+
27
+ let (:hit) { Song.new("Roxanne") }
28
+ end
29
+
30
+ MiniTest::Spec.class_eval do
31
+ module Saveable
32
+ def save
33
+ @saved = true
34
+ end
35
+
36
+ def saved?
37
+ @saved
38
+ end
39
+ end
40
+ end
41
+
42
+ require "reform/form/dry"
43
+ Reform::Contract.class_eval do
44
+ feature Reform::Form::Dry
45
+ end
46
+ # FIXME!
47
+ Reform::Form.class_eval do
48
+ feature Reform::Form::Dry
49
+ end
@@ -0,0 +1,420 @@
1
+ require 'test_helper'
2
+
3
+ class ContractValidateTest < MiniTest::Spec
4
+ Song = Struct.new(:title, :album, :composer)
5
+ Album = Struct.new(:name, :songs, :artist)
6
+ Artist = Struct.new(:name)
7
+
8
+ class AlbumForm < Reform::Contract
9
+ property :name
10
+ validation do
11
+ key(:name).required
12
+ end
13
+
14
+ collection :songs do
15
+ property :title
16
+ validation do
17
+ key(:title).required
18
+ end
19
+
20
+ property :composer do
21
+ validation do
22
+ key(:name).required
23
+ end
24
+ property :name
25
+ end
26
+ end
27
+
28
+ property :artist do
29
+ property :name
30
+ end
31
+ end
32
+
33
+ let (:song) { Song.new("Broken") }
34
+ let (:song_with_composer) { Song.new("Resist Stance", nil, composer) }
35
+ let (:composer) { Artist.new("Greg Graffin") }
36
+ let (:artist) { Artist.new("Bad Religion") }
37
+ let (:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
38
+
39
+ let (:form) { AlbumForm.new(album) }
40
+
41
+ # valid
42
+ it do
43
+ form.validate.must_equal true
44
+ form.errors.messages.inspect.must_equal "{}"
45
+ end
46
+
47
+ # invalid
48
+ it do
49
+ album.songs[1].composer.name = nil
50
+ album.name = nil
51
+
52
+ form.validate.must_equal false
53
+ form.errors.messages.inspect.must_equal "{:name=>[\"is missing\"], :\"songs.composer.name\"=>[\"is missing\"]}"
54
+ end
55
+ end
56
+
57
+
58
+ # no configuration results in "sync" (formerly known as parse_strategy: :sync).
59
+ class ValidateWithoutConfigurationTest < MiniTest::Spec
60
+ Song = Struct.new(:title, :album, :composer)
61
+ Album = Struct.new(:name, :songs, :artist)
62
+ Artist = Struct.new(:name)
63
+
64
+ class AlbumForm < Reform::Form
65
+ property :name
66
+ validation do
67
+ key(:name).required
68
+ end
69
+
70
+ collection :songs do
71
+
72
+ property :title
73
+ validation do
74
+ key(:title).required
75
+ end
76
+
77
+ property :composer do
78
+ property :name
79
+ validation do
80
+ key(:name).required
81
+ end
82
+ end
83
+ end
84
+
85
+ property :artist do
86
+ property :name
87
+ end
88
+ end
89
+
90
+ let (:song) { Song.new("Broken") }
91
+ let (:song_with_composer) { Song.new("Resist Stance", nil, composer) }
92
+ let (:composer) { Artist.new("Greg Graffin") }
93
+ let (:artist) { Artist.new("Bad Religion") }
94
+ let (:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
95
+
96
+ let (:form) { AlbumForm.new(album) }
97
+
98
+ # valid.
99
+ it do
100
+ object_ids = {song: form.songs[0].object_id, song_with_composer: form.songs[1].object_id,
101
+ artist: form.artist.object_id, composer: form.songs[1].composer.object_id}
102
+
103
+ form.validate(
104
+ "name" => "Best Of",
105
+ "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne", "composer" => {"name" => "Sting"}}],
106
+ "artist" => {"name" => "The Police"},
107
+ ).must_equal true
108
+
109
+ form.errors.messages.inspect.must_equal "{}"
110
+
111
+ # form has updated.
112
+ form.name.must_equal "Best Of"
113
+ form.songs[0].title.must_equal "Fallout"
114
+ form.songs[1].title.must_equal "Roxanne"
115
+ form.songs[1].composer.name.must_equal "Sting"
116
+ form.artist.name.must_equal "The Police"
117
+
118
+ # objects are still the same.
119
+ form.songs[0].object_id.must_equal object_ids[:song]
120
+ form.songs[1].object_id.must_equal object_ids[:song_with_composer]
121
+ form.songs[1].composer.object_id.must_equal object_ids[:composer]
122
+ form.artist.object_id.must_equal object_ids[:artist]
123
+
124
+
125
+ # model has not changed, yet.
126
+ album.name.must_equal "The Dissent Of Man"
127
+ album.songs[0].title.must_equal "Broken"
128
+ album.songs[1].title.must_equal "Resist Stance"
129
+ album.songs[1].composer.name.must_equal "Greg Graffin"
130
+ album.artist.name.must_equal "Bad Religion"
131
+ end
132
+
133
+ # with symbols.
134
+ it do
135
+ form.validate(
136
+ name: "Best Of",
137
+ songs: [{title: "The X-Creep"}, {title: "Trudging", composer: {name: "SNFU"}}],
138
+ artist: {name: "The Police"},
139
+ ).must_equal true
140
+
141
+ form.name.must_equal "Best Of"
142
+ form.songs[0].title.must_equal "The X-Creep"
143
+ form.songs[1].title.must_equal "Trudging"
144
+ form.songs[1].composer.name.must_equal "SNFU"
145
+ form.artist.name.must_equal "The Police"
146
+ end
147
+
148
+ # throws exception when no populators.
149
+ it do
150
+ album = Album.new("The Dissent Of Man", [])
151
+
152
+ assert_raises RuntimeError do
153
+ AlbumForm.new(album).validate(songs: {title: "Resist-Stance"})
154
+ end
155
+ end
156
+ end
157
+
158
+ class ValidateWithInternalPopulatorOptionTest < MiniTest::Spec
159
+ Song = Struct.new(:title, :album, :composer)
160
+ Album = Struct.new(:name, :songs, :artist)
161
+ Artist = Struct.new(:name)
162
+
163
+ class AlbumForm < Reform::Form
164
+ property :name
165
+ validation do
166
+ key(:name).required
167
+ end
168
+
169
+ collection :songs,
170
+ internal_populator: lambda { |input, options|
171
+ collection = options[:represented].songs
172
+ (item = collection[options[:index]]) ? item : collection.insert(options[:index], Song.new) } do
173
+
174
+ property :title
175
+ validation do
176
+ key(:title).required
177
+ end
178
+
179
+ property :composer, internal_populator: lambda { |input, options| (item = options[:represented].composer) ? item : Artist.new } do
180
+ property :name
181
+ validation do
182
+ key(:name).required
183
+ end
184
+ end
185
+ end
186
+
187
+ property :artist, internal_populator: lambda { |input, options| (item = options[:represented].artist) ? item : Artist.new } do
188
+ property :name
189
+ validation do
190
+ key(:name).required
191
+ end
192
+ end
193
+ end
194
+
195
+ let (:song) { Song.new("Broken") }
196
+ let (:song_with_composer) { Song.new("Resist Stance", nil, composer) }
197
+ let (:composer) { Artist.new("Greg Graffin") }
198
+ let (:artist) { Artist.new("Bad Religion") }
199
+ let (:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
200
+
201
+ let (:form) { AlbumForm.new(album) }
202
+
203
+ # valid.
204
+ it("xxx") do
205
+ form.validate(
206
+ "name" => "Best Of",
207
+ "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne", "composer" => {"name" => "Sting"}}],
208
+ "artist" => {"name" => "The Police"},
209
+ ).must_equal true
210
+
211
+ form.errors.messages.inspect.must_equal "{}"
212
+
213
+ # form has updated.
214
+ form.name.must_equal "Best Of"
215
+ form.songs[0].title.must_equal "Fallout"
216
+ form.songs[1].title.must_equal "Roxanne"
217
+ form.songs[1].composer.name.must_equal "Sting"
218
+ form.artist.name.must_equal "The Police"
219
+
220
+
221
+ # model has not changed, yet.
222
+ album.name.must_equal "The Dissent Of Man"
223
+ album.songs[0].title.must_equal "Broken"
224
+ album.songs[1].title.must_equal "Resist Stance"
225
+ album.songs[1].composer.name.must_equal "Greg Graffin"
226
+ album.artist.name.must_equal "Bad Religion"
227
+ end
228
+
229
+ # invalid.
230
+ it do
231
+ form.validate(
232
+ "name" => "",
233
+ "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne", "composer" => {"name" => ""}}],
234
+ "artist" => {"name" => ""},
235
+ ).must_equal false
236
+
237
+ form.errors.messages.inspect.must_equal "{:name=>[\"must be filled\"], :\"songs.composer.name\"=>[\"must be filled\"], :\"artist.name\"=>[\"must be filled\"]}"
238
+ end
239
+
240
+ # adding to collection via :instance.
241
+ # valid.
242
+ it do
243
+ form.validate(
244
+ "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"}, {"title" => "Rime Of The Ancient Mariner"}],
245
+ ).must_equal true
246
+
247
+ form.errors.messages.inspect.must_equal "{}"
248
+
249
+ # form has updated.
250
+ form.name.must_equal "The Dissent Of Man"
251
+ form.songs[0].title.must_equal "Fallout"
252
+ form.songs[1].title.must_equal "Roxanne"
253
+ form.songs[1].composer.name.must_equal "Greg Graffin"
254
+ form.songs[1].title.must_equal "Roxanne"
255
+ form.songs[2].title.must_equal "Rime Of The Ancient Mariner" # new song added.
256
+ form.songs.size.must_equal 3
257
+ form.artist.name.must_equal "Bad Religion"
258
+
259
+
260
+ # model has not changed, yet.
261
+ album.name.must_equal "The Dissent Of Man"
262
+ album.songs[0].title.must_equal "Broken"
263
+ album.songs[1].title.must_equal "Resist Stance"
264
+ album.songs[1].composer.name.must_equal "Greg Graffin"
265
+ album.songs.size.must_equal 2
266
+ album.artist.name.must_equal "Bad Religion"
267
+ end
268
+
269
+
270
+ # allow writeable: false even in the deserializer.
271
+ class SongForm < Reform::Form
272
+ property :title, deserializer: {writeable: false}
273
+ end
274
+
275
+ it do
276
+ form = SongForm.new(song = Song.new)
277
+ form.validate("title" => "Ignore me!")
278
+ form.title.must_equal nil
279
+ form.title = "Unopened"
280
+ form.sync # only the deserializer is marked as not-writeable.
281
+ song.title.must_equal "Unopened"
282
+ end
283
+ end
284
+
285
+ # # not sure if we should catch that in Reform or rather do that in disposable. this is https://github.com/apotonick/reform/pull/104
286
+ # # describe ":populator with :empty" do
287
+ # # let (:form) {
288
+ # # Class.new(Reform::Form) do
289
+ # # collection :songs, :empty => true, :populator => lambda { |fragment, index, args|
290
+ # # songs[index] = args.binding[:form].new(Song.new)
291
+ # # } do
292
+ # # property :title
293
+ # # end
294
+ # # end
295
+ # # }
296
+
297
+ # # let (:params) {
298
+ # # {
299
+ # # "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"}]
300
+ # # }
301
+ # # }
302
+
303
+ # # subject { form.new(Album.new("Hits", [], [])) }
304
+
305
+ # # before { subject.validate(params) }
306
+
307
+ # # it { subject.songs[0].title.must_equal "Fallout" }
308
+ # # it { subject.songs[1].title.must_equal "Roxanne" }
309
+ # # end
310
+
311
+
312
+ # # test cardinalities.
313
+ # describe "with empty collection and cardinality" do
314
+ # let (:album) { Album.new }
315
+
316
+ # subject { Class.new(Reform::Form) do
317
+ # include Reform::Form::ActiveModel
318
+ # model :album
319
+
320
+ # collection :songs do
321
+ # property :title
322
+ # end
323
+
324
+ # property :hit do
325
+ # property :title
326
+ # end
327
+
328
+ # validates :songs, :length => {:minimum => 1}
329
+ # validates :hit, :presence => true
330
+ # end.new(album) }
331
+
332
+
333
+ # describe "invalid" do
334
+ # before { subject.validate({}).must_equal false }
335
+
336
+ # it do
337
+ # # ensure that only hit and songs keys are present
338
+ # subject.errors.messages.keys.sort.must_equal([:hit, :songs])
339
+ # # validate content of hit and songs keys
340
+ # subject.errors.messages[:hit].must_equal(["must be filled"])
341
+ # subject.errors.messages[:songs].first.must_match(/\Ais too short \(minimum is 1 characters?\)\z/)
342
+ # end
343
+ # end
344
+
345
+
346
+ # describe "valid" do
347
+ # let (:album) { Album.new(nil, Song.new, [Song.new("Urban Myth")]) }
348
+
349
+ # before {
350
+ # subject.validate({"songs" => [{"title"=>"Daddy, Brother, Lover, Little Boy"}], "hit" => {"title"=>"The Horse"}}).
351
+ # must_equal true
352
+ # }
353
+
354
+ # it { subject.errors.messages.must_equal({}) }
355
+ # end
356
+ # end
357
+
358
+
359
+
360
+
361
+
362
+ # # providing manual validator method allows accessing form's API.
363
+ # describe "with ::validate" do
364
+ # let (:form) {
365
+ # Class.new(Reform::Form) do
366
+ # property :title
367
+
368
+ # validate :title?
369
+
370
+ # def title?
371
+ # errors.add :title, "not lowercase" if title == "Fallout"
372
+ # end
373
+ # end
374
+ # }
375
+
376
+ # let (:params) { {"title" => "Fallout"} }
377
+ # let (:song) { Song.new("Englishman") }
378
+
379
+ # subject { form.new(song) }
380
+
381
+ # before { @res = subject.validate(params) }
382
+
383
+ # it { @res.must_equal false }
384
+ # it { subject.errors.messages.must_equal({:title=>["not lowercase"]}) }
385
+ # end
386
+
387
+
388
+ # # overriding the reader for a nested form should only be considered when rendering.
389
+ # describe "with overridden reader for nested form" do
390
+ # let (:form) {
391
+ # Class.new(Reform::Form) do
392
+ # property :band, :populate_if_empty => lambda { |*| Band.new } do
393
+ # property :label
394
+ # end
395
+
396
+ # collection :songs, :populate_if_empty => lambda { |*| Song.new } do
397
+ # property :title
398
+ # end
399
+
400
+ # def band
401
+ # raise "only call me when rendering the form!"
402
+ # end
403
+
404
+ # def songs
405
+ # raise "only call me when rendering the form!"
406
+ # end
407
+ # end.new(album)
408
+ # }
409
+
410
+ # let (:album) { Album.new }
411
+
412
+ # # don't use #artist when validating!
413
+ # it do
414
+ # form.validate("band" => {"label" => "Hellcat"}, "songs" => [{"title" => "Stand Your Ground"}, {"title" => "Otherside"}])
415
+ # form.sync
416
+ # album.band.label.must_equal "Hellcat"
417
+ # album.songs.first.title.must_equal "Stand Your Ground"
418
+ # end
419
+ # end
420
+ # end