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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +17 -0
- data/.gitignore +1 -1
- data/CHANGES.md +15 -0
- data/Gemfile +1 -1
- data/LICENSE.txt +1 -1
- data/README.md +5 -5
- data/Rakefile +1 -12
- data/lib/reform/contract/validate.rb +1 -1
- data/lib/reform/form/dry.rb +47 -9
- data/lib/reform/form/populator.rb +13 -3
- data/lib/reform/form/prepopulate.rb +1 -1
- data/lib/reform/form/validate.rb +3 -3
- data/lib/reform/validation/groups.rb +0 -1
- data/lib/reform/version.rb +1 -1
- data/reform.gemspec +2 -2
- data/test/call_test.rb +23 -0
- data/test/changed_test.rb +6 -6
- data/test/coercion_test.rb +17 -17
- data/test/{composition_new_api.rb → composition_test.rb} +27 -28
- data/test/{contract_new_api.rb → contract_test.rb} +8 -8
- data/test/default_test.rb +2 -2
- data/test/deserialize_test.rb +8 -8
- data/test/docs/validation_test.rb +134 -0
- data/test/{errors_new_api.rb → errors_test.rb} +41 -41
- data/test/feature_test.rb +2 -2
- data/test/fixtures/dry_error_messages.yml +64 -54
- data/test/{form_option_new_api.rb → form_option_test.rb} +1 -1
- data/test/{form_new_api.rb → form_test.rb} +3 -3
- data/test/from_test.rb +10 -10
- data/test/{inherit_new_api.rb → inherit_test.rb} +17 -17
- data/test/{module_new_api.rb → module_test.rb} +10 -10
- data/test/parse_option_test.rb +7 -7
- data/test/parse_pipeline_test.rb +1 -1
- data/test/{populate_new_api.rb → populate_test.rb} +136 -53
- data/test/populator_skip_test.rb +2 -2
- data/test/prepopulator_test.rb +16 -16
- data/test/read_only_test.rb +2 -2
- data/test/readable_test.rb +3 -3
- data/test/{reform_new_api.rb → reform_test.rb} +19 -19
- data/test/{save_new_api.rb → save_test.rb} +4 -4
- data/test/setup_test.rb +9 -9
- data/test/{skip_if_new_api.rb → skip_if_test.rb} +12 -12
- data/test/skip_setter_and_getter_test.rb +6 -6
- data/test/test_helper.rb +5 -6
- data/test/{validate_new_api.rb → validate_test.rb} +65 -78
- data/test/validation/{dry_validation_new_api.rb → dry_validation_test.rb} +124 -123
- data/test/validation/result_test.rb +14 -14
- data/test/virtual_test.rb +7 -7
- data/test/writeable_test.rb +8 -8
- metadata +43 -82
- data/.travis.yml +0 -16
- data/Appraisals +0 -8
- data/gemfiles/0.13.0.gemfile +0 -8
- data/gemfiles/1.5.0.gemfile +0 -9
- data/lib/reform/form/dry/new_api.rb +0 -45
- data/lib/reform/form/dry/old_api.rb +0 -61
- data/test/call_new_api.rb +0 -23
- data/test/call_old_api.rb +0 -23
- data/test/composition_old_api.rb +0 -184
- data/test/contract_old_api.rb +0 -77
- data/test/errors_old_api.rb +0 -230
- data/test/fixtures/dry_new_api_error_messages.yml +0 -104
- data/test/form_old_api.rb +0 -57
- data/test/form_option_old_api.rb +0 -24
- data/test/inherit_old_api.rb +0 -105
- data/test/module_old_api.rb +0 -146
- data/test/populate_old_api.rb +0 -304
- data/test/reform_old_api.rb +0 -202
- data/test/save_old_api.rb +0 -101
- data/test/skip_if_old_api.rb +0 -92
- data/test/validate_old_api.rb +0 -410
- 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
|
-
|
|
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 {
|
|
29
|
-
it {
|
|
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
|
-
|
|
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 {
|
|
35
|
-
it {
|
|
36
|
-
it {
|
|
37
|
-
it {
|
|
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 {
|
|
44
|
-
it {
|
|
45
|
-
it {
|
|
46
|
-
it {
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
73
|
-
|
|
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
|
-
|
|
79
|
-
|
|
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
|
-
|
|
81
|
+
assert AlbumForm.options_for(:band)[:internal_populator].is_a? Reform::Form::Populator::IfEmpty
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
assert_equal CompilationForm.options_for(:title)[:deserializer][:skip_parse], "skip_if from CompilationForm"
|
|
84
84
|
# pp CompilationForm.options_for(:songs)
|
|
85
|
-
|
|
85
|
+
assert CompilationForm.options_for(:songs)[:internal_populator].is_a? Reform::Form::Populator::IfEmpty
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
assert CompilationForm.options_for(:band)[:internal_populator].is_a? Reform::Form::Populator::IfEmpty
|
|
88
88
|
|
|
89
89
|
# completely overwrite inherited.
|
|
90
|
-
|
|
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
|
-
|
|
94
|
-
|
|
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 {
|
|
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
|
|
29
|
-
property :cool, type:
|
|
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 {
|
|
63
|
+
it { assert_equal SongForm.new(song).band.title, "Time Again" }
|
|
64
64
|
|
|
65
65
|
# methods from module get included.
|
|
66
|
-
it {
|
|
67
|
-
it {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
134
|
-
|
|
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
|
data/test/parse_option_test.rb
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
22
|
-
|
|
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
|
-
|
|
34
|
-
|
|
33
|
+
assert_equal ArticleCommentForm.definitions.get(:user)[:deserializer][:writeable], false
|
|
34
|
+
assert_equal ArticleCommentForm.definitions.get(:user)[:deserializer][:instance], "Instance"
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
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
|
data/test/parse_pipeline_test.rb
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
)
|
|
75
|
+
)
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
assert_equal form.errors.messages.inspect, "{}"
|
|
78
78
|
|
|
79
79
|
# form has updated.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
-
|
|
85
|
+
form.songs[1].composer.model.is_a? Artist
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
243
|
+
assert_equal form.songs.size, 2
|
|
220
244
|
|
|
221
|
-
|
|
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
|
-
)
|
|
249
|
+
)
|
|
226
250
|
|
|
227
|
-
|
|
251
|
+
assert_equal form.errors.messages.inspect, "{}"
|
|
228
252
|
|
|
229
253
|
# form has updated.
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
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
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
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
|
-
|
|
279
|
+
assert_equal form.artist.name, "From Autumn To Ashes"
|
|
256
280
|
# test lambda was executed in form context.
|
|
257
|
-
|
|
281
|
+
assert form.artist.model.is_a? AlbumForm::Sting
|
|
258
282
|
# test lambda block arguments.
|
|
259
|
-
|
|
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
|
-
|
|
319
|
+
assert form.validate(
|
|
296
320
|
"songs" => [{"title" => "Broken, delete me!"}, {"title" => "Roxanne"}]
|
|
297
|
-
)
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
assert_equal form.errors.messages.inspect, "{}"
|
|
298
324
|
|
|
299
|
-
|
|
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
|
-
|
|
302
|
-
|
|
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
|