reform 2.3.2 → 2.6.1
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 +23 -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} +128 -128
- data/test/validation/result_test.rb +14 -14
- data/test/virtual_test.rb +7 -7
- data/test/writeable_test.rb +8 -8
- metadata +42 -75
- 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 -47
- 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
data/test/module_old_api.rb
DELETED
@@ -1,146 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
require "reform/form/coercion"
|
3
|
-
|
4
|
-
class ModuleInclusionTest < MiniTest::Spec
|
5
|
-
module BandPropertyForm
|
6
|
-
include Reform::Form::Module
|
7
|
-
|
8
|
-
property :artist
|
9
|
-
property :band do
|
10
|
-
property :title
|
11
|
-
|
12
|
-
validation do
|
13
|
-
required(:title).filled
|
14
|
-
end
|
15
|
-
|
16
|
-
def id # gets mixed into Form, too.
|
17
|
-
2
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def id # gets mixed into Form, too.
|
22
|
-
1
|
23
|
-
end
|
24
|
-
|
25
|
-
validation do
|
26
|
-
required(:band).filled
|
27
|
-
end
|
28
|
-
|
29
|
-
include Dry::Types.module # allows using Types::* in module.
|
30
|
-
property :cool, type: DRY_TYPES_CONSTANT::Bool # test coercion.
|
31
|
-
|
32
|
-
module InstanceMethods
|
33
|
-
def artist=(new_value)
|
34
|
-
errors.add(:artist, "this needs to be filled") if new_value.nil?
|
35
|
-
super(new_value)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# TODO: test if works, move stuff into inherit_schema!
|
41
|
-
module AirplaysPropertyForm
|
42
|
-
include Reform::Form::Module
|
43
|
-
|
44
|
-
collection :airplays do
|
45
|
-
property :station
|
46
|
-
validation do
|
47
|
-
required(:station).filled
|
48
|
-
end
|
49
|
-
end
|
50
|
-
validation do
|
51
|
-
required(:airplays).filled
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
# test:
|
56
|
-
# by including BandPropertyForm into multiple classes we assure that options hashes don't get messed up by AM:V.
|
57
|
-
class HitForm < TestForm
|
58
|
-
include BandPropertyForm
|
59
|
-
end
|
60
|
-
|
61
|
-
class SongForm < TestForm
|
62
|
-
include Coercion
|
63
|
-
property :title
|
64
|
-
|
65
|
-
include BandPropertyForm
|
66
|
-
end
|
67
|
-
|
68
|
-
let(:song) { OpenStruct.new(band: OpenStruct.new(title: "Time Again"), artist: "Ketama") }
|
69
|
-
|
70
|
-
# nested form from module is present and creates accessor.
|
71
|
-
it { SongForm.new(song).band.title.must_equal "Time Again" }
|
72
|
-
it { SongForm.new(song).artist.must_equal "Ketama" }
|
73
|
-
|
74
|
-
# methods from module get included.
|
75
|
-
it { SongForm.new(song).id.must_equal 1 }
|
76
|
-
it { SongForm.new(song).band.id.must_equal 2 }
|
77
|
-
|
78
|
-
# validators get inherited.
|
79
|
-
it do
|
80
|
-
form = SongForm.new(OpenStruct.new)
|
81
|
-
form.validate(artist: nil)
|
82
|
-
form.errors.messages.must_equal(artist: ["this needs to be filled"], band: ["must be filled"])
|
83
|
-
end
|
84
|
-
|
85
|
-
# coercion works
|
86
|
-
it do
|
87
|
-
form = SongForm.new(OpenStruct.new)
|
88
|
-
form.validate({cool: "1"})
|
89
|
-
form.cool.must_equal true
|
90
|
-
end
|
91
|
-
|
92
|
-
# include a module into a module into a class :)
|
93
|
-
module AlbumFormModule
|
94
|
-
include Reform::Form::Module
|
95
|
-
include BandPropertyForm
|
96
|
-
|
97
|
-
property :name
|
98
|
-
validation do
|
99
|
-
required(:name).filled
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
class AlbumForm < TestForm
|
104
|
-
include AlbumFormModule
|
105
|
-
|
106
|
-
# pp heritage
|
107
|
-
property :band, inherit: true do
|
108
|
-
property :label
|
109
|
-
validation do
|
110
|
-
required(:label).filled
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
it do
|
116
|
-
form = AlbumForm.new(OpenStruct.new(band: OpenStruct.new))
|
117
|
-
form.validate("band" => {})
|
118
|
-
form.errors.messages.must_equal("band.title": ["must be filled"], "band.label": ["must be filled"], name: ["must be filled"])
|
119
|
-
end
|
120
|
-
|
121
|
-
describe "module with custom accessors" do
|
122
|
-
module SongModule
|
123
|
-
include Reform::Form::Module
|
124
|
-
|
125
|
-
property :id # no custom accessor for id.
|
126
|
-
property :title # has custom accessor.
|
127
|
-
|
128
|
-
module InstanceMethods
|
129
|
-
def title
|
130
|
-
super.upcase
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
class IncludingSongForm < TestForm
|
136
|
-
include SongModule
|
137
|
-
end
|
138
|
-
|
139
|
-
let(:song) { OpenStruct.new(id: 1, title: "Instant Mash") }
|
140
|
-
|
141
|
-
it do
|
142
|
-
IncludingSongForm.new(song).id.must_equal 1
|
143
|
-
IncludingSongForm.new(song).title.must_equal "INSTANT MASH"
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|
data/test/populate_old_api.rb
DELETED
@@ -1,304 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
|
3
|
-
class PopulatorTest < 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 < TestForm
|
9
|
-
property :name, populator: ->(options) { self.name = options[:fragment].reverse }
|
10
|
-
validation do
|
11
|
-
required(:name).filled
|
12
|
-
end
|
13
|
-
|
14
|
-
collection :songs,
|
15
|
-
populator: ->(fragment:, model:, index:, **) {
|
16
|
-
(item = model[index]) ? item : model.insert(index, Song.new)
|
17
|
-
} do
|
18
|
-
property :title
|
19
|
-
validation do
|
20
|
-
required(:title).filled
|
21
|
-
end
|
22
|
-
|
23
|
-
property :composer, populator: ->(options) { options[:model] || self.composer = Artist.new } do
|
24
|
-
property :name
|
25
|
-
validation do
|
26
|
-
required(:name).filled
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
# property :artist, populator: lambda { |fragment, options| (item = options.binding.get) ? item : Artist.new } do
|
32
|
-
# NOTE: we have to document that model here is the twin!
|
33
|
-
property :artist, populator: ->(options) { options[:model] || self.artist = Artist.new } do
|
34
|
-
property :name
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
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) }
|
43
|
-
|
44
|
-
let(:form) { AlbumForm.new(album) }
|
45
|
-
|
46
|
-
it "runs populator on scalar" do
|
47
|
-
form.validate(
|
48
|
-
"name" => "override me!"
|
49
|
-
)
|
50
|
-
|
51
|
-
form.name.must_equal "!em edirrevo"
|
52
|
-
end
|
53
|
-
|
54
|
-
# changing existing property :artist.
|
55
|
-
# TODO: check with artist==nil
|
56
|
-
it do
|
57
|
-
old_id = artist.object_id
|
58
|
-
|
59
|
-
form.validate(
|
60
|
-
"artist" => {"name" => "Marcus Miller"}
|
61
|
-
)
|
62
|
-
|
63
|
-
form.artist.model.object_id.must_equal old_id
|
64
|
-
end
|
65
|
-
|
66
|
-
# use populator for default value on scalars?
|
67
|
-
|
68
|
-
# adding to collection via :populator.
|
69
|
-
# valid.
|
70
|
-
it "yyy" do
|
71
|
-
form.validate(
|
72
|
-
"songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"},
|
73
|
-
{"title" => "Rime Of The Ancient Mariner"}, # new song.
|
74
|
-
{"title" => "Re-Education", "composer" => {"name" => "Rise Against"}}], # new song with new composer.
|
75
|
-
).must_equal true
|
76
|
-
|
77
|
-
form.errors.messages.inspect.must_equal "{}"
|
78
|
-
|
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"
|
84
|
-
|
85
|
-
form.songs[1].composer.model.must_be_instance_of Artist
|
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"
|
93
|
-
|
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"
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
class PopulateWithMethodTest < Minitest::Spec
|
105
|
-
Album = Struct.new(:title)
|
106
|
-
|
107
|
-
class AlbumForm < TestForm
|
108
|
-
property :title, populator: :title!
|
109
|
-
|
110
|
-
def title!(options)
|
111
|
-
self.title = options[:fragment].reverse
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
let(:form) { AlbumForm.new(Album.new) }
|
116
|
-
|
117
|
-
it "runs populator method" do
|
118
|
-
form.validate("title" => "override me!")
|
119
|
-
|
120
|
-
form.title.must_equal "!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 AlbumForm < TestForm
|
136
|
-
property :title, populator: TitlePopulator.new
|
137
|
-
end
|
138
|
-
|
139
|
-
let(:form) { AlbumForm.new(Album.new) }
|
140
|
-
|
141
|
-
it "runs populator method" do
|
142
|
-
form.validate("title" => "override me!")
|
143
|
-
|
144
|
-
form.title.must_equal "!em edirrevo"
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
class PopulateWithProcTest < Minitest::Spec
|
149
|
-
Album = Struct.new(:title)
|
150
|
-
|
151
|
-
TitlePopulator = ->(options) do
|
152
|
-
options[:represented].title = options[:fragment].reverse
|
153
|
-
end
|
154
|
-
|
155
|
-
class AlbumForm < TestForm
|
156
|
-
property :title, populator: TitlePopulator
|
157
|
-
end
|
158
|
-
|
159
|
-
let(:form) { AlbumForm.new(Album.new) }
|
160
|
-
|
161
|
-
it "runs populator method" do
|
162
|
-
form.validate("title" => "override me!")
|
163
|
-
|
164
|
-
form.title.must_equal "!em edirrevo"
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
class PopulateIfEmptyTest < MiniTest::Spec
|
169
|
-
Song = Struct.new(:title, :album, :composer)
|
170
|
-
Album = Struct.new(:name, :songs, :artist)
|
171
|
-
Artist = Struct.new(:name)
|
172
|
-
|
173
|
-
let(:song) { Song.new("Broken") }
|
174
|
-
let(:song_with_composer) { Song.new("Resist Stance", nil, composer) }
|
175
|
-
let(:composer) { Artist.new("Greg Graffin") }
|
176
|
-
let(:artist) { Artist.new("Bad Religion") }
|
177
|
-
let(:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
|
178
|
-
|
179
|
-
class AlbumForm < TestForm
|
180
|
-
property :name
|
181
|
-
|
182
|
-
collection :songs,
|
183
|
-
populate_if_empty: Song do # class name works.
|
184
|
-
|
185
|
-
property :title
|
186
|
-
validation do
|
187
|
-
required(:title).filled
|
188
|
-
end
|
189
|
-
|
190
|
-
property :composer, populate_if_empty: :populate_composer! do # lambda works, too. in form context.
|
191
|
-
property :name
|
192
|
-
validation do
|
193
|
-
required(:name).filled
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
private
|
198
|
-
def populate_composer!(options)
|
199
|
-
Artist.new
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
property :artist, populate_if_empty: ->(args) { create_artist(args[:fragment], args[:user_options]) } do # methods work, too.
|
204
|
-
property :name
|
205
|
-
end
|
206
|
-
|
207
|
-
private
|
208
|
-
class Sting < Artist
|
209
|
-
attr_accessor :args
|
210
|
-
end
|
211
|
-
def create_artist(input, user_options)
|
212
|
-
Sting.new.tap { |artist| artist.args = ([input, user_options].to_s) }
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
let(:form) { AlbumForm.new(album) }
|
217
|
-
|
218
|
-
it do
|
219
|
-
form.songs.size.must_equal 2
|
220
|
-
|
221
|
-
form.validate(
|
222
|
-
"songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"},
|
223
|
-
{"title" => "Rime Of The Ancient Mariner"}, # new song.
|
224
|
-
{"title" => "Re-Education", "composer" => {"name" => "Rise Against"}}], # new song with new composer.
|
225
|
-
).must_equal true
|
226
|
-
|
227
|
-
form.errors.messages.inspect.must_equal "{}"
|
228
|
-
|
229
|
-
# 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"
|
240
|
-
|
241
|
-
# 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"
|
248
|
-
end
|
249
|
-
|
250
|
-
# trigger artist populator. lambda calling form instance method.
|
251
|
-
it "xxxx" do
|
252
|
-
form = AlbumForm.new(album = Album.new)
|
253
|
-
form.validate("artist" => {"name" => "From Autumn To Ashes"})
|
254
|
-
|
255
|
-
form.artist.name.must_equal "From Autumn To Ashes"
|
256
|
-
# test lambda was executed in form context.
|
257
|
-
form.artist.model.must_be_instance_of AlbumForm::Sting
|
258
|
-
# test lambda block arguments.
|
259
|
-
form.artist.model.args.to_s.must_equal "[{\"name\"=>\"From Autumn To Ashes\"}, nil]"
|
260
|
-
|
261
|
-
assert_nil album.artist
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
# delete songs while deserializing.
|
266
|
-
class PopulateIfEmptyWithDeletionTest < MiniTest::Spec
|
267
|
-
Song = Struct.new(:title, :album, :composer)
|
268
|
-
Album = Struct.new(:name, :songs, :artist)
|
269
|
-
|
270
|
-
let(:song) { Song.new("Broken") }
|
271
|
-
let(:song2) { Song.new("Resist Stance") }
|
272
|
-
let(:album) { Album.new("The Dissent Of Man", [song, song2]) }
|
273
|
-
|
274
|
-
class AlbumForm < TestForm
|
275
|
-
property :name
|
276
|
-
|
277
|
-
collection :songs,
|
278
|
-
populate_if_empty: Song, skip_if: :delete_song! do
|
279
|
-
|
280
|
-
property :title
|
281
|
-
validation do
|
282
|
-
required(:title).filled
|
283
|
-
end
|
284
|
-
end
|
285
|
-
|
286
|
-
def delete_song!(options)
|
287
|
-
songs.delete(songs[0]) and return true if options[:fragment]["title"] == "Broken, delete me!"
|
288
|
-
false
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
let(:form) { AlbumForm.new(album) }
|
293
|
-
|
294
|
-
it do
|
295
|
-
form.validate(
|
296
|
-
"songs" => [{"title" => "Broken, delete me!"}, {"title" => "Roxanne"}]
|
297
|
-
).must_equal true
|
298
|
-
|
299
|
-
form.errors.messages.inspect.must_equal "{}"
|
300
|
-
|
301
|
-
form.songs.size.must_equal 1
|
302
|
-
form.songs[0].title.must_equal "Roxanne"
|
303
|
-
end
|
304
|
-
end
|
data/test/reform_old_api.rb
DELETED
@@ -1,202 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
|
3
|
-
class ReformTest < Minitest::Spec
|
4
|
-
let(:comp) { OpenStruct.new(name: "Duran Duran", title: "Rio") }
|
5
|
-
|
6
|
-
let(:form) { SongForm.new(comp) }
|
7
|
-
|
8
|
-
class SongForm < TestForm
|
9
|
-
property :name
|
10
|
-
property :title
|
11
|
-
|
12
|
-
validation do
|
13
|
-
required(:name).filled
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
describe "(new) form with empty models" do
|
18
|
-
let(:comp) { OpenStruct.new }
|
19
|
-
|
20
|
-
it "returns empty fields" do
|
21
|
-
assert_nil form.title
|
22
|
-
form.name.must_be_nil
|
23
|
-
end
|
24
|
-
|
25
|
-
describe "and submitted values" do
|
26
|
-
it "returns filled-out fields" do
|
27
|
-
form.validate("name" => "Duran Duran")
|
28
|
-
|
29
|
-
assert_nil form.title
|
30
|
-
form.name.must_equal "Duran Duran"
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
describe "(edit) form with existing models" do
|
36
|
-
it "returns filled-out fields" do
|
37
|
-
form.name.must_equal "Duran Duran"
|
38
|
-
form.title.must_equal "Rio"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
describe "#validate" do
|
43
|
-
let(:comp) { OpenStruct.new }
|
44
|
-
|
45
|
-
it "ignores unmapped fields in input" do
|
46
|
-
form.validate("name" => "Duran Duran", :genre => "80s")
|
47
|
-
assert_raises NoMethodError do
|
48
|
-
form.genre
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
it "returns true when valid" do
|
53
|
-
form.validate("name" => "Duran Duran").must_equal true
|
54
|
-
end
|
55
|
-
|
56
|
-
it "exposes input via property accessors" do
|
57
|
-
form.validate("name" => "Duran Duran")
|
58
|
-
|
59
|
-
form.name.must_equal "Duran Duran"
|
60
|
-
end
|
61
|
-
|
62
|
-
it "doesn't change model properties" do
|
63
|
-
form.validate("name" => "Duran Duran")
|
64
|
-
|
65
|
-
assert_nil comp.name # don't touch model, yet.
|
66
|
-
end
|
67
|
-
|
68
|
-
# TODO: test errors. test valid.
|
69
|
-
describe "invalid input" do
|
70
|
-
class ValidatingForm < TestForm
|
71
|
-
property :name
|
72
|
-
property :title
|
73
|
-
|
74
|
-
validation do
|
75
|
-
required(:name).filled
|
76
|
-
required(:title).filled
|
77
|
-
end
|
78
|
-
end
|
79
|
-
let(:form) { ValidatingForm.new(comp) }
|
80
|
-
|
81
|
-
it "returns false when invalid" do
|
82
|
-
form.validate({}).must_equal false
|
83
|
-
end
|
84
|
-
|
85
|
-
it "populates errors" do
|
86
|
-
form.validate({})
|
87
|
-
form.errors.messages.must_equal({name: ["must be filled"], title: ["must be filled"]})
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
describe "#save" do
|
93
|
-
let(:comp) { OpenStruct.new }
|
94
|
-
let(:form) { SongForm.new(comp) }
|
95
|
-
|
96
|
-
before { form.validate("name" => "Diesel Boy") }
|
97
|
-
|
98
|
-
it "xxpushes data to models" do
|
99
|
-
form.save
|
100
|
-
|
101
|
-
comp.name.must_equal "Diesel Boy"
|
102
|
-
assert_nil comp.title
|
103
|
-
end
|
104
|
-
|
105
|
-
describe "#save with block" do
|
106
|
-
it do
|
107
|
-
hash = {}
|
108
|
-
|
109
|
-
form.save do |map|
|
110
|
-
hash = map
|
111
|
-
end
|
112
|
-
|
113
|
-
hash.must_equal({"name" => "Diesel Boy", "title" => nil})
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
describe "#model" do
|
119
|
-
it { form.model.must_equal comp }
|
120
|
-
end
|
121
|
-
|
122
|
-
describe "inheritance" do
|
123
|
-
class HitForm < SongForm
|
124
|
-
property :position
|
125
|
-
validation do
|
126
|
-
required(:position).filled
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
let(:form) { HitForm.new(OpenStruct.new()) }
|
131
|
-
it do
|
132
|
-
form.validate({"title" => "The Body"})
|
133
|
-
form.title.must_equal "The Body"
|
134
|
-
assert_nil form.position
|
135
|
-
form.errors.messages.must_equal({name: ["must be filled"], position: ["must be filled"]})
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
class OverridingAccessorsTest < BaseTest
|
141
|
-
class SongForm < TestForm
|
142
|
-
property :title
|
143
|
-
|
144
|
-
def title=(v) # used in #validate.
|
145
|
-
super v * 2
|
146
|
-
end
|
147
|
-
|
148
|
-
def title # used in #sync.
|
149
|
-
super.downcase
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
let(:song) { Song.new("Pray") }
|
154
|
-
subject { SongForm.new(song) }
|
155
|
-
|
156
|
-
# override reader for presentation.
|
157
|
-
it { subject.title.must_equal "pray" }
|
158
|
-
|
159
|
-
describe "#save" do
|
160
|
-
before { subject.validate("title" => "Hey Little World") }
|
161
|
-
|
162
|
-
# reader always used
|
163
|
-
it { subject.title.must_equal "hey little worldhey little world" }
|
164
|
-
|
165
|
-
# the reader is not used when saving/syncing.
|
166
|
-
it do
|
167
|
-
subject.save do |hash|
|
168
|
-
hash["title"].must_equal "Hey Little WorldHey Little World"
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
# no reader or writer used when saving/syncing.
|
173
|
-
it do
|
174
|
-
song.extend(Saveable)
|
175
|
-
subject.save
|
176
|
-
song.title.must_equal "Hey Little WorldHey Little World"
|
177
|
-
end
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
class MethodInFormTest < MiniTest::Spec
|
182
|
-
class AlbumForm < TestForm
|
183
|
-
property :title
|
184
|
-
|
185
|
-
def title
|
186
|
-
"The Suffer And The Witness"
|
187
|
-
end
|
188
|
-
|
189
|
-
property :hit do
|
190
|
-
property :title
|
191
|
-
|
192
|
-
def title
|
193
|
-
"Drones"
|
194
|
-
end
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
# methods can be used instead of created accessors.
|
199
|
-
subject { AlbumForm.new(OpenStruct.new(hit: OpenStruct.new)) }
|
200
|
-
it { subject.title.must_equal "The Suffer And The Witness" }
|
201
|
-
it { subject.hit.title.must_equal "Drones" }
|
202
|
-
end
|