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
|
@@ -1,44 +1,104 @@
|
|
|
1
|
-
|
|
1
|
+
en:
|
|
2
|
+
dry_validation:
|
|
3
|
+
errors:
|
|
4
|
+
array?: "must be an array"
|
|
2
5
|
|
|
3
|
-
empty?: "
|
|
6
|
+
empty?: "must be empty"
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
excludes?: "must not include %{value}"
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
excluded_from?:
|
|
11
|
+
arg:
|
|
12
|
+
default: "must not be one of: %{list}"
|
|
13
|
+
range: "must not be one of: %{list_left} - %{list_right}"
|
|
8
14
|
|
|
9
|
-
|
|
15
|
+
eql?: "must be equal to %{left}"
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
not_eql?: "must not be equal to %{left}"
|
|
12
18
|
|
|
13
|
-
|
|
19
|
+
filled?: "must be filled"
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
format?: "is in invalid format"
|
|
16
22
|
|
|
17
|
-
|
|
23
|
+
number?: "must be a number"
|
|
18
24
|
|
|
19
|
-
|
|
25
|
+
odd?: "must be odd"
|
|
20
26
|
|
|
21
|
-
|
|
27
|
+
even?: "must be even"
|
|
22
28
|
|
|
23
|
-
|
|
29
|
+
gt?: "must be greater than %{num}"
|
|
24
30
|
|
|
25
|
-
|
|
31
|
+
gteq?: "must be greater than or equal to %{num}"
|
|
26
32
|
|
|
27
|
-
|
|
33
|
+
hash?: "must be a hash"
|
|
28
34
|
|
|
29
|
-
|
|
35
|
+
included_in?:
|
|
36
|
+
arg:
|
|
37
|
+
default: "must be one of: %{list}"
|
|
38
|
+
range: "must be one of: %{list_left} - %{list_right}"
|
|
30
39
|
|
|
31
|
-
|
|
40
|
+
includes?: "must include %{value}"
|
|
32
41
|
|
|
33
|
-
|
|
42
|
+
bool?: "must be boolean"
|
|
34
43
|
|
|
35
|
-
|
|
36
|
-
range: "%{name} size must be within %{left} - %{right}"
|
|
37
|
-
default: "%{name} size must be %{num}"
|
|
44
|
+
true?: "must be true"
|
|
38
45
|
|
|
39
|
-
|
|
46
|
+
false?: "must be false"
|
|
40
47
|
|
|
41
|
-
|
|
48
|
+
int?: "must be an integer"
|
|
42
49
|
|
|
43
|
-
|
|
50
|
+
float?: "must be a float"
|
|
44
51
|
|
|
52
|
+
decimal?: "must be a decimal"
|
|
53
|
+
|
|
54
|
+
date?: "must be a date"
|
|
55
|
+
|
|
56
|
+
date_time?: "must be a date time"
|
|
57
|
+
|
|
58
|
+
time?: "must be a time"
|
|
59
|
+
|
|
60
|
+
key?: "is missing"
|
|
61
|
+
|
|
62
|
+
attr?: "is missing"
|
|
63
|
+
|
|
64
|
+
lt?: "must be less than %{num}"
|
|
65
|
+
|
|
66
|
+
lteq?: "must be less than or equal to %{num}"
|
|
67
|
+
|
|
68
|
+
max_size?: "size cannot be greater than %{num}"
|
|
69
|
+
|
|
70
|
+
min_size?: "size cannot be less than %{num}"
|
|
71
|
+
|
|
72
|
+
none?: "cannot be defined"
|
|
73
|
+
|
|
74
|
+
str?: "must be a string"
|
|
75
|
+
|
|
76
|
+
type?: "must be %{type}"
|
|
77
|
+
|
|
78
|
+
size?:
|
|
79
|
+
arg:
|
|
80
|
+
default: "size must be %{size}"
|
|
81
|
+
range: "size must be within %{size_left} - %{size_right}"
|
|
82
|
+
|
|
83
|
+
value:
|
|
84
|
+
string:
|
|
85
|
+
arg:
|
|
86
|
+
default: "length must be %{size}"
|
|
87
|
+
range: "length must be within %{size_left} - %{size_right}"
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
rules:
|
|
92
|
+
name:
|
|
93
|
+
good_musical_taste?: "you're a bad person"
|
|
94
|
+
title:
|
|
95
|
+
good_musical_taste?: "you're a bad person"
|
|
96
|
+
songs:
|
|
97
|
+
a_song?: "must have at least one enabled song"
|
|
98
|
+
artist:
|
|
99
|
+
with_last_name?: "must have last name"
|
|
100
|
+
|
|
101
|
+
de:
|
|
102
|
+
dry_validation:
|
|
103
|
+
errors:
|
|
104
|
+
filled?: "muss abgefüllt sein"
|
data/test/form_option_test.rb
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "test_helper"
|
|
2
2
|
|
|
3
3
|
class FormOptionTest < MiniTest::Spec
|
|
4
4
|
Song = Struct.new(:title)
|
|
5
5
|
Album = Struct.new(:song)
|
|
6
6
|
|
|
7
|
-
class SongForm <
|
|
7
|
+
class SongForm < TestForm
|
|
8
8
|
property :title
|
|
9
9
|
validation do
|
|
10
|
-
|
|
10
|
+
params { required(:title).filled }
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
class AlbumForm <
|
|
14
|
+
class AlbumForm < TestForm
|
|
15
15
|
property :song, form: SongForm
|
|
16
16
|
end
|
|
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
|
data/test/form_test.rb
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "test_helper"
|
|
2
2
|
|
|
3
3
|
class FormTest < MiniTest::Spec
|
|
4
4
|
Artist = Struct.new(:name)
|
|
5
5
|
|
|
6
|
-
class AlbumForm <
|
|
6
|
+
class AlbumForm < TestForm
|
|
7
7
|
property :title
|
|
8
8
|
|
|
9
9
|
property :hit do
|
|
@@ -22,11 +22,11 @@ class FormTest < MiniTest::Spec
|
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
describe "::dup" do
|
|
25
|
-
let
|
|
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
|
|
29
|
-
it { AlbumForm.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.
|
|
@@ -37,7 +37,7 @@ class FormTest < MiniTest::Spec
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
cloned.validation do
|
|
40
|
-
|
|
40
|
+
params { required(:title).filled }
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
cloned.new(OpenStruct.new).validate({})
|
|
@@ -45,13 +45,13 @@ class FormTest < MiniTest::Spec
|
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
describe "#initialize" do
|
|
48
|
-
class ArtistForm <
|
|
48
|
+
class ArtistForm < TestForm
|
|
49
49
|
property :name
|
|
50
50
|
property :current_user, virtual: true
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
it "allows injecting :virtual options" do
|
|
54
|
-
ArtistForm.new(Artist.new, current_user: Object).current_user
|
|
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
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "test_helper"
|
|
2
2
|
|
|
3
3
|
class AsTest < BaseTest
|
|
4
|
-
class AlbumForm <
|
|
4
|
+
class AlbumForm < TestForm
|
|
5
5
|
property :name, from: :title
|
|
6
6
|
|
|
7
7
|
property :single, from: :hit do
|
|
@@ -19,46 +19,42 @@ class AsTest < BaseTest
|
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
let
|
|
22
|
+
let(:song2) { Song.new("Roxanne") }
|
|
23
23
|
|
|
24
|
-
let
|
|
24
|
+
let(:params) do
|
|
25
25
|
{
|
|
26
26
|
"name" => "Best Of The Police",
|
|
27
|
-
"single"
|
|
27
|
+
"single" => {"title" => "So Lonely"},
|
|
28
28
|
"tracks" => [{"name" => "Message In A Bottle"}, {"name" => "Roxanne"}]
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
end
|
|
31
31
|
|
|
32
32
|
subject { AlbumForm.new(Album.new("Best Of", hit, [Song.new("Fallout"), song2])) }
|
|
33
33
|
|
|
34
|
-
it { subject.name
|
|
35
|
-
it { subject.single.title
|
|
36
|
-
it { subject.tracks[0].name
|
|
37
|
-
it { subject.tracks[1].name
|
|
38
|
-
|
|
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" }
|
|
39
38
|
|
|
40
39
|
describe "#validate" do
|
|
41
40
|
|
|
42
|
-
|
|
43
41
|
before { subject.validate(params) }
|
|
44
42
|
|
|
45
|
-
it { subject.name
|
|
46
|
-
it { subject.single.title
|
|
47
|
-
it { subject.tracks[0].name
|
|
48
|
-
it { subject.tracks[1].name
|
|
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" }
|
|
49
47
|
end
|
|
50
48
|
|
|
51
|
-
|
|
52
49
|
describe "#sync" do
|
|
53
|
-
before
|
|
50
|
+
before do
|
|
54
51
|
subject.tracks[1].name = "Livin' Ain't No Crime"
|
|
55
52
|
subject.sync
|
|
56
|
-
|
|
53
|
+
end
|
|
57
54
|
|
|
58
|
-
it { song2.title
|
|
55
|
+
it { assert_equal song2.title, "Livin' Ain't No Crime" }
|
|
59
56
|
end
|
|
60
57
|
|
|
61
|
-
|
|
62
58
|
describe "#save (nested hash)" do
|
|
63
59
|
before { subject.validate(params) }
|
|
64
60
|
|
|
@@ -69,7 +65,7 @@ class AsTest < BaseTest
|
|
|
69
65
|
hash = nested_hash
|
|
70
66
|
end
|
|
71
67
|
|
|
72
|
-
hash
|
|
68
|
+
assert_equal hash, "title" => "Best Of The Police", "hit" => {"title" => "So Lonely"}, "songs" => [{"title" => "Message In A Bottle"}, {"title" => "Roxanne"}], "band" => nil
|
|
73
69
|
end
|
|
74
70
|
end
|
|
75
71
|
end
|
data/test/inherit_test.rb
CHANGED
|
@@ -1,119 +1,105 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
1
|
+
require "test_helper"
|
|
2
|
+
require "representable/json"
|
|
3
3
|
|
|
4
4
|
class InheritTest < BaseTest
|
|
5
5
|
Populator = Reform::Form::Populator
|
|
6
6
|
|
|
7
|
-
class
|
|
7
|
+
class SkipParse
|
|
8
|
+
include Uber::Callable
|
|
9
|
+
def call(*_args)
|
|
10
|
+
false
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class AlbumForm < TestForm
|
|
8
15
|
property :title, deserializer: {instance: "Instance"}, skip_if: "skip_if in AlbumForm" # allow direct configuration of :deserializer.
|
|
9
16
|
|
|
10
|
-
property :hit,
|
|
17
|
+
property :hit, populate_if_empty: ->(*) { Song.new } do
|
|
11
18
|
property :title
|
|
19
|
+
validation do
|
|
20
|
+
params { required(:title).filled }
|
|
21
|
+
end
|
|
12
22
|
end
|
|
13
23
|
|
|
14
|
-
collection :songs, populate_if_empty:
|
|
24
|
+
collection :songs, populate_if_empty: -> {}, skip_if: :all_blank do
|
|
15
25
|
property :title
|
|
16
26
|
end
|
|
17
27
|
|
|
18
|
-
property :
|
|
19
|
-
|
|
20
|
-
def artist_id
|
|
28
|
+
property :band, populate_if_empty: -> {} do
|
|
29
|
+
def band_id
|
|
21
30
|
1
|
|
22
31
|
end
|
|
23
32
|
end
|
|
24
33
|
end
|
|
25
34
|
|
|
26
|
-
puts
|
|
27
|
-
puts "inherit"
|
|
28
|
-
|
|
29
35
|
class CompilationForm < AlbumForm
|
|
30
36
|
property :title, inherit: true, skip_if: "skip_if from CompilationForm"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
# puts representer_class.representable_attrs.
|
|
38
|
-
# get(:hit)[:extend].evaluate(nil).new(OpenStruct.new).rating
|
|
37
|
+
property :hit, inherit: true, populate_if_empty: ->(*) { Song.new }, skip_if: SkipParse.new do
|
|
38
|
+
property :rating
|
|
39
|
+
validation do
|
|
40
|
+
params { required(:rating).filled }
|
|
41
|
+
end
|
|
42
|
+
end
|
|
39
43
|
|
|
40
44
|
# NO collection here, this is entirely inherited.
|
|
41
|
-
# collection :songs, ..
|
|
42
|
-
|
|
43
|
-
property :artist, inherit: true do # inherit everything, but explicitely.
|
|
44
|
-
end
|
|
45
45
|
|
|
46
|
-
#
|
|
47
|
-
property :hit, skip_if: "SkipParse" do
|
|
46
|
+
property :band, inherit: true do # inherit everything, but explicitely.
|
|
48
47
|
end
|
|
49
|
-
|
|
50
|
-
# override partly.
|
|
51
48
|
end
|
|
52
49
|
|
|
53
|
-
let
|
|
50
|
+
let(:album) { Album.new(nil, Song.new, [], Band.new) }
|
|
54
51
|
subject { CompilationForm.new(album) }
|
|
55
52
|
|
|
53
|
+
it do
|
|
54
|
+
subject.validate("hit" => {"title" => "LA Drone", "rating" => 10})
|
|
55
|
+
assert_equal subject.hit.title, "LA Drone"
|
|
56
|
+
assert_equal subject.hit.rating, 10
|
|
57
|
+
assert_equal subject.errors.messages, {}
|
|
58
|
+
end
|
|
56
59
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
# }
|
|
64
|
-
|
|
65
|
-
# it do
|
|
66
|
-
# subject.validate({})
|
|
67
|
-
# subject.hit.title.must_equal nil
|
|
68
|
-
# subject.hit.rating.must_equal nil
|
|
69
|
-
# subject.errors.messages.must_equal({:"hit.title"=>["can't be blank"], :"hit.rating"=>["can't be blank"]})
|
|
70
|
-
# end
|
|
71
|
-
|
|
72
|
-
require "pp"
|
|
60
|
+
it do
|
|
61
|
+
subject.validate({})
|
|
62
|
+
assert_nil subject.model.hit.title
|
|
63
|
+
assert_nil subject.model.hit.rating
|
|
64
|
+
assert_equal subject.errors.messages, "hit.title": ["must be filled"], "hit.rating": ["must be filled"]
|
|
65
|
+
end
|
|
73
66
|
|
|
74
67
|
it "xxx" do
|
|
75
68
|
# sub hashes like :deserializer must be properly cloned when inheriting.
|
|
76
|
-
AlbumForm.options_for(:title)[:deserializer].object_id
|
|
69
|
+
refute_equal AlbumForm.options_for(:title)[:deserializer].object_id, CompilationForm.options_for(:title)[:deserializer].object_id
|
|
77
70
|
|
|
78
71
|
# don't overwrite direct deserializer: {} configuration.
|
|
79
|
-
AlbumForm.options_for(:title)[:internal_populator].
|
|
80
|
-
AlbumForm.options_for(:title)[:deserializer][:skip_parse]
|
|
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"
|
|
81
74
|
|
|
82
|
-
AlbumForm.options_for(:hit)[:internal_populator].inspect.must_match /Reform::Form::Populator:.+ @user_proc="Populator"/
|
|
75
|
+
# AlbumForm.options_for(:hit)[:internal_populator].inspect.must_match /Reform::Form::Populator:.+ @user_proc="Populator"/
|
|
83
76
|
# AlbumForm.options_for(:hit)[:deserializer][:instance].inspect.must_be_instance_with Reform::Form::Populator, user_proc: "Populator"
|
|
84
77
|
|
|
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
|
|
85
80
|
|
|
86
|
-
AlbumForm.options_for(:
|
|
87
|
-
AlbumForm.options_for(:songs)[:deserializer][:skip_parse].must_be_instance_of Reform::Form::Validate::Skip::AllBlank
|
|
88
|
-
|
|
89
|
-
AlbumForm.options_for(:artist)[:internal_populator].must_be_instance_of Reform::Form::Populator::IfEmpty
|
|
81
|
+
assert AlbumForm.options_for(:band)[:internal_populator].is_a? Reform::Form::Populator::IfEmpty
|
|
90
82
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
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"
|
|
94
84
|
# pp CompilationForm.options_for(:songs)
|
|
95
|
-
CompilationForm.options_for(:songs)[:internal_populator].
|
|
96
|
-
|
|
85
|
+
assert CompilationForm.options_for(:songs)[:internal_populator].is_a? Reform::Form::Populator::IfEmpty
|
|
97
86
|
|
|
98
|
-
CompilationForm.options_for(:
|
|
87
|
+
assert CompilationForm.options_for(:band)[:internal_populator].is_a? Reform::Form::Populator::IfEmpty
|
|
99
88
|
|
|
100
89
|
# completely overwrite inherited.
|
|
101
|
-
CompilationForm.options_for(:hit)[:
|
|
102
|
-
CompilationForm.options_for(:hit)[:deserializer][:skip_parse].must_equal "SkipParse"
|
|
103
|
-
|
|
90
|
+
assert CompilationForm.options_for(:hit)[:deserializer][:skip_parse].is_a? SkipParse
|
|
104
91
|
|
|
105
92
|
# inherit: true with block will still inherit the original class.
|
|
106
|
-
AlbumForm.new(OpenStruct.new(
|
|
107
|
-
CompilationForm.new(OpenStruct.new(
|
|
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
|
|
108
95
|
end
|
|
109
96
|
|
|
110
|
-
|
|
111
97
|
class CDForm < AlbumForm
|
|
112
|
-
# override :
|
|
113
|
-
property :
|
|
98
|
+
# override :band's original populate_if_empty but with :inherit.
|
|
99
|
+
property :band, inherit: true, populator: "CD Populator" do
|
|
114
100
|
|
|
115
101
|
end
|
|
116
102
|
end
|
|
117
103
|
|
|
118
|
-
it { CDForm.options_for(:
|
|
119
|
-
end
|
|
104
|
+
it { assert_equal CDForm.options_for(:band)[:internal_populator].instance_variable_get(:@user_proc), "CD Populator" }
|
|
105
|
+
end
|
data/test/module_test.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
require "test_helper"
|
|
2
|
-
require
|
|
2
|
+
require "reform/form/coercion"
|
|
3
3
|
|
|
4
4
|
class ModuleInclusionTest < MiniTest::Spec
|
|
5
5
|
module BandPropertyForm
|
|
@@ -9,7 +9,7 @@ class ModuleInclusionTest < MiniTest::Spec
|
|
|
9
9
|
property :title
|
|
10
10
|
|
|
11
11
|
validation do
|
|
12
|
-
|
|
12
|
+
params { required(:title).filled }
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def id # gets mixed into Form, too.
|
|
@@ -22,11 +22,11 @@ class ModuleInclusionTest < MiniTest::Spec
|
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
validation do
|
|
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!
|
|
@@ -36,53 +36,50 @@ class ModuleInclusionTest < MiniTest::Spec
|
|
|
36
36
|
collection :airplays do
|
|
37
37
|
property :station
|
|
38
38
|
validation do
|
|
39
|
-
|
|
39
|
+
params { required(:station).filled }
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
42
|
validation do
|
|
43
|
-
|
|
43
|
+
params { required(:airplays).filled }
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
|
|
48
47
|
# test:
|
|
49
48
|
# by including BandPropertyForm into multiple classes we assure that options hashes don't get messed up by AM:V.
|
|
50
|
-
class HitForm <
|
|
49
|
+
class HitForm < TestForm
|
|
51
50
|
include BandPropertyForm
|
|
52
51
|
end
|
|
53
52
|
|
|
54
|
-
class SongForm <
|
|
53
|
+
class SongForm < TestForm
|
|
55
54
|
include Coercion
|
|
56
55
|
property :title
|
|
57
56
|
|
|
58
57
|
include BandPropertyForm
|
|
59
58
|
end
|
|
60
59
|
|
|
61
|
-
|
|
62
|
-
let (:song) { OpenStruct.new(:band => OpenStruct.new(:title => "Time Again")) }
|
|
60
|
+
let(:song) { OpenStruct.new(band: OpenStruct.new(title: "Time Again")) }
|
|
63
61
|
|
|
64
62
|
# nested form from module is present and creates accessor.
|
|
65
|
-
it { SongForm.new(song).band.title
|
|
63
|
+
it { assert_equal SongForm.new(song).band.title, "Time Again" }
|
|
66
64
|
|
|
67
65
|
# methods from module get included.
|
|
68
|
-
it { SongForm.new(song).id
|
|
69
|
-
it { SongForm.new(song).band.id
|
|
66
|
+
it { assert_equal SongForm.new(song).id, 1 }
|
|
67
|
+
it { assert_equal SongForm.new(song).band.id, 2 }
|
|
70
68
|
|
|
71
69
|
# validators get inherited.
|
|
72
70
|
it do
|
|
73
71
|
form = SongForm.new(OpenStruct.new)
|
|
74
72
|
form.validate({})
|
|
75
|
-
form.errors.messages
|
|
73
|
+
assert_equal form.errors.messages, band: ["must be filled"]
|
|
76
74
|
end
|
|
77
75
|
|
|
78
76
|
# coercion works
|
|
79
77
|
it do
|
|
80
78
|
form = SongForm.new(OpenStruct.new)
|
|
81
|
-
form.validate(
|
|
82
|
-
form.cool
|
|
79
|
+
form.validate(cool: "1")
|
|
80
|
+
assert form.cool
|
|
83
81
|
end
|
|
84
82
|
|
|
85
|
-
|
|
86
83
|
# include a module into a module into a class :)
|
|
87
84
|
module AlbumFormModule
|
|
88
85
|
include Reform::Form::Module
|
|
@@ -90,29 +87,28 @@ class ModuleInclusionTest < MiniTest::Spec
|
|
|
90
87
|
|
|
91
88
|
property :name
|
|
92
89
|
validation do
|
|
93
|
-
|
|
90
|
+
params { required(:name).filled }
|
|
94
91
|
end
|
|
95
92
|
end
|
|
96
93
|
|
|
97
|
-
class AlbumForm <
|
|
94
|
+
class AlbumForm < TestForm
|
|
98
95
|
include AlbumFormModule
|
|
99
96
|
|
|
100
97
|
# pp heritage
|
|
101
|
-
property :band, :
|
|
98
|
+
property :band, inherit: true do
|
|
102
99
|
property :label
|
|
103
100
|
validation do
|
|
104
|
-
|
|
101
|
+
params { required(:label).filled }
|
|
105
102
|
end
|
|
106
103
|
end
|
|
107
104
|
end
|
|
108
105
|
|
|
109
106
|
it do
|
|
110
|
-
form = AlbumForm.new(OpenStruct.new(:
|
|
111
|
-
form.validate(
|
|
112
|
-
form.errors.messages
|
|
107
|
+
form = AlbumForm.new(OpenStruct.new(band: OpenStruct.new))
|
|
108
|
+
form.validate("band" => {})
|
|
109
|
+
assert_equal form.errors.messages, "band.title": ["must be filled"], "band.label": ["must be filled"], name: ["must be filled"]
|
|
113
110
|
end
|
|
114
111
|
|
|
115
|
-
|
|
116
112
|
describe "module with custom accessors" do
|
|
117
113
|
module SongModule
|
|
118
114
|
include Reform::Form::Module
|
|
@@ -127,16 +123,15 @@ class ModuleInclusionTest < MiniTest::Spec
|
|
|
127
123
|
end
|
|
128
124
|
end
|
|
129
125
|
|
|
130
|
-
class IncludingSongForm <
|
|
126
|
+
class IncludingSongForm < TestForm
|
|
131
127
|
include SongModule
|
|
132
128
|
end
|
|
133
129
|
|
|
134
|
-
let
|
|
130
|
+
let(:song) { OpenStruct.new(id: 1, title: "Instant Mash") }
|
|
135
131
|
|
|
136
132
|
it do
|
|
137
|
-
IncludingSongForm.new(song).id
|
|
138
|
-
IncludingSongForm.new(song).title
|
|
133
|
+
assert_equal IncludingSongForm.new(song).id, 1
|
|
134
|
+
assert_equal IncludingSongForm.new(song).title, "INSTANT MASH"
|
|
139
135
|
end
|
|
140
136
|
end
|
|
141
137
|
end
|
|
142
|
-
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require "test_helper"
|
|
2
|
+
|
|
3
|
+
class ParseOptionTest < MiniTest::Spec
|
|
4
|
+
Comment = Struct.new(:content, :user)
|
|
5
|
+
User = Struct.new(:name)
|
|
6
|
+
|
|
7
|
+
class CommentForm < TestForm
|
|
8
|
+
property :content
|
|
9
|
+
property :user, parse: false
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
let(:current_user) { User.new("Peter") }
|
|
13
|
+
let(:form) { CommentForm.new(Comment.new, user: current_user) }
|
|
14
|
+
|
|
15
|
+
it do
|
|
16
|
+
assert_equal form.user, current_user
|
|
17
|
+
|
|
18
|
+
lorem = "Lorem ipsum dolor sit amet..."
|
|
19
|
+
form.validate("content" => lorem, "user" => "not the current user")
|
|
20
|
+
|
|
21
|
+
assert_equal form.content, lorem
|
|
22
|
+
assert_equal form.user, current_user
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
describe "using ':parse' option doesn't override other ':deserialize' options" do
|
|
26
|
+
class ArticleCommentForm < TestForm
|
|
27
|
+
property :content
|
|
28
|
+
property :article, deserializer: {instance: "Instance"}
|
|
29
|
+
property :user, parse: false, deserializer: {instance: "Instance"}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it do
|
|
33
|
+
assert_equal ArticleCommentForm.definitions.get(:user)[:deserializer][:writeable], false
|
|
34
|
+
assert_equal ArticleCommentForm.definitions.get(:user)[:deserializer][:instance], "Instance"
|
|
35
|
+
|
|
36
|
+
assert ArticleCommentForm.definitions.get(:article)[:deserializer][:writeable]
|
|
37
|
+
assert_equal ArticleCommentForm.definitions.get(:article)[:deserializer][:instance], "Instance"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|