reform 2.2.4

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 (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