reform 1.2.6 → 2.0.0.beta1

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