reform 1.2.6 → 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +6 -1
  3. data/CHANGES.md +14 -0
  4. data/Gemfile +3 -2
  5. data/README.md +225 -283
  6. data/Rakefile +27 -0
  7. data/TODO.md +12 -0
  8. data/database.sqlite3 +0 -0
  9. data/gemfiles/Gemfile.rails-3.0 +1 -0
  10. data/gemfiles/Gemfile.rails-3.1 +1 -0
  11. data/gemfiles/Gemfile.rails-3.2 +1 -0
  12. data/gemfiles/Gemfile.rails-4.0 +1 -0
  13. data/lib/reform.rb +0 -1
  14. data/lib/reform/contract.rb +64 -170
  15. data/lib/reform/contract/validate.rb +10 -13
  16. data/lib/reform/form.rb +74 -19
  17. data/lib/reform/form/active_model.rb +19 -14
  18. data/lib/reform/form/coercion.rb +1 -13
  19. data/lib/reform/form/composition.rb +2 -24
  20. data/lib/reform/form/multi_parameter_attributes.rb +43 -62
  21. data/lib/reform/form/populator.rb +85 -0
  22. data/lib/reform/form/prepopulate.rb +13 -43
  23. data/lib/reform/form/validate.rb +29 -90
  24. data/lib/reform/form/validation/unique_validator.rb +13 -0
  25. data/lib/reform/version.rb +1 -1
  26. data/reform.gemspec +7 -7
  27. data/test/active_model_test.rb +43 -0
  28. data/test/changed_test.rb +23 -51
  29. data/test/coercion_test.rb +1 -7
  30. data/test/composition_test.rb +128 -34
  31. data/test/contract_test.rb +27 -86
  32. data/test/feature_test.rb +43 -6
  33. data/test/fields_test.rb +2 -12
  34. data/test/form_builder_test.rb +28 -25
  35. data/test/form_option_test.rb +19 -0
  36. data/test/from_test.rb +0 -75
  37. data/test/inherit_test.rb +178 -117
  38. data/test/model_reflections_test.rb +1 -1
  39. data/test/populate_test.rb +226 -0
  40. data/test/prepopulator_test.rb +112 -0
  41. data/test/readable_test.rb +2 -4
  42. data/test/save_test.rb +56 -112
  43. data/test/setup_test.rb +48 -0
  44. data/test/skip_if_test.rb +5 -2
  45. data/test/skip_setter_and_getter_test.rb +54 -0
  46. data/test/test_helper.rb +3 -1
  47. data/test/uniqueness_test.rb +41 -0
  48. data/test/validate_test.rb +325 -289
  49. data/test/virtual_test.rb +1 -3
  50. data/test/writeable_test.rb +3 -4
  51. metadata +35 -39
  52. data/lib/reform/composition.rb +0 -63
  53. data/lib/reform/contract/setup.rb +0 -50
  54. data/lib/reform/form/changed.rb +0 -9
  55. data/lib/reform/form/sync.rb +0 -116
  56. data/lib/reform/representer.rb +0 -84
  57. data/test/empty_test.rb +0 -58
  58. data/test/form_composition_test.rb +0 -145
  59. data/test/nested_form_test.rb +0 -197
  60. data/test/prepopulate_test.rb +0 -85
  61. data/test/sync_option_test.rb +0 -83
  62. data/test/sync_test.rb +0 -56
@@ -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
data/test/skip_if_test.rb CHANGED
@@ -10,10 +10,13 @@ class SkipIfTest < BaseTest
10
10
  validates :title, presence: true
11
11
  end
12
12
 
13
- collection :songs, skip_if: lambda { |fragment, *| fragment["title"].nil? },
14
- populate_if_empty: BaseTest::Song do
13
+ collection :songs, skip_if: :skip_song?, populate_if_empty: BaseTest::Song do
15
14
  property :title
16
15
  end
16
+
17
+ def skip_song?(fragment, options)
18
+ fragment["title"].nil?
19
+ end
17
20
  end
18
21
 
19
22
 
@@ -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
data/test/test_helper.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'reform'
2
2
  require 'minitest/autorun'
3
+ require "representable/debug"
4
+ require "pp"
3
5
 
4
6
  class ReformSpec < MiniTest::Spec
5
7
  let (:duran) { Struct.new(:name).new("Duran Duran") }
@@ -59,4 +61,4 @@ MiniTest::Spec.class_eval do
59
61
  @saved
60
62
  end
61
63
  end
62
- end
64
+ end
@@ -0,0 +1,41 @@
1
+ require "test_helper"
2
+
3
+ require "reform/form/validation/unique_validator.rb"
4
+
5
+ class UniquenessValidatorOnCreateTest < MiniTest::Spec
6
+ class SongForm < Reform::Form
7
+ property :title
8
+ validates :title, unique: true
9
+ end
10
+
11
+ it do
12
+ Song.delete_all
13
+
14
+ form = SongForm.new(Song.new)
15
+ form.validate("title" => "How Many Tears").must_equal true
16
+ form.save
17
+
18
+ form = SongForm.new(Song.new)
19
+ form.validate("title" => "How Many Tears").must_equal false
20
+ form.errors.to_s.must_equal "{:title=>[\"title must be unique.\"]}"
21
+ end
22
+ end
23
+
24
+ class UniquenessValidatorOnUpdateTest < MiniTest::Spec
25
+ class SongForm < Reform::Form
26
+ property :title
27
+ validates :title, unique: true
28
+ end
29
+
30
+ it do
31
+ Song.delete_all
32
+ @song = Song.create(title: "How Many Tears")
33
+
34
+ form = SongForm.new(@song)
35
+ form.validate("title" => "How Many Tears").must_equal true
36
+ form.save
37
+
38
+ form = SongForm.new(@song)
39
+ form.validate("title" => "How Many Tears").must_equal true
40
+ end
41
+ end
@@ -1,362 +1,398 @@
1
1
  require 'test_helper'
2
2
 
3
- class ValidateTest < BaseTest
4
- describe "populated" do
5
- let (:params) {
6
- {
7
- "title" => "Best Of",
8
- "hit" => {"title" => "Roxanne"},
9
- "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"}]
10
- }
11
- }
12
- let (:hit) { Song.new }
13
- let (:song2) { Song.new }
14
- let (:song1) { Song.new }
15
-
16
- subject { AlbumForm.new(Album.new(nil, hit, [song1, song2])) }
17
-
18
- before { subject.validate(params) }
19
-
20
- it { subject.title.must_equal "Best Of" }
21
-
22
- it { subject.hit.must_be_kind_of Reform::Form }
23
- it { subject.hit.title.must_equal "Roxanne" }
24
-
25
- it { subject.songs.must_be_kind_of Array }
26
- it { subject.songs.size.must_equal 2 }
27
-
28
- it { subject.songs[0].must_be_kind_of Reform::Form }
29
- it { subject.songs[0].title.must_equal "Fallout" }
30
-
31
- it { subject.songs[1].must_be_kind_of Reform::Form }
32
- it { subject.songs[1].title.must_equal "Roxanne" }
33
-
34
- # don't touch model.
35
- it { hit.title.must_equal nil }
36
- it { song1.title.must_equal nil }
37
- it { song2.title.must_equal nil }
38
- end
39
-
40
- describe "not populated properly raises error" do
41
- it do
42
- assert_raises Reform::Form::Validate::DeserializeError do
43
- AlbumForm.new(Album.new).validate("hit" => {"title" => "Roxanne"})
3
+ # tests: -------
4
+ # Contract
5
+ # validate
6
+ # errors
7
+
8
+ # Form
9
+ # validate
10
+ # errors
11
+
12
+ class ContractValidateTest < MiniTest::Spec
13
+ Song = Struct.new(:title, :album, :composer)
14
+ Album = Struct.new(:name, :songs, :artist)
15
+ Artist = Struct.new(:name)
16
+
17
+ class AlbumForm < Reform::Contract
18
+ property :name
19
+ validates :name, presence: true
20
+
21
+ collection :songs do
22
+ property :title
23
+ validates :title, presence: true
24
+
25
+ property :composer do
26
+ validates :name, presence: true
27
+ property :name
44
28
  end
45
29
  end
46
- end
47
-
48
- # TODO: the following tests go to populate_test.rb
49
- describe "manual setup with populator" do
50
- let (:form) {
51
- Class.new(Reform::Form) do
52
- property :hit, :populator => lambda { |fragment, args|
53
- puts "******************* #{fragment}"
54
-
55
- hit or self.hit = args.binding[:form].new(Song.new)
56
- } do
57
- property :title
58
- end
59
- end
60
- }
61
-
62
- let (:params) {
63
- {
64
- "hit" => {"title" => "Roxanne"},
65
- # "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"}]
66
- }
67
- }
68
30
 
69
- subject { form.new(Album.new) }
70
-
71
- before { subject.validate(params) }
72
-
73
- it { subject.hit.title.must_equal "Roxanne" }
31
+ property :artist do
32
+ property :name
33
+ end
74
34
  end
75
35
 
36
+ let (:song) { Song.new("Broken") }
37
+ let (:song_with_composer) { Song.new("Resist Stance", nil, composer) }
38
+ let (:composer) { Artist.new("Greg Graffin") }
39
+ let (:artist) { Artist.new("Bad Religion") }
40
+ let (:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
76
41
 
77
- describe ":populator, half-populated collection" do
78
- let (:form) {
79
- Class.new(Reform::Form) do
80
- collection :songs, :populator => lambda { |fragment, index, args|
81
- songs[index] or songs[index] = args.binding[:form].new(Song.new)
82
- } do
83
- property :title
84
- end
85
- end
86
- }
87
-
88
- let (:params) {
89
- {
90
- "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"}]
91
- }
92
- }
93
- let (:song) { Song.new("Englishman") }
94
-
95
- subject { form.new(Album.new("Hits", nil, [song])) }
96
-
97
- before { subject.validate(params) }
42
+ let (:form) { AlbumForm.new(album) }
98
43
 
99
- it { subject.songs[0].model.object_id.must_equal song.object_id } # this song was existing before.
100
- it { subject.songs[0].title.must_equal "Fallout" }
101
- it { subject.songs[1].title.must_equal "Roxanne" }
44
+ # valid
45
+ it do
46
+ form.validate.must_equal true
47
+ form.errors.messages.inspect.must_equal "{}"
102
48
  end
103
49
 
50
+ # invalid
51
+ it do
52
+ album.songs[1].composer.name = nil
53
+ album.name = nil
104
54
 
105
- # not sure if we should catch that in Reform or rather do that in disposable. this is https://github.com/apotonick/reform/pull/104
106
- # describe ":populator with :empty" do
107
- # let (:form) {
108
- # Class.new(Reform::Form) do
109
- # collection :songs, :empty => true, :populator => lambda { |fragment, index, args|
110
- # songs[index] = args.binding[:form].new(Song.new)
111
- # } do
112
- # property :title
113
- # end
114
- # end
115
- # }
55
+ form.validate.must_equal false
56
+ form.errors.messages.inspect.must_equal "{:\"songs.composer.name\"=>[\"can't be blank\"], :name=>[\"can't be blank\"]}"
57
+ end
58
+ end
116
59
 
117
- # let (:params) {
118
- # {
119
- # "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"}]
120
- # }
121
- # }
122
60
 
123
- # subject { form.new(Album.new("Hits", [], [])) }
61
+ # no configuration results in "sync" (formerly known as parse_strategy: :sync).
62
+ class ValidateWithoutConfigurationTest < MiniTest::Spec
63
+ Song = Struct.new(:title, :album, :composer)
64
+ Album = Struct.new(:name, :songs, :artist)
65
+ Artist = Struct.new(:name)
124
66
 
125
- # before { subject.validate(params) }
67
+ class AlbumForm < Reform::Form
68
+ property :name
69
+ validates :name, presence: true
126
70
 
127
- # it { subject.songs[0].title.must_equal "Fallout" }
128
- # it { subject.songs[1].title.must_equal "Roxanne" }
129
- # end
71
+ collection :songs do
130
72
 
73
+ property :title
74
+ validates :title, presence: true
131
75
 
132
- describe ":populate_if_empty, half-populated collection" do
133
- let (:form) {
134
- Class.new(Reform::Form) do
135
- collection :songs, :populate_if_empty => Song do
136
- property :title
137
- end
76
+ property :composer do
77
+ property :name
78
+ validates :name, presence: true
138
79
  end
139
- }
140
-
141
- let (:params) {
142
- {
143
- "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"}]
144
- }
145
- }
146
- let (:song) { Song.new("Englishman") }
147
-
148
- subject { form.new(Album.new("Hits", nil, [song])) }
80
+ end
149
81
 
150
- before { subject.validate(params) }
82
+ property :artist do
83
+ property :name
84
+ end
85
+ end
151
86
 
152
- it { subject.songs[0].model.object_id.must_equal song.object_id } # this song was existing before.
153
- it { subject.songs[0].title.must_equal "Fallout" }
154
- it { subject.songs[1].title.must_equal "Roxanne" }
87
+ let (:song) { Song.new("Broken") }
88
+ let (:song_with_composer) { Song.new("Resist Stance", nil, composer) }
89
+ let (:composer) { Artist.new("Greg Graffin") }
90
+ let (:artist) { Artist.new("Bad Religion") }
91
+ let (:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
92
+
93
+ let (:form) { AlbumForm.new(album) }
94
+
95
+ # valid.
96
+ it do
97
+ object_ids = {song: form.songs[0].object_id, song_with_composer: form.songs[1].object_id,
98
+ artist: form.artist.object_id, composer: form.songs[1].composer.object_id}
99
+
100
+ form.validate(
101
+ "name" => "Best Of",
102
+ "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne", "composer" => {"name" => "Sting"}}],
103
+ "artist" => {"name" => "The Police"},
104
+ ).must_equal true
105
+
106
+ form.errors.messages.inspect.must_equal "{}"
107
+
108
+ # form has updated.
109
+ form.name.must_equal "Best Of"
110
+ form.songs[0].title.must_equal "Fallout"
111
+ form.songs[1].title.must_equal "Roxanne"
112
+ form.songs[1].composer.name.must_equal "Sting"
113
+ form.artist.name.must_equal "The Police"
114
+
115
+ # objects are still the same.
116
+ form.songs[0].object_id.must_equal object_ids[:song]
117
+ form.songs[1].object_id.must_equal object_ids[:song_with_composer]
118
+ form.songs[1].composer.object_id.must_equal object_ids[:composer]
119
+ form.artist.object_id.must_equal object_ids[:artist]
120
+
121
+
122
+ # model has not changed, yet.
123
+ album.name.must_equal "The Dissent Of Man"
124
+ album.songs[0].title.must_equal "Broken"
125
+ album.songs[1].title.must_equal "Resist Stance"
126
+ album.songs[1].composer.name.must_equal "Greg Graffin"
127
+ album.artist.name.must_equal "Bad Religion"
155
128
  end
129
+ end
156
130
 
131
+ class ValidateWithDeserializerOptionTest < MiniTest::Spec
132
+ Song = Struct.new(:title, :album, :composer)
133
+ Album = Struct.new(:name, :songs, :artist)
134
+ Artist = Struct.new(:name)
157
135
 
158
- describe ":populate_if_empty" do
159
- let (:form) {
160
- Class.new(Reform::Form) do
161
- property :hit, :populate_if_empty => lambda { |fragment, args| Song.new } do
162
- property :title
163
- end
136
+ class AlbumForm < Reform::Form
137
+ property :name
138
+ validates :name, presence: true
164
139
 
165
- collection :songs, :populate_if_empty => lambda { |fragment, args| model.songs.build } do
166
- property :title
167
- end
140
+ collection :songs,
141
+ deserializer: {instance: lambda { |fragment, index, options|
142
+ collection = options.binding.get
143
+ (item = collection[index]) ? item : collection.insert(index, Song.new) },
144
+ setter: nil} do
168
145
 
169
- property :band, :populate_if_empty => lambda { |fragment, args| Band.new } do
170
- property :label, :populate_if_empty => lambda { |fragment, args| Label.new } do
171
- property :name
172
- end
173
- end
146
+ property :title
147
+ validates :title, presence: true
148
+
149
+ property :composer, deserializer: { instance: lambda { |fragment, options| (item = options.binding.get) ? item : Artist.new } } do
150
+ property :name
151
+ validates :name, presence: true
174
152
  end
175
- }
153
+ end
176
154
 
177
- let (:params) {
178
- {
179
- "hit" => {"title" => "Roxanne"},
180
- "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"}],
181
- "band" => {"label" => {"name" => "Epitaph"}}
182
- }
183
- }
155
+ property :artist, deserializer: { instance: lambda { |fragment, options| (item = options.binding.get) ? item : Artist.new } } do
156
+ property :name
157
+ validates :name, presence: true
158
+ end
159
+ end
184
160
 
185
- let (:song_collection_proxy) { Class.new(Array) { def build; Song.new; end } }
186
- let (:album) { Album.new(nil,nil, song_collection_proxy.new, nil) }
187
- subject { form.new(album) } # DISCUSS: require at least an array here? this is provided by all ORMs.
161
+ let (:song) { Song.new("Broken") }
162
+ let (:song_with_composer) { Song.new("Resist Stance", nil, composer) }
163
+ let (:composer) { Artist.new("Greg Graffin") }
164
+ let (:artist) { Artist.new("Bad Religion") }
165
+ let (:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
166
+
167
+ let (:form) { AlbumForm.new(album) }
168
+
169
+ # valid.
170
+ it("xxx") do
171
+ form.validate(
172
+ "name" => "Best Of",
173
+ "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne", "composer" => {"name" => "Sting"}}],
174
+ "artist" => {"name" => "The Police"},
175
+ ).must_equal true
176
+
177
+ form.errors.messages.inspect.must_equal "{}"
178
+
179
+ # form has updated.
180
+ form.name.must_equal "Best Of"
181
+ form.songs[0].title.must_equal "Fallout"
182
+ form.songs[1].title.must_equal "Roxanne"
183
+ form.songs[1].composer.name.must_equal "Sting"
184
+ form.artist.name.must_equal "The Police"
185
+
186
+
187
+ # model has not changed, yet.
188
+ album.name.must_equal "The Dissent Of Man"
189
+ album.songs[0].title.must_equal "Broken"
190
+ album.songs[1].title.must_equal "Resist Stance"
191
+ album.songs[1].composer.name.must_equal "Greg Graffin"
192
+ album.artist.name.must_equal "Bad Religion"
193
+ end
188
194
 
189
- before { subject.validate(params) }
195
+ # invalid.
196
+ it do
197
+ form.validate(
198
+ "name" => "",
199
+ "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne", "composer" => {"name" => ""}}],
200
+ "artist" => {"name" => ""},
201
+ ).must_equal false
190
202
 
191
- it { subject.hit.title.must_equal "Roxanne" }
192
- it { subject.songs[0].title.must_equal "Fallout" }
193
- it { subject.songs[1].title.must_equal "Roxanne" }
203
+ form.errors.messages.inspect.must_equal "{:\"songs.composer.name\"=>[\"can't be blank\"], :\"artist.name\"=>[\"can't be blank\"], :name=>[\"can't be blank\"]}"
204
+ end
194
205
 
195
- # population doesn't write to the model.
196
- it { album.hit.must_equal nil }
197
- it { album.songs.size.must_equal 0 }
206
+ # adding to collection via :instance.
207
+ # valid.
208
+ it do
209
+ form.validate(
210
+ "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"}, {"title" => "Rime Of The Ancient Mariner"}],
211
+ ).must_equal true
212
+
213
+ form.errors.messages.inspect.must_equal "{}"
214
+
215
+ # form has updated.
216
+ form.name.must_equal "The Dissent Of Man"
217
+ form.songs[0].title.must_equal "Fallout"
218
+ form.songs[1].title.must_equal "Roxanne"
219
+ form.songs[1].composer.name.must_equal "Greg Graffin"
220
+ form.songs[1].title.must_equal "Roxanne"
221
+ form.songs[2].title.must_equal "Rime Of The Ancient Mariner" # new song added.
222
+ form.songs.size.must_equal 3
223
+ form.artist.name.must_equal "Bad Religion"
224
+
225
+
226
+ # model has not changed, yet.
227
+ album.name.must_equal "The Dissent Of Man"
228
+ album.songs[0].title.must_equal "Broken"
229
+ album.songs[1].title.must_equal "Resist Stance"
230
+ album.songs[1].composer.name.must_equal "Greg Graffin"
231
+ album.songs.size.must_equal 2
232
+ album.artist.name.must_equal "Bad Religion"
233
+ end
198
234
 
199
- it { subject.band.label.name.must_equal "Epitaph" }
200
235
 
236
+ # allow writeable: false even in the deserializer.
237
+ class SongForm < Reform::Form
238
+ property :title, deserializer: {writeable: false}
239
+ end
201
240
 
202
- describe "missing parameters" do
203
- let (:params) {
204
- { }
205
- }
241
+ it do
242
+ form = SongForm.new(song = Song.new)
243
+ form.validate("title" => "Ignore me!")
244
+ form.title.must_equal nil
245
+ form.title = "Unopened"
246
+ form.sync # only the deserializer is marked as not-writeable.
247
+ song.title.must_equal "Unopened"
248
+ end
249
+ end
206
250
 
207
- before { subject.validate(params) }
208
251
 
209
- it { subject.hit.must_equal nil }
210
- end
211
- end
252
+ # # not sure if we should catch that in Reform or rather do that in disposable. this is https://github.com/apotonick/reform/pull/104
253
+ # # describe ":populator with :empty" do
254
+ # # let (:form) {
255
+ # # Class.new(Reform::Form) do
256
+ # # collection :songs, :empty => true, :populator => lambda { |fragment, index, args|
257
+ # # songs[index] = args.binding[:form].new(Song.new)
258
+ # # } do
259
+ # # property :title
260
+ # # end
261
+ # # end
262
+ # # }
212
263
 
264
+ # # let (:params) {
265
+ # # {
266
+ # # "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"}]
267
+ # # }
268
+ # # }
213
269
 
214
- describe "populate_if_empty: Class" do
215
- let (:form) {
216
- Class.new(Reform::Form) do
217
- property :hit, :populate_if_empty => Song do
218
- property :title
219
- end
220
- end
221
- }
270
+ # # subject { form.new(Album.new("Hits", [], [])) }
222
271
 
223
- let (:params) {
224
- {
225
- "hit" => {"title" => "Roxanne"},
226
- }
227
- }
272
+ # # before { subject.validate(params) }
228
273
 
229
- let (:album) { Album.new }
230
- subject { form.new(album) }
274
+ # # it { subject.songs[0].title.must_equal "Fallout" }
275
+ # # it { subject.songs[1].title.must_equal "Roxanne" }
276
+ # # end
231
277
 
232
- before { subject.validate(params) }
233
278
 
234
- it { subject.hit.title.must_equal "Roxanne" }
235
- end
279
+ # # test cardinalities.
280
+ # describe "with empty collection and cardinality" do
281
+ # let (:album) { Album.new }
236
282
 
283
+ # subject { Class.new(Reform::Form) do
284
+ # include Reform::Form::ActiveModel
285
+ # model :album
237
286
 
287
+ # collection :songs do
288
+ # property :title
289
+ # end
238
290
 
239
- # test cardinalities.
240
- describe "with empty collection and cardinality" do
241
- let (:album) { Album.new }
291
+ # property :hit do
292
+ # property :title
293
+ # end
242
294
 
243
- subject { Class.new(Reform::Form) do
244
- include Reform::Form::ActiveModel
245
- model :album
295
+ # validates :songs, :length => {:minimum => 1}
296
+ # validates :hit, :presence => true
297
+ # end.new(album) }
246
298
 
247
- collection :songs do
248
- property :title
249
- end
250
299
 
251
- property :hit do
252
- property :title
253
- end
300
+ # describe "invalid" do
301
+ # before { subject.validate({}).must_equal false }
254
302
 
255
- validates :songs, :length => {:minimum => 1}
256
- validates :hit, :presence => true
257
- end.new(album) }
303
+ # it do
304
+ # # ensure that only hit and songs keys are present
305
+ # subject.errors.messages.keys.sort.must_equal([:hit, :songs])
306
+ # # validate content of hit and songs keys
307
+ # subject.errors.messages[:hit].must_equal(["can't be blank"])
308
+ # subject.errors.messages[:songs].first.must_match(/\Ais too short \(minimum is 1 characters?\)\z/)
309
+ # end
310
+ # end
258
311
 
259
312
 
260
- describe "invalid" do
261
- before { subject.validate({}).must_equal false }
313
+ # describe "valid" do
314
+ # let (:album) { Album.new(nil, Song.new, [Song.new("Urban Myth")]) }
262
315
 
263
- it { subject.errors.messages.must_equal(
264
- :songs => ["is too short (minimum is 1 characters)"],
265
- :hit => ["can't be blank"]) }
266
- end
316
+ # before {
317
+ # subject.validate({"songs" => [{"title"=>"Daddy, Brother, Lover, Little Boy"}], "hit" => {"title"=>"The Horse"}}).
318
+ # must_equal true
319
+ # }
267
320
 
321
+ # it { subject.errors.messages.must_equal({}) }
322
+ # end
323
+ # end
268
324
 
269
- describe "valid" do
270
- let (:album) { Album.new(nil, Song.new, [Song.new("Urban Myth")]) }
271
325
 
272
- before {
273
- subject.validate({"songs" => [{"title"=>"Daddy, Brother, Lover, Little Boy"}], "hit" => {"title"=>"The Horse"}}).
274
- must_equal true
275
- }
326
+ # describe "with symbols" do
327
+ # let (:album) { OpenStruct.new(:band => OpenStruct.new(:label => OpenStruct.new(:name => "Epitaph"))) }
328
+ # subject { ErrorsTest::AlbumForm.new(album) }
329
+ # let (:params) { {:band => {:label => {:name => "Stiff"}}, :title => "House Of Fun"} }
276
330
 
277
- it { subject.errors.messages.must_equal({}) }
278
- end
279
- end
331
+ # before {
332
+ # subject.validate(params).must_equal true
333
+ # }
280
334
 
335
+ # it { subject.band.label.name.must_equal "Stiff" }
336
+ # it { subject.title.must_equal "House Of Fun" }
337
+ # end
281
338
 
282
- describe "with symbols" do
283
- let (:album) { OpenStruct.new(:band => OpenStruct.new(:label => OpenStruct.new(:name => "Epitaph"))) }
284
- subject { ErrorsTest::AlbumForm.new(album) }
285
- let (:params) { {:band => {:label => {:name => "Stiff"}}, :title => "House Of Fun"} }
286
339
 
287
- before {
288
- subject.validate(params).must_equal true
289
- }
340
+ # # providing manual validator method allows accessing form's API.
341
+ # describe "with ::validate" do
342
+ # let (:form) {
343
+ # Class.new(Reform::Form) do
344
+ # property :title
290
345
 
291
- it { subject.band.label.name.must_equal "Stiff" }
292
- it { subject.title.must_equal "House Of Fun" }
293
- end
346
+ # validate :title?
294
347
 
348
+ # def title?
349
+ # errors.add :title, "not lowercase" if title == "Fallout"
350
+ # end
351
+ # end
352
+ # }
295
353
 
296
- # providing manual validator method allows accessing form's API.
297
- describe "with ::validate" do
298
- let (:form) {
299
- Class.new(Reform::Form) do
300
- property :title
354
+ # let (:params) { {"title" => "Fallout"} }
355
+ # let (:song) { Song.new("Englishman") }
301
356
 
302
- validate :title?
357
+ # subject { form.new(song) }
303
358
 
304
- def title?
305
- errors.add :title, "not lowercase" if title == "Fallout"
306
- end
307
- end
308
- }
359
+ # before { @res = subject.validate(params) }
309
360
 
310
- let (:params) { {"title" => "Fallout"} }
311
- let (:song) { Song.new("Englishman") }
361
+ # it { @res.must_equal false }
362
+ # it { subject.errors.messages.must_equal({:title=>["not lowercase"]}) }
363
+ # end
312
364
 
313
- subject { form.new(song) }
314
365
 
315
- before { @res = subject.validate(params) }
366
+ # # overriding the reader for a nested form should only be considered when rendering.
367
+ # describe "with overridden reader for nested form" do
368
+ # let (:form) {
369
+ # Class.new(Reform::Form) do
370
+ # property :band, :populate_if_empty => lambda { |*| Band.new } do
371
+ # property :label
372
+ # end
316
373
 
317
- it { @res.must_equal false }
318
- it { subject.errors.messages.must_equal({:title=>["not lowercase"]}) }
319
- end
374
+ # collection :songs, :populate_if_empty => lambda { |*| Song.new } do
375
+ # property :title
376
+ # end
320
377
 
378
+ # def band
379
+ # raise "only call me when rendering the form!"
380
+ # end
321
381
 
322
- # overriding the reader for a nested form should only be considered when rendering.
323
- describe "with overridden reader for nested form" do
324
- let (:form) {
325
- Class.new(Reform::Form) do
326
- property :band, :populate_if_empty => lambda { |*| Band.new } do
327
- property :label
328
- end
329
-
330
- collection :songs, :populate_if_empty => lambda { |*| Song.new } do
331
- property :title
332
- end
333
-
334
- def band
335
- raise "only call me when rendering the form!"
336
- end
337
-
338
- def songs
339
- raise "only call me when rendering the form!"
340
- end
341
- end.new(album)
342
- }
343
-
344
- let (:album) { Album.new }
345
-
346
- # don't use #artist when validating!
347
- it do
348
- form.validate("band" => {"label" => "Hellcat"}, "songs" => [{"title" => "Stand Your Ground"}, {"title" => "Otherside"}])
349
- form.sync
350
- album.band.label.must_equal "Hellcat"
351
- album.songs.first.title.must_equal "Stand Your Ground"
352
- end
353
- end
354
- end
382
+ # def songs
383
+ # raise "only call me when rendering the form!"
384
+ # end
385
+ # end.new(album)
386
+ # }
355
387
 
356
- # #validate(params)
357
- # title=(params[:title])
358
- # song.validate(params[:song], errors)
388
+ # let (:album) { Album.new }
359
389
 
360
- # #sync (assumes that forms already have updated fields)
361
- # model.title=
362
- # song.sync
390
+ # # don't use #artist when validating!
391
+ # it do
392
+ # form.validate("band" => {"label" => "Hellcat"}, "songs" => [{"title" => "Stand Your Ground"}, {"title" => "Otherside"}])
393
+ # form.sync
394
+ # album.band.label.must_equal "Hellcat"
395
+ # album.songs.first.title.must_equal "Stand Your Ground"
396
+ # end
397
+ # end
398
+ # end