reform 2.2.4 → 2.6.2
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 +5 -5
- data/.github/workflows/ci.yml +17 -0
- data/.gitignore +5 -1
- data/CHANGES.md +80 -4
- data/CONTRIBUTING.md +31 -0
- data/Gemfile +2 -16
- data/ISSUE_TEMPLATE.md +25 -0
- data/LICENSE.txt +1 -1
- data/README.md +10 -12
- data/Rakefile +6 -10
- data/lib/reform/contract/custom_error.rb +41 -0
- data/lib/reform/contract/validate.rb +53 -23
- data/lib/reform/contract.rb +7 -17
- data/lib/reform/errors.rb +61 -0
- data/lib/reform/form/call.rb +1 -1
- data/lib/reform/form/composition.rb +2 -2
- data/lib/reform/form/dry/input_hash.rb +37 -0
- data/lib/reform/form/dry.rb +25 -35
- data/lib/reform/form/populator.rb +20 -26
- data/lib/reform/form/prepopulate.rb +5 -4
- data/lib/reform/form/validate.rb +29 -14
- data/lib/reform/form.rb +36 -10
- data/lib/reform/result.rb +90 -0
- data/lib/reform/validation/groups.rb +12 -28
- data/lib/reform/validation.rb +19 -11
- data/lib/reform/version.rb +1 -1
- data/lib/reform.rb +1 -0
- data/reform.gemspec +13 -13
- data/test/benchmarking.rb +39 -6
- data/test/call_test.rb +9 -9
- data/test/changed_test.rb +14 -14
- data/test/coercion_test.rb +57 -25
- data/test/composition_test.rb +85 -49
- data/test/contract/custom_error_test.rb +55 -0
- data/test/contract_test.rb +20 -20
- data/test/default_test.rb +4 -4
- data/test/deserialize_test.rb +17 -20
- data/test/docs/validation_test.rb +134 -0
- data/test/errors_test.rb +142 -82
- data/test/feature_test.rb +10 -12
- data/test/fixtures/dry_error_messages.yml +83 -23
- data/test/form_option_test.rb +5 -5
- data/test/form_test.rb +8 -8
- data/test/from_test.rb +18 -22
- data/test/inherit_test.rb +54 -68
- data/test/module_test.rb +27 -32
- data/test/parse_option_test.rb +40 -0
- data/test/parse_pipeline_test.rb +4 -4
- data/test/populate_test.rb +217 -100
- data/test/populator_skip_test.rb +11 -11
- data/test/prepopulator_test.rb +24 -25
- data/test/read_only_test.rb +12 -1
- data/test/readable_test.rb +9 -9
- data/test/reform_test.rb +47 -66
- data/test/save_test.rb +35 -23
- data/test/setup_test.rb +17 -17
- data/test/skip_if_test.rb +33 -22
- data/test/skip_setter_and_getter_test.rb +9 -10
- data/test/test_helper.rb +23 -14
- data/test/validate_test.rb +165 -145
- data/test/validation/dry_validation_test.rb +630 -146
- data/test/validation/result_test.rb +77 -0
- data/test/validation_library_provided_test.rb +16 -0
- data/test/virtual_test.rb +47 -7
- data/test/writeable_test.rb +38 -9
- metadata +46 -38
- data/.travis.yml +0 -11
- data/gemfiles/Gemfile.disposable-0.3 +0 -6
- data/lib/reform/contract/errors.rb +0 -43
- data/lib/reform/form/mongoid.rb +0 -37
- data/lib/reform/form/orm.rb +0 -26
- data/lib/reform/mongoid.rb +0 -4
- data/test/deprecation_test.rb +0 -27
- data/test/readonly_test.rb +0 -14
- data/test/validation/dry_test.rb +0 -60
- data/test/validation/errors.yml +0 -4
data/test/parse_pipeline_test.rb
CHANGED
|
@@ -3,13 +3,13 @@ require "test_helper"
|
|
|
3
3
|
class ParsePipelineTest < MiniTest::Spec
|
|
4
4
|
Album = Struct.new(:name)
|
|
5
5
|
|
|
6
|
-
class AlbumForm <
|
|
7
|
-
property :name, deserializer: {
|
|
6
|
+
class AlbumForm < TestForm
|
|
7
|
+
property :name, deserializer: {parse_pipeline: ->(input, options) { Representable::Pipeline[->(ipt, opts) { opts[:represented].name = ipt.inspect }] }}
|
|
8
8
|
end
|
|
9
9
|
|
|
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
|
|
13
|
+
assert_equal form.name, "{\"name\"=>\"Greatest Hits\"}"
|
|
14
14
|
end
|
|
15
|
-
end
|
|
15
|
+
end
|
data/test/populate_test.rb
CHANGED
|
@@ -5,27 +5,25 @@ class PopulatorTest < MiniTest::Spec
|
|
|
5
5
|
Album = Struct.new(:name, :songs, :artist)
|
|
6
6
|
Artist = Struct.new(:name)
|
|
7
7
|
|
|
8
|
-
class AlbumForm <
|
|
8
|
+
class AlbumForm < TestForm
|
|
9
9
|
property :name, populator: ->(options) { self.name = options[:fragment].reverse }
|
|
10
10
|
validation do
|
|
11
|
-
|
|
11
|
+
params { required(:name).filled }
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
collection :songs,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
(item = collection[index]) ? item : collection.insert(index, Song.new) } do
|
|
19
|
-
|
|
15
|
+
populator: ->(fragment:, model:, index:, **) {
|
|
16
|
+
(item = model[index]) ? item : model.insert(index, Song.new)
|
|
17
|
+
} do
|
|
20
18
|
property :title
|
|
21
19
|
validation do
|
|
22
|
-
|
|
20
|
+
params { required(:title).filled }
|
|
23
21
|
end
|
|
24
22
|
|
|
25
|
-
property :composer, populator: ->(options) { options[:model] || self.composer= Artist.new } do
|
|
23
|
+
property :composer, populator: ->(options) { options[:model] || self.composer = Artist.new } do
|
|
26
24
|
property :name
|
|
27
25
|
validation do
|
|
28
|
-
|
|
26
|
+
params { required(:name).filled }
|
|
29
27
|
end
|
|
30
28
|
end
|
|
31
29
|
end
|
|
@@ -37,20 +35,20 @@ class PopulatorTest < MiniTest::Spec
|
|
|
37
35
|
end
|
|
38
36
|
end
|
|
39
37
|
|
|
40
|
-
let
|
|
41
|
-
let
|
|
42
|
-
let
|
|
43
|
-
let
|
|
44
|
-
let
|
|
38
|
+
let(:song) { Song.new("Broken") }
|
|
39
|
+
let(:song_with_composer) { Song.new("Resist Stance", nil, composer) }
|
|
40
|
+
let(:composer) { Artist.new("Greg Graffin") }
|
|
41
|
+
let(:artist) { Artist.new("Bad Religion") }
|
|
42
|
+
let(:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
|
|
45
43
|
|
|
46
|
-
let
|
|
44
|
+
let(:form) { AlbumForm.new(album) }
|
|
47
45
|
|
|
48
46
|
it "runs populator on scalar" do
|
|
49
47
|
form.validate(
|
|
50
48
|
"name" => "override me!"
|
|
51
49
|
)
|
|
52
50
|
|
|
53
|
-
form.name
|
|
51
|
+
assert_equal form.name, "!em edirrevo"
|
|
54
52
|
end
|
|
55
53
|
|
|
56
54
|
# changing existing property :artist.
|
|
@@ -62,7 +60,7 @@ class PopulatorTest < MiniTest::Spec
|
|
|
62
60
|
"artist" => {"name" => "Marcus Miller"}
|
|
63
61
|
)
|
|
64
62
|
|
|
65
|
-
form.artist.model.object_id
|
|
63
|
+
assert_equal form.artist.model.object_id, old_id
|
|
66
64
|
end
|
|
67
65
|
|
|
68
66
|
# use populator for default value on scalars?
|
|
@@ -70,44 +68,43 @@ class PopulatorTest < MiniTest::Spec
|
|
|
70
68
|
# adding to collection via :populator.
|
|
71
69
|
# valid.
|
|
72
70
|
it "yyy" do
|
|
73
|
-
form.validate(
|
|
71
|
+
assert form.validate(
|
|
74
72
|
"songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"},
|
|
75
73
|
{"title" => "Rime Of The Ancient Mariner"}, # new song.
|
|
76
74
|
{"title" => "Re-Education", "composer" => {"name" => "Rise Against"}}], # new song with new composer.
|
|
77
|
-
)
|
|
75
|
+
)
|
|
78
76
|
|
|
79
|
-
form.errors.messages.inspect
|
|
77
|
+
assert_equal form.errors.messages.inspect, "{}"
|
|
80
78
|
|
|
81
79
|
# form has updated.
|
|
82
|
-
form.name
|
|
83
|
-
form.songs[0].title
|
|
84
|
-
form.songs[1].title
|
|
85
|
-
form.songs[1].composer.name
|
|
86
|
-
|
|
87
|
-
form.songs[1].composer.model.must_be_instance_of Artist
|
|
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"
|
|
88
84
|
|
|
89
|
-
form.songs[1].
|
|
90
|
-
form.songs[2].title.must_equal "Rime Of The Ancient Mariner" # new song added.
|
|
91
|
-
form.songs[3].title.must_equal "Re-Education"
|
|
92
|
-
form.songs[3].composer.name.must_equal "Rise Against"
|
|
93
|
-
form.songs.size.must_equal 4
|
|
94
|
-
form.artist.name.must_equal "Bad Religion"
|
|
85
|
+
form.songs[1].composer.model.is_a? Artist
|
|
95
86
|
|
|
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"
|
|
96
93
|
|
|
97
94
|
# model has not changed, yet.
|
|
98
|
-
album.name
|
|
99
|
-
album.songs[0].title
|
|
100
|
-
album.songs[1].title
|
|
101
|
-
album.songs[1].composer.name
|
|
102
|
-
album.songs.size
|
|
103
|
-
album.artist.name
|
|
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"
|
|
104
101
|
end
|
|
105
102
|
end
|
|
106
103
|
|
|
107
104
|
class PopulateWithMethodTest < Minitest::Spec
|
|
108
105
|
Album = Struct.new(:title)
|
|
109
106
|
|
|
110
|
-
class AlbumForm <
|
|
107
|
+
class AlbumForm < TestForm
|
|
111
108
|
property :title, populator: :title!
|
|
112
109
|
|
|
113
110
|
def title!(options)
|
|
@@ -115,14 +112,80 @@ class PopulateWithMethodTest < Minitest::Spec
|
|
|
115
112
|
end
|
|
116
113
|
end
|
|
117
114
|
|
|
118
|
-
let
|
|
115
|
+
let(:form) { AlbumForm.new(Album.new) }
|
|
119
116
|
|
|
120
117
|
it "runs populator method" do
|
|
121
|
-
form.validate(
|
|
122
|
-
|
|
123
|
-
|
|
118
|
+
form.validate("title" => "override me!")
|
|
119
|
+
|
|
120
|
+
assert_equal form.title, "!em edirrevo"
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
class PopulateWithCallableTest < Minitest::Spec
|
|
125
|
+
Album = Struct.new(:title)
|
|
126
|
+
|
|
127
|
+
class TitlePopulator
|
|
128
|
+
include Uber::Callable
|
|
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
|
+
|
|
138
|
+
def call(form, options)
|
|
139
|
+
form.title = options[:fragment].reverse
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
class AlbumForm < TestForm
|
|
144
|
+
property :title, populator: TitlePopulator.new
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
class AlbumFormWithOldPopulator < TestForm
|
|
148
|
+
property :title, populator: TitlePopulatorWithOldSignature.new
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
let(:form) { AlbumForm.new(Album.new) }
|
|
152
|
+
|
|
153
|
+
it "runs populator method" do
|
|
154
|
+
form.validate("title" => "override me!")
|
|
155
|
+
|
|
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
|
+
}
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
class PopulateWithProcTest < Minitest::Spec
|
|
173
|
+
Album = Struct.new(:title)
|
|
174
|
+
|
|
175
|
+
TitlePopulator = ->(options) do
|
|
176
|
+
options[:represented].title = options[:fragment].reverse
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
class AlbumForm < TestForm
|
|
180
|
+
property :title, populator: TitlePopulator
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
let(:form) { AlbumForm.new(Album.new) }
|
|
124
184
|
|
|
125
|
-
|
|
185
|
+
it "runs populator method" do
|
|
186
|
+
form.validate("title" => "override me!")
|
|
187
|
+
|
|
188
|
+
assert_equal form.title, "!em edirrevo"
|
|
126
189
|
end
|
|
127
190
|
end
|
|
128
191
|
|
|
@@ -131,15 +194,13 @@ class PopulateIfEmptyTest < MiniTest::Spec
|
|
|
131
194
|
Album = Struct.new(:name, :songs, :artist)
|
|
132
195
|
Artist = Struct.new(:name)
|
|
133
196
|
|
|
134
|
-
let
|
|
135
|
-
let
|
|
136
|
-
let
|
|
137
|
-
let
|
|
138
|
-
let
|
|
139
|
-
|
|
197
|
+
let(:song) { Song.new("Broken") }
|
|
198
|
+
let(:song_with_composer) { Song.new("Resist Stance", nil, composer) }
|
|
199
|
+
let(:composer) { Artist.new("Greg Graffin") }
|
|
200
|
+
let(:artist) { Artist.new("Bad Religion") }
|
|
201
|
+
let(:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
|
|
140
202
|
|
|
141
|
-
|
|
142
|
-
class AlbumForm < Reform::Form
|
|
203
|
+
class AlbumForm < TestForm
|
|
143
204
|
property :name
|
|
144
205
|
|
|
145
206
|
collection :songs,
|
|
@@ -147,68 +208,67 @@ class PopulateIfEmptyTest < MiniTest::Spec
|
|
|
147
208
|
|
|
148
209
|
property :title
|
|
149
210
|
validation do
|
|
150
|
-
|
|
211
|
+
params { required(:title).filled }
|
|
151
212
|
end
|
|
152
213
|
|
|
153
214
|
property :composer, populate_if_empty: :populate_composer! do # lambda works, too. in form context.
|
|
154
215
|
property :name
|
|
155
216
|
validation do
|
|
156
|
-
|
|
217
|
+
params { required(:name).filled }
|
|
157
218
|
end
|
|
158
219
|
end
|
|
159
220
|
|
|
160
221
|
private
|
|
161
|
-
def populate_composer!(
|
|
222
|
+
def populate_composer!(options)
|
|
162
223
|
Artist.new
|
|
163
224
|
end
|
|
164
225
|
end
|
|
165
226
|
|
|
166
|
-
property :artist, populate_if_empty:
|
|
227
|
+
property :artist, populate_if_empty: ->(args) { create_artist(args[:fragment], args[:user_options]) } do # methods work, too.
|
|
167
228
|
property :name
|
|
168
229
|
end
|
|
169
230
|
|
|
170
|
-
|
|
231
|
+
private
|
|
171
232
|
class Sting < Artist
|
|
172
233
|
attr_accessor :args
|
|
173
234
|
end
|
|
174
235
|
def create_artist(input, user_options)
|
|
175
|
-
Sting.new.tap { |artist| artist.args=([input, user_options].to_s) }
|
|
236
|
+
Sting.new.tap { |artist| artist.args = ([input, user_options].to_s) }
|
|
176
237
|
end
|
|
177
238
|
end
|
|
178
239
|
|
|
179
|
-
let
|
|
240
|
+
let(:form) { AlbumForm.new(album) }
|
|
180
241
|
|
|
181
242
|
it do
|
|
182
|
-
form.songs.size
|
|
243
|
+
assert_equal form.songs.size, 2
|
|
183
244
|
|
|
184
|
-
form.validate(
|
|
185
|
-
"songs"
|
|
245
|
+
assert form.validate(
|
|
246
|
+
"songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"},
|
|
186
247
|
{"title" => "Rime Of The Ancient Mariner"}, # new song.
|
|
187
248
|
{"title" => "Re-Education", "composer" => {"name" => "Rise Against"}}], # new song with new composer.
|
|
188
|
-
)
|
|
249
|
+
)
|
|
189
250
|
|
|
190
|
-
form.errors.messages.inspect
|
|
251
|
+
assert_equal form.errors.messages.inspect, "{}"
|
|
191
252
|
|
|
192
253
|
# form has updated.
|
|
193
|
-
form.name
|
|
194
|
-
form.songs[0].title
|
|
195
|
-
form.songs[1].title
|
|
196
|
-
form.songs[1].composer.name
|
|
197
|
-
form.songs[1].title
|
|
198
|
-
form.songs[2].title
|
|
199
|
-
form.songs[3].title
|
|
200
|
-
form.songs[3].composer.name
|
|
201
|
-
form.songs.size
|
|
202
|
-
form.artist.name
|
|
203
|
-
|
|
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"
|
|
204
264
|
|
|
205
265
|
# model has not changed, yet.
|
|
206
|
-
album.name
|
|
207
|
-
album.songs[0].title
|
|
208
|
-
album.songs[1].title
|
|
209
|
-
album.songs[1].composer.name
|
|
210
|
-
album.songs.size
|
|
211
|
-
album.artist.name
|
|
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"
|
|
212
272
|
end
|
|
213
273
|
|
|
214
274
|
# trigger artist populator. lambda calling form instance method.
|
|
@@ -216,28 +276,26 @@ class PopulateIfEmptyTest < MiniTest::Spec
|
|
|
216
276
|
form = AlbumForm.new(album = Album.new)
|
|
217
277
|
form.validate("artist" => {"name" => "From Autumn To Ashes"})
|
|
218
278
|
|
|
219
|
-
form.artist.name
|
|
279
|
+
assert_equal form.artist.name, "From Autumn To Ashes"
|
|
220
280
|
# test lambda was executed in form context.
|
|
221
|
-
form.artist.model.
|
|
281
|
+
assert form.artist.model.is_a? AlbumForm::Sting
|
|
222
282
|
# test lambda block arguments.
|
|
223
|
-
form.artist.model.args.to_s
|
|
283
|
+
assert_equal form.artist.model.args.to_s, "[{\"name\"=>\"From Autumn To Ashes\"}, nil]"
|
|
224
284
|
|
|
225
|
-
album.artist
|
|
285
|
+
assert_nil album.artist
|
|
226
286
|
end
|
|
227
287
|
end
|
|
228
288
|
|
|
229
|
-
|
|
230
289
|
# delete songs while deserializing.
|
|
231
290
|
class PopulateIfEmptyWithDeletionTest < MiniTest::Spec
|
|
232
291
|
Song = Struct.new(:title, :album, :composer)
|
|
233
292
|
Album = Struct.new(:name, :songs, :artist)
|
|
234
293
|
|
|
235
|
-
let
|
|
236
|
-
let
|
|
237
|
-
let
|
|
238
|
-
|
|
294
|
+
let(:song) { Song.new("Broken") }
|
|
295
|
+
let(:song2) { Song.new("Resist Stance") }
|
|
296
|
+
let(:album) { Album.new("The Dissent Of Man", [song, song2]) }
|
|
239
297
|
|
|
240
|
-
class AlbumForm <
|
|
298
|
+
class AlbumForm < TestForm
|
|
241
299
|
property :name
|
|
242
300
|
|
|
243
301
|
collection :songs,
|
|
@@ -245,7 +303,7 @@ class PopulateIfEmptyWithDeletionTest < MiniTest::Spec
|
|
|
245
303
|
|
|
246
304
|
property :title
|
|
247
305
|
validation do
|
|
248
|
-
|
|
306
|
+
params { required(:title).filled }
|
|
249
307
|
end
|
|
250
308
|
end
|
|
251
309
|
|
|
@@ -255,16 +313,75 @@ class PopulateIfEmptyWithDeletionTest < MiniTest::Spec
|
|
|
255
313
|
end
|
|
256
314
|
end
|
|
257
315
|
|
|
258
|
-
let
|
|
316
|
+
let(:form) { AlbumForm.new(album) }
|
|
259
317
|
|
|
260
318
|
it do
|
|
261
|
-
form.validate(
|
|
262
|
-
"songs"
|
|
263
|
-
)
|
|
319
|
+
assert form.validate(
|
|
320
|
+
"songs" => [{"title" => "Broken, delete me!"}, {"title" => "Roxanne"}]
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
assert_equal form.errors.messages.inspect, "{}"
|
|
324
|
+
|
|
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)
|
|
333
|
+
|
|
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
|
|
264
348
|
|
|
265
|
-
form
|
|
349
|
+
collection :songs, form: SongForm, populator: :populator!, model_identifier: :title
|
|
266
350
|
|
|
267
|
-
|
|
268
|
-
|
|
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
|
|
269
386
|
end
|
|
270
387
|
end
|
data/test/populator_skip_test.rb
CHANGED
|
@@ -4,14 +4,14 @@ class PopulatorSkipTest < MiniTest::Spec
|
|
|
4
4
|
Album = Struct.new(:songs)
|
|
5
5
|
Song = Struct.new(:title)
|
|
6
6
|
|
|
7
|
+
class AlbumForm < TestForm
|
|
8
|
+
collection :songs, populator: :my_populator do
|
|
9
|
+
property :title
|
|
10
|
+
end
|
|
7
11
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return skip! if options[:fragment][:title] == "Good"
|
|
12
|
-
songs[options[:index]]
|
|
13
|
-
} do
|
|
14
|
-
property :title
|
|
12
|
+
def my_populator(options)
|
|
13
|
+
return skip! if options[:fragment][:title] == "Good"
|
|
14
|
+
songs[options[:index]]
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
|
|
@@ -21,8 +21,8 @@ class PopulatorSkipTest < MiniTest::Spec
|
|
|
21
21
|
|
|
22
22
|
form.validate(hash)
|
|
23
23
|
|
|
24
|
-
form.songs.size
|
|
25
|
-
form.songs[0].title
|
|
26
|
-
form.songs[1].title
|
|
24
|
+
assert_equal form.songs.size, 2
|
|
25
|
+
assert_nil form.songs[0].title
|
|
26
|
+
assert_equal form.songs[1].title, "Bad"
|
|
27
27
|
end
|
|
28
|
-
end
|
|
28
|
+
end
|
data/test/prepopulator_test.rb
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "test_helper"
|
|
2
2
|
|
|
3
3
|
class PrepopulatorTest < MiniTest::Spec
|
|
4
4
|
Song = Struct.new(:title, :band, :length)
|
|
5
5
|
Band = Struct.new(:name)
|
|
6
6
|
|
|
7
|
-
class AlbumForm <
|
|
8
|
-
property :title, prepopulator: ->(*){ self.title = "Another Day At Work" } # normal assignment.
|
|
7
|
+
class AlbumForm < TestForm
|
|
8
|
+
property :title, prepopulator: ->(*) { self.title = "Another Day At Work" } # normal assignment.
|
|
9
9
|
property :length
|
|
10
10
|
|
|
11
11
|
property :hit, prepopulator: ->(options) { self.hit = Song.new(options[:title]) } do # use user options.
|
|
12
12
|
property :title
|
|
13
13
|
|
|
14
|
-
property :band, prepopulator: ->(options){ self.band = my_band(options[:title]) } do # invoke your own code.
|
|
14
|
+
property :band, prepopulator: ->(options) { self.band = my_band(options[:title]) } do # invoke your own code.
|
|
15
15
|
property :name
|
|
16
16
|
end
|
|
17
17
|
|
|
@@ -24,7 +24,7 @@ class PrepopulatorTest < MiniTest::Spec
|
|
|
24
24
|
property :title
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
private
|
|
28
28
|
def prepopulate_songs!(options)
|
|
29
29
|
if songs == nil
|
|
30
30
|
self.songs = [Song.new, Song.new]
|
|
@@ -37,25 +37,25 @@ class PrepopulatorTest < MiniTest::Spec
|
|
|
37
37
|
it do
|
|
38
38
|
form = AlbumForm.new(OpenStruct.new(length: 1)).prepopulate!(title: "Potemkin City Limits")
|
|
39
39
|
|
|
40
|
-
form.length
|
|
41
|
-
form.title
|
|
42
|
-
form.hit.model
|
|
43
|
-
form.songs.size
|
|
44
|
-
form.songs[0].model
|
|
45
|
-
form.songs[1].model
|
|
46
|
-
form.songs[1].model
|
|
40
|
+
assert_equal form.length, 1
|
|
41
|
+
assert_equal form.title, "Another Day At Work"
|
|
42
|
+
assert_equal form.hit.model, Song.new("Potemkin City Limits")
|
|
43
|
+
assert_equal form.songs.size, 2
|
|
44
|
+
assert_equal form.songs[0].model, Song.new
|
|
45
|
+
assert_equal form.songs[1].model, Song.new
|
|
46
|
+
assert_equal form.songs[1].model, Song.new
|
|
47
47
|
# prepopulate works more than 1 level, recursive.
|
|
48
48
|
# it also passes options properly down there.
|
|
49
|
-
form.hit.band.model
|
|
49
|
+
assert_equal form.hit.band.model, Band.new("Potemkin City Limits")
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
# add to existing collection.
|
|
53
53
|
it do
|
|
54
|
-
form = AlbumForm.new(OpenStruct.new(songs: [Song.new])).prepopulate!
|
|
54
|
+
form = AlbumForm.new(OpenStruct.new(songs: [Song.new])).prepopulate!(title: "Potemkin City Limits")
|
|
55
55
|
|
|
56
|
-
form.songs.size
|
|
57
|
-
form.songs[0].model
|
|
58
|
-
form.songs[1].model
|
|
56
|
+
assert_equal form.songs.size, 2
|
|
57
|
+
assert_equal form.songs[0].model, Song.new
|
|
58
|
+
assert_equal form.songs[1].model, Song.new
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
61
|
|
|
@@ -63,7 +63,7 @@ end
|
|
|
63
63
|
class PrepopulateWithoutConfiguration < MiniTest::Spec
|
|
64
64
|
Song = Struct.new(:title)
|
|
65
65
|
|
|
66
|
-
class AlbumForm <
|
|
66
|
+
class AlbumForm < TestForm
|
|
67
67
|
collection :songs do
|
|
68
68
|
property :title
|
|
69
69
|
end
|
|
@@ -75,15 +75,14 @@ class PrepopulateWithoutConfiguration < MiniTest::Spec
|
|
|
75
75
|
|
|
76
76
|
subject { AlbumForm.new(OpenStruct.new(songs: [], hit: nil)).prepopulate! }
|
|
77
77
|
|
|
78
|
-
it { subject.songs.size
|
|
78
|
+
it { assert_equal subject.songs.size, 0 }
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
-
|
|
82
81
|
class ManualPrepopulatorOverridingTest < MiniTest::Spec
|
|
83
82
|
Song = Struct.new(:title, :band, :length)
|
|
84
83
|
Band = Struct.new(:name)
|
|
85
84
|
|
|
86
|
-
class AlbumForm <
|
|
85
|
+
class AlbumForm < TestForm
|
|
87
86
|
property :title
|
|
88
87
|
property :length
|
|
89
88
|
|
|
@@ -105,8 +104,8 @@ class ManualPrepopulatorOverridingTest < MiniTest::Spec
|
|
|
105
104
|
it do
|
|
106
105
|
form = AlbumForm.new(OpenStruct.new(length: 1)).prepopulate!(title: "Potemkin City Limits")
|
|
107
106
|
|
|
108
|
-
form.length
|
|
109
|
-
form.hit.model
|
|
110
|
-
form.hit.title
|
|
107
|
+
assert_equal form.length, 1
|
|
108
|
+
assert_equal form.hit.model, Song.new("Potemkin City Limits")
|
|
109
|
+
assert_equal form.hit.title, "Potemkin City Limits"
|
|
111
110
|
end
|
|
112
|
-
end
|
|
111
|
+
end
|
data/test/read_only_test.rb
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "test_helper"
|
|
2
2
|
|
|
3
|
+
class ReadonlyTest < MiniTest::Spec
|
|
4
|
+
class SongForm < TestForm
|
|
5
|
+
property :artist
|
|
6
|
+
property :title, writeable: false
|
|
7
|
+
# TODO: what to do with virtual values?
|
|
8
|
+
end
|
|
3
9
|
|
|
10
|
+
let(:form) { SongForm.new(OpenStruct.new) }
|
|
11
|
+
|
|
12
|
+
it { refute form.readonly?(:artist) }
|
|
13
|
+
it { assert form.readonly?(:title) }
|
|
14
|
+
end
|