reform 2.3.3 → 2.6.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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +17 -0
  3. data/.gitignore +1 -1
  4. data/CHANGES.md +15 -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/form/populator.rb +13 -3
  12. data/lib/reform/form/prepopulate.rb +1 -1
  13. data/lib/reform/form/validate.rb +3 -3
  14. data/lib/reform/validation/groups.rb +0 -1
  15. data/lib/reform/version.rb +1 -1
  16. data/reform.gemspec +2 -2
  17. data/test/call_test.rb +23 -0
  18. data/test/changed_test.rb +6 -6
  19. data/test/coercion_test.rb +17 -17
  20. data/test/{composition_new_api.rb → composition_test.rb} +27 -28
  21. data/test/{contract_new_api.rb → contract_test.rb} +8 -8
  22. data/test/default_test.rb +2 -2
  23. data/test/deserialize_test.rb +8 -8
  24. data/test/docs/validation_test.rb +134 -0
  25. data/test/{errors_new_api.rb → errors_test.rb} +41 -41
  26. data/test/feature_test.rb +2 -2
  27. data/test/fixtures/dry_error_messages.yml +64 -54
  28. data/test/{form_option_new_api.rb → form_option_test.rb} +1 -1
  29. data/test/{form_new_api.rb → form_test.rb} +3 -3
  30. data/test/from_test.rb +10 -10
  31. data/test/{inherit_new_api.rb → inherit_test.rb} +17 -17
  32. data/test/{module_new_api.rb → module_test.rb} +10 -10
  33. data/test/parse_option_test.rb +7 -7
  34. data/test/parse_pipeline_test.rb +1 -1
  35. data/test/{populate_new_api.rb → populate_test.rb} +136 -53
  36. data/test/populator_skip_test.rb +2 -2
  37. data/test/prepopulator_test.rb +16 -16
  38. data/test/read_only_test.rb +2 -2
  39. data/test/readable_test.rb +3 -3
  40. data/test/{reform_new_api.rb → reform_test.rb} +19 -19
  41. data/test/{save_new_api.rb → save_test.rb} +4 -4
  42. data/test/setup_test.rb +9 -9
  43. data/test/{skip_if_new_api.rb → skip_if_test.rb} +12 -12
  44. data/test/skip_setter_and_getter_test.rb +6 -6
  45. data/test/test_helper.rb +5 -6
  46. data/test/{validate_new_api.rb → validate_test.rb} +65 -78
  47. data/test/validation/{dry_validation_new_api.rb → dry_validation_test.rb} +124 -123
  48. data/test/validation/result_test.rb +14 -14
  49. data/test/virtual_test.rb +7 -7
  50. data/test/writeable_test.rb +8 -8
  51. metadata +43 -82
  52. data/.travis.yml +0 -16
  53. data/Appraisals +0 -8
  54. data/gemfiles/0.13.0.gemfile +0 -8
  55. data/gemfiles/1.5.0.gemfile +0 -9
  56. data/lib/reform/form/dry/new_api.rb +0 -45
  57. data/lib/reform/form/dry/old_api.rb +0 -61
  58. data/test/call_new_api.rb +0 -23
  59. data/test/call_old_api.rb +0 -23
  60. data/test/composition_old_api.rb +0 -184
  61. data/test/contract_old_api.rb +0 -77
  62. data/test/errors_old_api.rb +0 -230
  63. data/test/fixtures/dry_new_api_error_messages.yml +0 -104
  64. data/test/form_old_api.rb +0 -57
  65. data/test/form_option_old_api.rb +0 -24
  66. data/test/inherit_old_api.rb +0 -105
  67. data/test/module_old_api.rb +0 -146
  68. data/test/populate_old_api.rb +0 -304
  69. data/test/reform_old_api.rb +0 -202
  70. data/test/save_old_api.rb +0 -101
  71. data/test/skip_if_old_api.rb +0 -92
  72. data/test/validate_old_api.rb +0 -410
  73. data/test/validation/dry_validation_old_api.rb +0 -772
@@ -17,7 +17,7 @@ class FormOptionTest < MiniTest::Spec
17
17
 
18
18
  it do
19
19
  form = AlbumForm.new(Album.new(Song.new("When It Comes To You")))
20
- _(form.song.title).must_equal "When It Comes To You"
20
+ assert_equal "When It Comes To You", form.song.title
21
21
 
22
22
  form.validate(song: {title: "Run For Cover"})
23
23
  end
@@ -25,8 +25,8 @@ class FormTest < MiniTest::Spec
25
25
  let(:cloned) { AlbumForm.clone }
26
26
 
27
27
  # #dup is called in Op.inheritable_attr(:contract_class), it must be subclass of the original one.
28
- it { _(cloned).wont_equal AlbumForm }
29
- it { _(AlbumForm.definitions).wont_equal cloned.definitions }
28
+ it { refute_equal cloned, AlbumForm }
29
+ it { refute_equal AlbumForm.definitions, cloned.definitions }
30
30
 
31
31
  it do
32
32
  # currently, forms need a name for validation, even without AM.
@@ -51,7 +51,7 @@ class FormTest < MiniTest::Spec
51
51
  end
52
52
 
53
53
  it "allows injecting :virtual options" do
54
- _(ArtistForm.new(Artist.new, current_user: Object).current_user).must_equal Object
54
+ assert_equal ArtistForm.new(Artist.new, current_user: Object).current_user, Object
55
55
  end
56
56
  end
57
57
  end
data/test/from_test.rb CHANGED
@@ -31,19 +31,19 @@ class AsTest < BaseTest
31
31
 
32
32
  subject { AlbumForm.new(Album.new("Best Of", hit, [Song.new("Fallout"), song2])) }
33
33
 
34
- it { _(subject.name).must_equal "Best Of" }
35
- it { _(subject.single.title).must_equal "Roxanne" }
36
- it { _(subject.tracks[0].name).must_equal "Fallout" }
37
- it { _(subject.tracks[1].name).must_equal "Roxanne" }
34
+ it { assert_equal subject.name, "Best Of" }
35
+ it { assert_equal subject.single.title, "Roxanne" }
36
+ it { assert_equal subject.tracks[0].name, "Fallout" }
37
+ it { assert_equal subject.tracks[1].name, "Roxanne" }
38
38
 
39
39
  describe "#validate" do
40
40
 
41
41
  before { subject.validate(params) }
42
42
 
43
- it { _(subject.name).must_equal "Best Of The Police" }
44
- it { _(subject.single.title).must_equal "So Lonely" }
45
- it { _(subject.tracks[0].name).must_equal "Message In A Bottle" }
46
- it { _(subject.tracks[1].name).must_equal "Roxanne" }
43
+ it { assert_equal subject.name, "Best Of The Police" }
44
+ it { assert_equal subject.single.title, "So Lonely" }
45
+ it { assert_equal subject.tracks[0].name, "Message In A Bottle" }
46
+ it { assert_equal subject.tracks[1].name, "Roxanne" }
47
47
  end
48
48
 
49
49
  describe "#sync" do
@@ -52,7 +52,7 @@ class AsTest < BaseTest
52
52
  subject.sync
53
53
  end
54
54
 
55
- it { _(song2.title).must_equal "Livin' Ain't No Crime" }
55
+ it { assert_equal song2.title, "Livin' Ain't No Crime" }
56
56
  end
57
57
 
58
58
  describe "#save (nested hash)" do
@@ -65,7 +65,7 @@ class AsTest < BaseTest
65
65
  hash = nested_hash
66
66
  end
67
67
 
68
- _(hash).must_equal({"title" => "Best Of The Police", "hit" => {"title" => "So Lonely"}, "songs" => [{"title" => "Message In A Bottle"}, {"title" => "Roxanne"}], "band" => nil})
68
+ assert_equal hash, "title" => "Best Of The Police", "hit" => {"title" => "So Lonely"}, "songs" => [{"title" => "Message In A Bottle"}, {"title" => "Roxanne"}], "band" => nil
69
69
  end
70
70
  end
71
71
  end
@@ -52,46 +52,46 @@ class InheritTest < BaseTest
52
52
 
53
53
  it do
54
54
  subject.validate("hit" => {"title" => "LA Drone", "rating" => 10})
55
- _(subject.hit.title).must_equal "LA Drone"
56
- _(subject.hit.rating).must_equal 10
57
- _(subject.errors.messages).must_equal({})
55
+ assert_equal subject.hit.title, "LA Drone"
56
+ assert_equal subject.hit.rating, 10
57
+ assert_equal subject.errors.messages, {}
58
58
  end
59
59
 
60
60
  it do
61
61
  subject.validate({})
62
62
  assert_nil subject.model.hit.title
63
63
  assert_nil subject.model.hit.rating
64
- _(subject.errors.messages).must_equal("hit.title": ["must be filled"], "hit.rating": ["must be filled"])
64
+ assert_equal subject.errors.messages, "hit.title": ["must be filled"], "hit.rating": ["must be filled"]
65
65
  end
66
66
 
67
67
  it "xxx" do
68
68
  # sub hashes like :deserializer must be properly cloned when inheriting.
69
- _(AlbumForm.options_for(:title)[:deserializer].object_id).wont_equal CompilationForm.options_for(:title)[:deserializer].object_id
69
+ refute_equal AlbumForm.options_for(:title)[:deserializer].object_id, CompilationForm.options_for(:title)[:deserializer].object_id
70
70
 
71
71
  # don't overwrite direct deserializer: {} configuration.
72
- _(AlbumForm.options_for(:title)[:internal_populator]).must_be_instance_of Reform::Form::Populator::Sync
73
- _(AlbumForm.options_for(:title)[:deserializer][:skip_parse]).must_equal "skip_if in AlbumForm"
72
+ assert AlbumForm.options_for(:title)[:internal_populator].is_a? Reform::Form::Populator::Sync
73
+ assert_equal AlbumForm.options_for(:title)[:deserializer][:skip_parse], "skip_if in AlbumForm"
74
74
 
75
75
  # AlbumForm.options_for(:hit)[:internal_populator].inspect.must_match /Reform::Form::Populator:.+ @user_proc="Populator"/
76
76
  # AlbumForm.options_for(:hit)[:deserializer][:instance].inspect.must_be_instance_with Reform::Form::Populator, user_proc: "Populator"
77
77
 
78
- _(AlbumForm.options_for(:songs)[:internal_populator]).must_be_instance_of Reform::Form::Populator::IfEmpty
79
- _(AlbumForm.options_for(:songs)[:deserializer][:skip_parse]).must_be_instance_of Reform::Form::Validate::Skip::AllBlank
78
+ assert AlbumForm.options_for(:songs)[:internal_populator].is_a? Reform::Form::Populator::IfEmpty
79
+ assert AlbumForm.options_for(:songs)[:deserializer][:skip_parse].is_a? Reform::Form::Validate::Skip::AllBlank
80
80
 
81
- _(AlbumForm.options_for(:band)[:internal_populator]).must_be_instance_of Reform::Form::Populator::IfEmpty
81
+ assert AlbumForm.options_for(:band)[:internal_populator].is_a? Reform::Form::Populator::IfEmpty
82
82
 
83
- _(CompilationForm.options_for(:title)[:deserializer][:skip_parse]).must_equal "skip_if from CompilationForm"
83
+ assert_equal CompilationForm.options_for(:title)[:deserializer][:skip_parse], "skip_if from CompilationForm"
84
84
  # pp CompilationForm.options_for(:songs)
85
- _(CompilationForm.options_for(:songs)[:internal_populator]).must_be_instance_of Reform::Form::Populator::IfEmpty
85
+ assert CompilationForm.options_for(:songs)[:internal_populator].is_a? Reform::Form::Populator::IfEmpty
86
86
 
87
- _(CompilationForm.options_for(:band)[:internal_populator]).must_be_instance_of Reform::Form::Populator::IfEmpty
87
+ assert CompilationForm.options_for(:band)[:internal_populator].is_a? Reform::Form::Populator::IfEmpty
88
88
 
89
89
  # completely overwrite inherited.
90
- _(CompilationForm.options_for(:hit)[:deserializer][:skip_parse]).must_be_instance_of SkipParse
90
+ assert CompilationForm.options_for(:hit)[:deserializer][:skip_parse].is_a? SkipParse
91
91
 
92
92
  # inherit: true with block will still inherit the original class.
93
- _(AlbumForm.new(OpenStruct.new(band: OpenStruct.new)).band.band_id).must_equal 1
94
- _(CompilationForm.new(OpenStruct.new(band: OpenStruct.new)).band.band_id).must_equal 1
93
+ assert_equal AlbumForm.new(OpenStruct.new(band: OpenStruct.new)).band.band_id, 1
94
+ assert_equal CompilationForm.new(OpenStruct.new(band: OpenStruct.new)).band.band_id, 1
95
95
  end
96
96
 
97
97
  class CDForm < AlbumForm
@@ -101,5 +101,5 @@ class InheritTest < BaseTest
101
101
  end
102
102
  end
103
103
 
104
- it { _(CDForm.options_for(:band)[:internal_populator].instance_variable_get(:@user_proc)).must_equal "CD Populator" }
104
+ it { assert_equal CDForm.options_for(:band)[:internal_populator].instance_variable_get(:@user_proc), "CD Populator" }
105
105
  end
@@ -25,8 +25,8 @@ class ModuleInclusionTest < MiniTest::Spec
25
25
  params { required(:band).filled }
26
26
  end
27
27
 
28
- include Dry::Types.module # allows using Types::* in module.
29
- property :cool, type: DRY_TYPES_CONSTANT::Bool # test coercion.
28
+ include Dry.Types(default: :nominal) # allows using Types::* in module.
29
+ property :cool, type: Types::Params::Bool # test coercion.
30
30
  end
31
31
 
32
32
  # TODO: test if works, move stuff into inherit_schema!
@@ -60,24 +60,24 @@ class ModuleInclusionTest < MiniTest::Spec
60
60
  let(:song) { OpenStruct.new(band: OpenStruct.new(title: "Time Again")) }
61
61
 
62
62
  # nested form from module is present and creates accessor.
63
- it { _(SongForm.new(song).band.title).must_equal "Time Again" }
63
+ it { assert_equal SongForm.new(song).band.title, "Time Again" }
64
64
 
65
65
  # methods from module get included.
66
- it { _(SongForm.new(song).id).must_equal 1 }
67
- it { _(SongForm.new(song).band.id).must_equal 2 }
66
+ it { assert_equal SongForm.new(song).id, 1 }
67
+ it { assert_equal SongForm.new(song).band.id, 2 }
68
68
 
69
69
  # validators get inherited.
70
70
  it do
71
71
  form = SongForm.new(OpenStruct.new)
72
72
  form.validate({})
73
- _(form.errors.messages).must_equal(band: ["must be filled"])
73
+ assert_equal form.errors.messages, band: ["must be filled"]
74
74
  end
75
75
 
76
76
  # coercion works
77
77
  it do
78
78
  form = SongForm.new(OpenStruct.new)
79
79
  form.validate(cool: "1")
80
- _(form.cool).must_equal true
80
+ assert form.cool
81
81
  end
82
82
 
83
83
  # include a module into a module into a class :)
@@ -106,7 +106,7 @@ class ModuleInclusionTest < MiniTest::Spec
106
106
  it do
107
107
  form = AlbumForm.new(OpenStruct.new(band: OpenStruct.new))
108
108
  form.validate("band" => {})
109
- _(form.errors.messages).must_equal("band.title": ["must be filled"], "band.label": ["must be filled"], name: ["must be filled"])
109
+ assert_equal form.errors.messages, "band.title": ["must be filled"], "band.label": ["must be filled"], name: ["must be filled"]
110
110
  end
111
111
 
112
112
  describe "module with custom accessors" do
@@ -130,8 +130,8 @@ class ModuleInclusionTest < MiniTest::Spec
130
130
  let(:song) { OpenStruct.new(id: 1, title: "Instant Mash") }
131
131
 
132
132
  it do
133
- _(IncludingSongForm.new(song).id).must_equal 1
134
- _(IncludingSongForm.new(song).title).must_equal "INSTANT MASH"
133
+ assert_equal IncludingSongForm.new(song).id, 1
134
+ assert_equal IncludingSongForm.new(song).title, "INSTANT MASH"
135
135
  end
136
136
  end
137
137
  end
@@ -13,13 +13,13 @@ class ParseOptionTest < MiniTest::Spec
13
13
  let(:form) { CommentForm.new(Comment.new, user: current_user) }
14
14
 
15
15
  it do
16
- _(form.user).must_equal current_user
16
+ assert_equal form.user, current_user
17
17
 
18
18
  lorem = "Lorem ipsum dolor sit amet..."
19
19
  form.validate("content" => lorem, "user" => "not the current user")
20
20
 
21
- _(form.content).must_equal lorem
22
- _(form.user).must_equal current_user
21
+ assert_equal form.content, lorem
22
+ assert_equal form.user, current_user
23
23
  end
24
24
 
25
25
  describe "using ':parse' option doesn't override other ':deserialize' options" do
@@ -30,11 +30,11 @@ class ParseOptionTest < MiniTest::Spec
30
30
  end
31
31
 
32
32
  it do
33
- _(ArticleCommentForm.definitions.get(:user)[:deserializer][:writeable]).must_equal false
34
- _(ArticleCommentForm.definitions.get(:user)[:deserializer][:instance]).must_equal "Instance"
33
+ assert_equal ArticleCommentForm.definitions.get(:user)[:deserializer][:writeable], false
34
+ assert_equal ArticleCommentForm.definitions.get(:user)[:deserializer][:instance], "Instance"
35
35
 
36
- _(ArticleCommentForm.definitions.get(:article)[:deserializer][:writeable]).must_equal true
37
- _(ArticleCommentForm.definitions.get(:article)[:deserializer][:instance]).must_equal "Instance"
36
+ assert ArticleCommentForm.definitions.get(:article)[:deserializer][:writeable]
37
+ assert_equal ArticleCommentForm.definitions.get(:article)[:deserializer][:instance], "Instance"
38
38
  end
39
39
  end
40
40
  end
@@ -10,6 +10,6 @@ class ParsePipelineTest < MiniTest::Spec
10
10
  it "allows passing :parse_pipeline directly" do
11
11
  form = AlbumForm.new(Album.new)
12
12
  form.validate("name" => "Greatest Hits")
13
- _(form.name).must_equal "{\"name\"=>\"Greatest Hits\"}"
13
+ assert_equal form.name, "{\"name\"=>\"Greatest Hits\"}"
14
14
  end
15
15
  end
@@ -48,7 +48,7 @@ class PopulatorTest < MiniTest::Spec
48
48
  "name" => "override me!"
49
49
  )
50
50
 
51
- _(form.name).must_equal "!em edirrevo"
51
+ assert_equal form.name, "!em edirrevo"
52
52
  end
53
53
 
54
54
  # changing existing property :artist.
@@ -60,7 +60,7 @@ class PopulatorTest < MiniTest::Spec
60
60
  "artist" => {"name" => "Marcus Miller"}
61
61
  )
62
62
 
63
- _(form.artist.model.object_id).must_equal old_id
63
+ assert_equal form.artist.model.object_id, old_id
64
64
  end
65
65
 
66
66
  # use populator for default value on scalars?
@@ -68,36 +68,36 @@ class PopulatorTest < MiniTest::Spec
68
68
  # adding to collection via :populator.
69
69
  # valid.
70
70
  it "yyy" do
71
- _(form.validate(
71
+ assert form.validate(
72
72
  "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"},
73
73
  {"title" => "Rime Of The Ancient Mariner"}, # new song.
74
74
  {"title" => "Re-Education", "composer" => {"name" => "Rise Against"}}], # new song with new composer.
75
- )).must_equal true
75
+ )
76
76
 
77
- _(form.errors.messages.inspect).must_equal "{}"
77
+ assert_equal form.errors.messages.inspect, "{}"
78
78
 
79
79
  # form has updated.
80
- _(form.name).must_equal "The Dissent Of Man"
81
- _(form.songs[0].title).must_equal "Fallout"
82
- _(form.songs[1].title).must_equal "Roxanne"
83
- _(form.songs[1].composer.name).must_equal "Greg Graffin"
80
+ assert_equal form.name, "The Dissent Of Man"
81
+ assert_equal form.songs[0].title, "Fallout"
82
+ assert_equal form.songs[1].title, "Roxanne"
83
+ assert_equal form.songs[1].composer.name, "Greg Graffin"
84
84
 
85
- _(form.songs[1].composer.model).must_be_instance_of Artist
85
+ form.songs[1].composer.model.is_a? Artist
86
86
 
87
- _(form.songs[1].title).must_equal "Roxanne"
88
- _(form.songs[2].title).must_equal "Rime Of The Ancient Mariner" # new song added.
89
- _(form.songs[3].title).must_equal "Re-Education"
90
- _(form.songs[3].composer.name).must_equal "Rise Against"
91
- _(form.songs.size).must_equal 4
92
- _(form.artist.name).must_equal "Bad Religion"
87
+ assert_equal form.songs[1].title, "Roxanne"
88
+ assert_equal form.songs[2].title, "Rime Of The Ancient Mariner" # new song added.
89
+ assert_equal form.songs[3].title, "Re-Education"
90
+ assert_equal form.songs[3].composer.name, "Rise Against"
91
+ assert_equal form.songs.size, 4
92
+ assert_equal form.artist.name, "Bad Religion"
93
93
 
94
94
  # model has not changed, yet.
95
- _(album.name).must_equal "The Dissent Of Man"
96
- _(album.songs[0].title).must_equal "Broken"
97
- _(album.songs[1].title).must_equal "Resist Stance"
98
- _(album.songs[1].composer.name).must_equal "Greg Graffin"
99
- _(album.songs.size).must_equal 2
100
- _(album.artist.name).must_equal "Bad Religion"
95
+ assert_equal album.name, "The Dissent Of Man"
96
+ assert_equal album.songs[0].title, "Broken"
97
+ assert_equal album.songs[1].title, "Resist Stance"
98
+ assert_equal album.songs[1].composer.name, "Greg Graffin"
99
+ assert_equal album.songs.size, 2
100
+ assert_equal album.artist.name, "Bad Religion"
101
101
  end
102
102
  end
103
103
 
@@ -117,7 +117,7 @@ class PopulateWithMethodTest < Minitest::Spec
117
117
  it "runs populator method" do
118
118
  form.validate("title" => "override me!")
119
119
 
120
- _(form.title).must_equal "!em edirrevo"
120
+ assert_equal form.title, "!em edirrevo"
121
121
  end
122
122
  end
123
123
 
@@ -127,6 +127,14 @@ class PopulateWithCallableTest < Minitest::Spec
127
127
  class TitlePopulator
128
128
  include Uber::Callable
129
129
 
130
+ def call(form:, **options)
131
+ form.title = options[:fragment].reverse
132
+ end
133
+ end
134
+
135
+ class TitlePopulatorWithOldSignature
136
+ include Uber::Callable
137
+
130
138
  def call(form, options)
131
139
  form.title = options[:fragment].reverse
132
140
  end
@@ -136,12 +144,28 @@ class PopulateWithCallableTest < Minitest::Spec
136
144
  property :title, populator: TitlePopulator.new
137
145
  end
138
146
 
147
+ class AlbumFormWithOldPopulator < TestForm
148
+ property :title, populator: TitlePopulatorWithOldSignature.new
149
+ end
150
+
139
151
  let(:form) { AlbumForm.new(Album.new) }
140
152
 
141
153
  it "runs populator method" do
142
154
  form.validate("title" => "override me!")
143
155
 
144
- _(form.title).must_equal "!em edirrevo"
156
+ assert_equal form.title, "!em edirrevo"
157
+ end
158
+
159
+ it "gives warning when `form` is accepted as a positional argument" do
160
+ _, warnings = capture_io do
161
+ form = AlbumFormWithOldPopulator.new(Album.new)
162
+ form.validate("title" => "override me!")
163
+
164
+ assert_equal form.title, "!em edirrevo"
165
+ end
166
+
167
+ assert_equal warnings, %{[Reform] Accepting `form` as a positional argument in `:populator` will be deprecated. Please use `def call(form:, **options)` signature instead.
168
+ }
145
169
  end
146
170
  end
147
171
 
@@ -161,7 +185,7 @@ class PopulateWithProcTest < Minitest::Spec
161
185
  it "runs populator method" do
162
186
  form.validate("title" => "override me!")
163
187
 
164
- _(form.title).must_equal "!em edirrevo"
188
+ assert_equal form.title, "!em edirrevo"
165
189
  end
166
190
  end
167
191
 
@@ -216,35 +240,35 @@ class PopulateIfEmptyTest < MiniTest::Spec
216
240
  let(:form) { AlbumForm.new(album) }
217
241
 
218
242
  it do
219
- _(form.songs.size).must_equal 2
243
+ assert_equal form.songs.size, 2
220
244
 
221
- _(form.validate(
245
+ assert form.validate(
222
246
  "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"},
223
247
  {"title" => "Rime Of The Ancient Mariner"}, # new song.
224
248
  {"title" => "Re-Education", "composer" => {"name" => "Rise Against"}}], # new song with new composer.
225
- )).must_equal true
249
+ )
226
250
 
227
- _(form.errors.messages.inspect).must_equal "{}"
251
+ assert_equal form.errors.messages.inspect, "{}"
228
252
 
229
253
  # form has updated.
230
- _(form.name).must_equal "The Dissent Of Man"
231
- _(form.songs[0].title).must_equal "Fallout"
232
- _(form.songs[1].title).must_equal "Roxanne"
233
- _(form.songs[1].composer.name).must_equal "Greg Graffin"
234
- _(form.songs[1].title).must_equal "Roxanne"
235
- _(form.songs[2].title).must_equal "Rime Of The Ancient Mariner" # new song added.
236
- _(form.songs[3].title).must_equal "Re-Education"
237
- _(form.songs[3].composer.name).must_equal "Rise Against"
238
- _(form.songs.size).must_equal 4
239
- _(form.artist.name).must_equal "Bad Religion"
254
+ assert_equal form.name, "The Dissent Of Man"
255
+ assert_equal form.songs[0].title, "Fallout"
256
+ assert_equal form.songs[1].title, "Roxanne"
257
+ assert_equal form.songs[1].composer.name, "Greg Graffin"
258
+ assert_equal form.songs[1].title, "Roxanne"
259
+ assert_equal form.songs[2].title, "Rime Of The Ancient Mariner" # new song added.
260
+ assert_equal form.songs[3].title, "Re-Education"
261
+ assert_equal form.songs[3].composer.name, "Rise Against"
262
+ assert_equal form.songs.size, 4
263
+ assert_equal form.artist.name, "Bad Religion"
240
264
 
241
265
  # model has not changed, yet.
242
- _(album.name).must_equal "The Dissent Of Man"
243
- _(album.songs[0].title).must_equal "Broken"
244
- _(album.songs[1].title).must_equal "Resist Stance"
245
- _(album.songs[1].composer.name).must_equal "Greg Graffin"
246
- _(album.songs.size).must_equal 2
247
- _(album.artist.name).must_equal "Bad Religion"
266
+ assert_equal album.name, "The Dissent Of Man"
267
+ assert_equal album.songs[0].title, "Broken"
268
+ assert_equal album.songs[1].title, "Resist Stance"
269
+ assert_equal album.songs[1].composer.name, "Greg Graffin"
270
+ assert_equal album.songs.size, 2
271
+ assert_equal album.artist.name, "Bad Religion"
248
272
  end
249
273
 
250
274
  # trigger artist populator. lambda calling form instance method.
@@ -252,11 +276,11 @@ class PopulateIfEmptyTest < MiniTest::Spec
252
276
  form = AlbumForm.new(album = Album.new)
253
277
  form.validate("artist" => {"name" => "From Autumn To Ashes"})
254
278
 
255
- _(form.artist.name).must_equal "From Autumn To Ashes"
279
+ assert_equal form.artist.name, "From Autumn To Ashes"
256
280
  # test lambda was executed in form context.
257
- _(form.artist.model).must_be_instance_of AlbumForm::Sting
281
+ assert form.artist.model.is_a? AlbumForm::Sting
258
282
  # test lambda block arguments.
259
- _(form.artist.model.args.to_s).must_equal "[{\"name\"=>\"From Autumn To Ashes\"}, nil]"
283
+ assert_equal form.artist.model.args.to_s, "[{\"name\"=>\"From Autumn To Ashes\"}, nil]"
260
284
 
261
285
  assert_nil album.artist
262
286
  end
@@ -292,13 +316,72 @@ class PopulateIfEmptyWithDeletionTest < MiniTest::Spec
292
316
  let(:form) { AlbumForm.new(album) }
293
317
 
294
318
  it do
295
- _(form.validate(
319
+ assert form.validate(
296
320
  "songs" => [{"title" => "Broken, delete me!"}, {"title" => "Roxanne"}]
297
- )).must_equal true
321
+ )
322
+
323
+ assert_equal form.errors.messages.inspect, "{}"
298
324
 
299
- _(form.errors.messages.inspect).must_equal "{}"
325
+ assert_equal form.songs.size, 1
326
+ assert_equal form.songs[0].title, "Roxanne"
327
+ end
328
+ end
329
+
330
+ class PopulateWithFormKeyTest < MiniTest::Spec
331
+ Song = Struct.new(:title, :album, :composer)
332
+ Album = Struct.new(:name, :songs, :artist)
300
333
 
301
- _(form.songs.size).must_equal 1
302
- _(form.songs[0].title).must_equal "Roxanne"
334
+ let(:song) { Song.new('Broken') }
335
+ let(:song2) { Song.new('Resist Stance') }
336
+ let(:album) { Album.new('The Dissent Of Man', [song, song2]) }
337
+
338
+ class SongForm < TestForm
339
+ property :title
340
+
341
+ validation do
342
+ params { required(:title).filled }
343
+ end
344
+ end
345
+
346
+ class AlbumForm < TestForm
347
+ property :name
348
+
349
+ collection :songs, form: SongForm, populator: :populator!, model_identifier: :title
350
+
351
+ def populator!(fragment:, **)
352
+ item = songs.find { |song| song.title == fragment['title'] }
353
+ if item && fragment['delete'] == '1'
354
+ songs.delete(item)
355
+ return skip!
356
+ end
357
+ item || songs.append(Song.new)
358
+ end
359
+ end
360
+
361
+ let(:form) { AlbumForm.new(album) }
362
+
363
+ it do
364
+ assert_equal 2, form.songs.size
365
+
366
+ assert form.validate(
367
+ 'songs' => [
368
+ { 'title' => 'Broken' },
369
+ { 'title' => 'Resist Stance' },
370
+ { 'title' => 'Rime Of The Ancient Mariner' }
371
+ ]
372
+ )
373
+
374
+ assert_equal 3, form.songs.size
375
+
376
+ assert form.validate(
377
+ 'songs' => [
378
+ { 'title' => 'Broken', 'delete' => '1' },
379
+ { 'title' => 'Resist Stance' },
380
+ { 'title' => 'Rime Of The Ancient Mariner' }
381
+ ]
382
+ )
383
+ assert_equal 2, form.songs.size
384
+ assert_equal 'Resist Stance', form.songs.first.title
385
+ assert_equal 'Rime Of The Ancient Mariner', form.songs.last.title
303
386
  end
304
387
  end