reform 2.3.3 → 2.5.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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.travis.yml +0 -3
  4. data/CHANGES.md +9 -0
  5. data/Gemfile +1 -1
  6. data/LICENSE.txt +1 -1
  7. data/README.md +5 -5
  8. data/Rakefile +1 -12
  9. data/lib/reform/contract/validate.rb +1 -1
  10. data/lib/reform/form/dry.rb +47 -9
  11. data/lib/reform/validation/groups.rb +0 -1
  12. data/lib/reform/version.rb +1 -1
  13. data/test/call_test.rb +23 -0
  14. data/test/changed_test.rb +6 -6
  15. data/test/coercion_test.rb +17 -17
  16. data/test/{composition_new_api.rb → composition_test.rb} +27 -28
  17. data/test/{contract_new_api.rb → contract_test.rb} +8 -8
  18. data/test/default_test.rb +2 -2
  19. data/test/deserialize_test.rb +8 -8
  20. data/test/docs/validation_test.rb +134 -0
  21. data/test/{errors_new_api.rb → errors_test.rb} +41 -41
  22. data/test/feature_test.rb +2 -2
  23. data/test/fixtures/dry_error_messages.yml +64 -54
  24. data/test/{form_option_new_api.rb → form_option_test.rb} +1 -1
  25. data/test/{form_new_api.rb → form_test.rb} +3 -3
  26. data/test/from_test.rb +10 -10
  27. data/test/{inherit_new_api.rb → inherit_test.rb} +17 -17
  28. data/test/{module_new_api.rb → module_test.rb} +10 -10
  29. data/test/parse_option_test.rb +7 -7
  30. data/test/parse_pipeline_test.rb +1 -1
  31. data/test/{populate_new_api.rb → populate_test.rb} +112 -53
  32. data/test/populator_skip_test.rb +2 -2
  33. data/test/prepopulator_test.rb +15 -15
  34. data/test/read_only_test.rb +2 -2
  35. data/test/readable_test.rb +3 -3
  36. data/test/{reform_new_api.rb → reform_test.rb} +19 -19
  37. data/test/{save_new_api.rb → save_test.rb} +4 -4
  38. data/test/setup_test.rb +9 -9
  39. data/test/{skip_if_new_api.rb → skip_if_test.rb} +12 -12
  40. data/test/skip_setter_and_getter_test.rb +6 -6
  41. data/test/test_helper.rb +5 -6
  42. data/test/{validate_new_api.rb → validate_test.rb} +65 -78
  43. data/test/validation/{dry_validation_new_api.rb → dry_validation_test.rb} +124 -123
  44. data/test/validation/result_test.rb +14 -14
  45. data/test/virtual_test.rb +7 -7
  46. data/test/writeable_test.rb +8 -8
  47. metadata +35 -68
  48. data/Appraisals +0 -8
  49. data/gemfiles/0.13.0.gemfile +0 -8
  50. data/gemfiles/1.5.0.gemfile +0 -9
  51. data/lib/reform/form/dry/new_api.rb +0 -45
  52. data/lib/reform/form/dry/old_api.rb +0 -61
  53. data/test/call_new_api.rb +0 -23
  54. data/test/call_old_api.rb +0 -23
  55. data/test/composition_old_api.rb +0 -184
  56. data/test/contract_old_api.rb +0 -77
  57. data/test/errors_old_api.rb +0 -230
  58. data/test/fixtures/dry_new_api_error_messages.yml +0 -104
  59. data/test/form_old_api.rb +0 -57
  60. data/test/form_option_old_api.rb +0 -24
  61. data/test/inherit_old_api.rb +0 -105
  62. data/test/module_old_api.rb +0 -146
  63. data/test/populate_old_api.rb +0 -304
  64. data/test/reform_old_api.rb +0 -202
  65. data/test/save_old_api.rb +0 -101
  66. data/test/skip_if_old_api.rb +0 -92
  67. data/test/validate_old_api.rb +0 -410
  68. data/test/validation/dry_validation_old_api.rb +0 -772
@@ -1,202 +0,0 @@
1
- require "test_helper"
2
-
3
- class ReformTest < Minitest::Spec
4
- let(:comp) { OpenStruct.new(name: "Duran Duran", title: "Rio") }
5
-
6
- let(:form) { SongForm.new(comp) }
7
-
8
- class SongForm < TestForm
9
- property :name
10
- property :title
11
-
12
- validation do
13
- required(:name).filled
14
- end
15
- end
16
-
17
- describe "(new) form with empty models" do
18
- let(:comp) { OpenStruct.new }
19
-
20
- it "returns empty fields" do
21
- assert_nil form.title
22
- _(form.name).must_be_nil
23
- end
24
-
25
- describe "and submitted values" do
26
- it "returns filled-out fields" do
27
- form.validate("name" => "Duran Duran")
28
-
29
- assert_nil form.title
30
- _(form.name).must_equal "Duran Duran"
31
- end
32
- end
33
- end
34
-
35
- describe "(edit) form with existing models" do
36
- it "returns filled-out fields" do
37
- _(form.name).must_equal "Duran Duran"
38
- _(form.title).must_equal "Rio"
39
- end
40
- end
41
-
42
- describe "#validate" do
43
- let(:comp) { OpenStruct.new }
44
-
45
- it "ignores unmapped fields in input" do
46
- form.validate("name" => "Duran Duran", :genre => "80s")
47
- assert_raises NoMethodError do
48
- form.genre
49
- end
50
- end
51
-
52
- it "returns true when valid" do
53
- _(form.validate("name" => "Duran Duran")).must_equal true
54
- end
55
-
56
- it "exposes input via property accessors" do
57
- form.validate("name" => "Duran Duran")
58
-
59
- _(form.name).must_equal "Duran Duran"
60
- end
61
-
62
- it "doesn't change model properties" do
63
- form.validate("name" => "Duran Duran")
64
-
65
- assert_nil comp.name # don't touch model, yet.
66
- end
67
-
68
- # TODO: test errors. test valid.
69
- describe "invalid input" do
70
- class ValidatingForm < TestForm
71
- property :name
72
- property :title
73
-
74
- validation do
75
- required(:name).filled
76
- required(:title).filled
77
- end
78
- end
79
- let(:form) { ValidatingForm.new(comp) }
80
-
81
- it "returns false when invalid" do
82
- _(form.validate({})).must_equal false
83
- end
84
-
85
- it "populates errors" do
86
- form.validate({})
87
- _(form.errors.messages).must_equal({name: ["must be filled"], title: ["must be filled"]})
88
- end
89
- end
90
- end
91
-
92
- describe "#save" do
93
- let(:comp) { OpenStruct.new }
94
- let(:form) { SongForm.new(comp) }
95
-
96
- before { form.validate("name" => "Diesel Boy") }
97
-
98
- it "xxpushes data to models" do
99
- form.save
100
-
101
- _(comp.name).must_equal "Diesel Boy"
102
- assert_nil comp.title
103
- end
104
-
105
- describe "#save with block" do
106
- it do
107
- hash = {}
108
-
109
- form.save do |map|
110
- hash = map
111
- end
112
-
113
- _(hash).must_equal({"name" => "Diesel Boy", "title" => nil})
114
- end
115
- end
116
- end
117
-
118
- describe "#model" do
119
- it { _(form.model).must_equal comp }
120
- end
121
-
122
- describe "inheritance" do
123
- class HitForm < SongForm
124
- property :position
125
- validation do
126
- required(:position).filled
127
- end
128
- end
129
-
130
- let(:form) { HitForm.new(OpenStruct.new()) }
131
- it do
132
- form.validate({"title" => "The Body"})
133
- _(form.title).must_equal "The Body"
134
- assert_nil form.position
135
- _(form.errors.messages).must_equal({name: ["must be filled"], position: ["must be filled"]})
136
- end
137
- end
138
- end
139
-
140
- class OverridingAccessorsTest < BaseTest
141
- class SongForm < TestForm
142
- property :title
143
-
144
- def title=(v) # used in #validate.
145
- super v * 2
146
- end
147
-
148
- def title # used in #sync.
149
- super.downcase
150
- end
151
- end
152
-
153
- let(:song) { Song.new("Pray") }
154
- subject { SongForm.new(song) }
155
-
156
- # override reader for presentation.
157
- it { _(subject.title).must_equal "pray" }
158
-
159
- describe "#save" do
160
- before { subject.validate("title" => "Hey Little World") }
161
-
162
- # reader always used
163
- it { _(subject.title).must_equal "hey little worldhey little world" }
164
-
165
- # the reader is not used when saving/syncing.
166
- it do
167
- subject.save do |hash|
168
- _(hash["title"]).must_equal "Hey Little WorldHey Little World"
169
- end
170
- end
171
-
172
- # no reader or writer used when saving/syncing.
173
- it do
174
- song.extend(Saveable)
175
- subject.save
176
- _(song.title).must_equal "Hey Little WorldHey Little World"
177
- end
178
- end
179
- end
180
-
181
- class MethodInFormTest < MiniTest::Spec
182
- class AlbumForm < TestForm
183
- property :title
184
-
185
- def title
186
- "The Suffer And The Witness"
187
- end
188
-
189
- property :hit do
190
- property :title
191
-
192
- def title
193
- "Drones"
194
- end
195
- end
196
- end
197
-
198
- # methods can be used instead of created accessors.
199
- subject { AlbumForm.new(OpenStruct.new(hit: OpenStruct.new)) }
200
- it { _(subject.title).must_equal "The Suffer And The Witness" }
201
- it { _(subject.hit.title).must_equal "Drones" }
202
- end
data/test/save_old_api.rb DELETED
@@ -1,101 +0,0 @@
1
- require "test_helper"
2
-
3
- class SaveTest < BaseTest
4
- Song = Struct.new(:title, :album, :composer)
5
- Album = Struct.new(:name, :songs, :artist)
6
- Artist = Struct.new(:name)
7
-
8
- class AlbumForm < TestForm
9
- property :name
10
- validation do
11
- required(:name).filled
12
- end
13
-
14
- collection :songs do
15
- property :title
16
- validation do
17
- required(:title).filled
18
- end
19
-
20
- property :composer do
21
- property :name
22
- validation do
23
- required(:name).filled
24
- end
25
- end
26
- end
27
-
28
- property :artist, save: false do
29
- property :name
30
- end
31
- end
32
-
33
- module Saveable
34
- def save
35
- @saved = true
36
- end
37
-
38
- def saved?
39
- defined?(@saved) && @saved
40
- end
41
- end
42
-
43
- let(:song) { Song.new("Broken").extend(Saveable) }
44
- # let(:song_with_composer) { Song.new("Resist Stance", nil, composer).extend(Saveable) }
45
- let(:composer) { Artist.new("Greg Graffin").extend(Saveable) }
46
- let(:artist) { Artist.new("Bad Religion").extend(Saveable).extend(Saveable) }
47
- let(:album) { Album.new("The Dissent Of Man", [song], artist).extend(Saveable) }
48
-
49
- let(:form) { AlbumForm.new(album) }
50
-
51
- it do
52
- form.validate("songs" => [{"title" => "Fixed"}])
53
-
54
- form.save
55
-
56
- _(album.saved?).must_equal true
57
- _(album.songs[0].title).must_equal "Fixed"
58
- _(album.songs[0].saved?).must_equal true
59
- assert_nil album.artist.saved?
60
- end
61
-
62
- describe "#sync with block" do
63
- it do
64
- form = AlbumForm.new(Album.new("Greatest Hits"))
65
-
66
- form.validate(name: nil) # nil-out the title.
67
-
68
- nested_hash = nil
69
- form.sync do |hash|
70
- nested_hash = hash
71
- end
72
-
73
- _(nested_hash).must_equal({"name" => nil, "artist" => nil})
74
- end
75
- end
76
- end
77
-
78
- # class SaveWithDynamicOptionsTest < MiniTest::Spec
79
- # Song = Struct.new(:id, :title, :length) do
80
- # include Saveable
81
- # end
82
-
83
- # class SongForm < TestForm
84
- # property :title#, save: false
85
- # property :length, virtual: true
86
- # end
87
-
88
- # let(:song) { Song.new }
89
- # let(:form) { SongForm.new(song) }
90
-
91
- # # we have access to original input value and outside parameters.
92
- # it "xxx" do
93
- # form.validate("title" => "A Poor Man's Memory", "length" => 10)
94
- # length_seconds = 120
95
- # form.save(length: lambda { |value, options| form.model.id = "#{value}: #{length_seconds}" })
96
-
97
- # song.title.must_equal "A Poor Man's Memory"
98
- # assert_nil song.length
99
- # song.id.must_equal "10: 120"
100
- # end
101
- # end
@@ -1,92 +0,0 @@
1
- require "test_helper"
2
-
3
- class SkipIfTest < BaseTest
4
- let(:hit) { Song.new }
5
- let(:album) { Album.new(nil, hit, [], nil) }
6
-
7
- class AlbumForm < TestForm
8
- property :title
9
-
10
- property :hit, skip_if: ->(options) { options[:fragment]["title"] == "" } do
11
- property :title
12
- validation do
13
- required(:title).filled
14
- end
15
- end
16
-
17
- collection :songs, skip_if: :skip_song?, populate_if_empty: BaseTest::Song do
18
- property :title
19
- end
20
-
21
- def skip_song?(options)
22
- options[:fragment]["title"].nil?
23
- end
24
- end
25
-
26
- # deserializes when present.
27
- it do
28
- form = AlbumForm.new(album)
29
- _(form.validate("hit" => {"title" => "Altar Of Sacrifice"})).must_equal true
30
- _(form.hit.title).must_equal "Altar Of Sacrifice"
31
- end
32
-
33
- # skips deserialization when not present.
34
- it do
35
- form = AlbumForm.new(Album.new)
36
- _(form.validate("hit" => {"title" => ""})).must_equal true
37
- assert_nil form.hit # hit hasn't been deserialised.
38
- end
39
-
40
- # skips deserialization when not present.
41
- it do
42
- form = AlbumForm.new(Album.new(nil, nil, []))
43
- _(form.validate("songs" => [{"title" => "Waste Of Breath"}, {"title" => nil}])).must_equal true
44
- _(form.songs.size).must_equal 1
45
- _(form.songs[0].title).must_equal "Waste Of Breath"
46
- end
47
- end
48
-
49
- class SkipIfAllBlankTest < BaseTest
50
- # skip_if: :all_blank"
51
- class AlbumForm < TestForm
52
- collection :songs, skip_if: :all_blank, populate_if_empty: BaseTest::Song do
53
- property :title
54
- property :length
55
- end
56
- end
57
-
58
- # create only one object.
59
- it do
60
- form = AlbumForm.new(OpenStruct.new(songs: []))
61
- _(form.validate("songs" => [{"title" => "Apathy"}, {"title" => "", "length" => ""}])).must_equal true
62
- _(form.songs.size).must_equal 1
63
- _(form.songs[0].title).must_equal "Apathy"
64
- end
65
-
66
- it do
67
- form = AlbumForm.new(OpenStruct.new(songs: []))
68
- _(form.validate("songs" => [{"title" => "", "length" => ""}, {"title" => "Apathy"}])).must_equal true
69
- _(form.songs.size).must_equal 1
70
- _(form.songs[0].title).must_equal "Apathy"
71
- end
72
-
73
- it do
74
- form = AlbumForm.new(OpenStruct.new(songs: []))
75
- _(form.validate(:songs => [{:title=>"", :length => ""}, {:title=>"Apathy"}])).must_equal true
76
- _(form.songs.size).must_equal 1
77
- _(form.songs[0].title).must_equal "Apathy"
78
- end
79
- end
80
-
81
- class InvalidOptionsCombinationTest < BaseTest
82
- it do
83
- assert_raises(Reform::Form::InvalidOptionsCombinationError) do
84
- class AlbumForm < TestForm
85
- collection :songs, skip_if: :all_blank, populator: -> {} do
86
- property :title
87
- property :length
88
- end
89
- end
90
- end
91
- end
92
- end
@@ -1,410 +0,0 @@
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 < TestContract
9
- property :name
10
- validation do
11
- required(:name).filled
12
- end
13
-
14
- collection :songs do
15
- property :title
16
- validation do
17
- required(:title).filled
18
- end
19
-
20
- property :composer do
21
- validation do
22
- required(:name).filled
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=>[\"must be filled\"], :\"songs.composer.name\"=>[\"must be filled\"]}"
54
- end
55
- end
56
-
57
- # no configuration results in "sync" (formerly known as parse_strategy: :sync).
58
- class ValidateWithoutConfigurationTest < MiniTest::Spec
59
- Song = Struct.new(:title, :album, :composer)
60
- Album = Struct.new(:name, :songs, :artist)
61
- Artist = Struct.new(:name)
62
-
63
- class AlbumForm < TestForm
64
- property :name
65
- validation do
66
- required(:name).filled
67
- end
68
-
69
- collection :songs do
70
- property :title
71
- validation do
72
- required(:title).filled
73
- end
74
-
75
- property :composer do
76
- property :name
77
- validation do
78
- required(:name).filled
79
- end
80
- end
81
- end
82
-
83
- property :artist do
84
- property :name
85
- end
86
- end
87
-
88
- let(:song) { Song.new("Broken") }
89
- let(:song_with_composer) { Song.new("Resist Stance", nil, composer) }
90
- let(:composer) { Artist.new("Greg Graffin") }
91
- let(:artist) { Artist.new("Bad Religion") }
92
- let(:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
93
-
94
- let(:form) { AlbumForm.new(album) }
95
-
96
- # valid.
97
- it do
98
- object_ids = {
99
- song: form.songs[0].object_id, song_with_composer: form.songs[1].object_id,
100
- artist: form.artist.object_id, composer: form.songs[1].composer.object_id
101
- }
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
- # model has not changed, yet.
125
- _(album.name).must_equal "The Dissent Of Man"
126
- _(album.songs[0].title).must_equal "Broken"
127
- _(album.songs[1].title).must_equal "Resist Stance"
128
- _(album.songs[1].composer.name).must_equal "Greg Graffin"
129
- _(album.artist.name).must_equal "Bad Religion"
130
- end
131
-
132
- # with symbols.
133
- it do
134
- _(form.validate(
135
- name: "Best Of",
136
- songs: [{title: "The X-Creep"}, {title: "Trudging", composer: {name: "SNFU"}}],
137
- artist: {name: "The Police"}
138
- )).must_equal true
139
-
140
- _(form.name).must_equal "Best Of"
141
- _(form.songs[0].title).must_equal "The X-Creep"
142
- _(form.songs[1].title).must_equal "Trudging"
143
- _(form.songs[1].composer.name).must_equal "SNFU"
144
- _(form.artist.name).must_equal "The Police"
145
- end
146
-
147
- # throws exception when no populators.
148
- it do
149
- album = Album.new("The Dissent Of Man", [])
150
-
151
- assert_raises RuntimeError do
152
- AlbumForm.new(album).validate(songs: {title: "Resist-Stance"})
153
- end
154
- end
155
- end
156
-
157
- class ValidateWithInternalPopulatorOptionTest < MiniTest::Spec
158
- Song = Struct.new(:title, :album, :composer)
159
- Album = Struct.new(:name, :songs, :artist)
160
- Artist = Struct.new(:name)
161
-
162
- class AlbumForm < TestForm
163
- property :name
164
- validation do
165
- required(:name).filled
166
- end
167
-
168
- collection :songs,
169
- internal_populator: ->(input, options) {
170
- collection = options[:represented].songs
171
- (item = collection[options[:index]]) ? item : collection.insert(options[:index], Song.new)
172
- } do
173
- property :title
174
- validation do
175
- required(:title).filled
176
- end
177
-
178
- property :composer, internal_populator: ->(input, options) { (item = options[:represented].composer) ? item : Artist.new } do
179
- property :name
180
- validation do
181
- required(:name).filled
182
- end
183
- end
184
- end
185
-
186
- property :artist, internal_populator: ->(input, options) { (item = options[:represented].artist) ? item : Artist.new } do
187
- property :name
188
- validation do
189
- required(:name).filled
190
- end
191
- end
192
- end
193
-
194
- let(:song) { Song.new("Broken") }
195
- let(:song_with_composer) { Song.new("Resist Stance", nil, composer) }
196
- let(:composer) { Artist.new("Greg Graffin") }
197
- let(:artist) { Artist.new("Bad Religion") }
198
- let(:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
199
-
200
- let(:form) { AlbumForm.new(album) }
201
-
202
- # valid.
203
- it("xxx") do
204
- _(form.validate(
205
- "name" => "Best Of",
206
- "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne", "composer" => {"name" => "Sting"}}],
207
- "artist" => {"name" => "The Police"},
208
- )).must_equal true
209
- _(form.valid?).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
- # model has not changed, yet.
221
- _(album.name).must_equal "The Dissent Of Man"
222
- _(album.songs[0].title).must_equal "Broken"
223
- _(album.songs[1].title).must_equal "Resist Stance"
224
- _(album.songs[1].composer.name).must_equal "Greg Graffin"
225
- _(album.artist.name).must_equal "Bad Religion"
226
- end
227
-
228
- # invalid.
229
- it do
230
- _(form.validate(
231
- "name" => "",
232
- "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne", "composer" => {"name" => ""}}],
233
- "artist" => {"name" => ""},
234
- )).must_equal false
235
- _(form.valid?).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
- # model has not changed, yet.
260
- _(album.name).must_equal "The Dissent Of Man"
261
- _(album.songs[0].title).must_equal "Broken"
262
- _(album.songs[1].title).must_equal "Resist Stance"
263
- _(album.songs[1].composer.name).must_equal "Greg Graffin"
264
- _(album.songs.size).must_equal 2
265
- _(album.artist.name).must_equal "Bad Religion"
266
- end
267
-
268
- # allow writeable: false even in the deserializer.
269
- class SongForm < TestForm
270
- property :title, deserializer: {writeable: false}
271
- end
272
-
273
- it do
274
- form = SongForm.new(song = Song.new)
275
- form.validate("title" => "Ignore me!")
276
- assert_nil form.title
277
- form.title = "Unopened"
278
- form.sync # only the deserializer is marked as not-writeable.
279
- _(song.title).must_equal "Unopened"
280
- end
281
- end
282
-
283
- # # not sure if we should catch that in Reform or rather do that in disposable. this is https://github.com/trailblazer/reform/pull/104
284
- # # describe ":populator with :empty" do
285
- # # let(:form) {
286
- # # Class.new(Reform::Form) do
287
- # # collection :songs, :empty => true, :populator => lambda { |fragment, index, args|
288
- # # songs[index] = args.binding[:form].new(Song.new)
289
- # # } do
290
- # # property :title
291
- # # end
292
- # # end
293
- # # }
294
-
295
- # # let(:params) {
296
- # # {
297
- # # "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"}]
298
- # # }
299
- # # }
300
-
301
- # # subject { form.new(Album.new("Hits", [], [])) }
302
-
303
- # # before { subject.validate(params) }
304
-
305
- # # it { subject.songs[0].title.must_equal "Fallout" }
306
- # # it { subject.songs[1].title.must_equal "Roxanne" }
307
- # # end
308
-
309
- # # test cardinalities.
310
- # describe "with empty collection and cardinality" do
311
- # let(:album) { Album.new }
312
-
313
- # subject { Class.new(Reform::Form) do
314
- # include Reform::Form::ActiveModel
315
- # model :album
316
-
317
- # collection :songs do
318
- # property :title
319
- # end
320
-
321
- # property :hit do
322
- # property :title
323
- # end
324
-
325
- # validates :songs, :length => {:minimum => 1}
326
- # validates :hit, :presence => true
327
- # end.new(album) }
328
-
329
- # describe "invalid" do
330
- # before { subject.validate({}).must_equal false }
331
-
332
- # it do
333
- # # ensure that only hit and songs keys are present
334
- # subject.errors.messages.keys.sort.must_equal([:hit, :songs])
335
- # # validate content of hit and songs keys
336
- # subject.errors.messages[:hit].must_equal(["must be filled"])
337
- # subject.errors.messages[:songs].first.must_match(/\Ais too short \(minimum is 1 characters?\)\z/)
338
- # end
339
- # end
340
-
341
- # describe "valid" do
342
- # let(:album) { Album.new(nil, Song.new, [Song.new("Urban Myth")]) }
343
-
344
- # before {
345
- # subject.validate({"songs" => [{"title"=>"Daddy, Brother, Lover, Little Boy"}], "hit" => {"title"=>"The Horse"}}).
346
- # must_equal true
347
- # }
348
-
349
- # it { subject.errors.messages.must_equal({}) }
350
- # end
351
- # end
352
-
353
- # # providing manual validator method allows accessing form's API.
354
- # describe "with ::validate" do
355
- # let(:form) {
356
- # Class.new(Reform::Form) do
357
- # property :title
358
-
359
- # validate :title?
360
-
361
- # def title?
362
- # errors.add :title, "not lowercase" if title == "Fallout"
363
- # end
364
- # end
365
- # }
366
-
367
- # let(:params) { {"title" => "Fallout"} }
368
- # let(:song) { Song.new("Englishman") }
369
-
370
- # subject { form.new(song) }
371
-
372
- # before { @res = subject.validate(params) }
373
-
374
- # it { @res.must_equal false }
375
- # it { subject.errors.messages.must_equal({:title=>["not lowercase"]}) }
376
- # end
377
-
378
- # # overriding the reader for a nested form should only be considered when rendering.
379
- # describe "with overridden reader for nested form" do
380
- # let(:form) {
381
- # Class.new(Reform::Form) do
382
- # property :band, :populate_if_empty => lambda { |*| Band.new } do
383
- # property :label
384
- # end
385
-
386
- # collection :songs, :populate_if_empty => lambda { |*| Song.new } do
387
- # property :title
388
- # end
389
-
390
- # def band
391
- # raise "only call me when rendering the form!"
392
- # end
393
-
394
- # def songs
395
- # raise "only call me when rendering the form!"
396
- # end
397
- # end.new(album)
398
- # }
399
-
400
- # let(:album) { Album.new }
401
-
402
- # # don't use #artist when validating!
403
- # it do
404
- # form.validate("band" => {"label" => "Hellcat"}, "songs" => [{"title" => "Stand Your Ground"}, {"title" => "Otherside"}])
405
- # form.sync
406
- # album.band.label.must_equal "Hellcat"
407
- # album.songs.first.title.must_equal "Stand Your Ground"
408
- # end
409
- # end
410
- # end