reform 2.3.0.rc1 → 2.3.0.rc2
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/.gitignore +2 -0
- data/.rubocop.yml +30 -0
- data/.rubocop_todo.yml +460 -0
- data/.travis.yml +26 -11
- data/CHANGES.md +25 -2
- data/Gemfile +6 -3
- data/ISSUE_TEMPLATE.md +1 -1
- data/README.md +2 -4
- data/Rakefile +18 -9
- data/lib/reform/contract.rb +7 -7
- data/lib/reform/contract/custom_error.rb +41 -0
- data/lib/reform/contract/validate.rb +9 -5
- data/lib/reform/errors.rb +27 -15
- data/lib/reform/form.rb +22 -11
- data/lib/reform/form/call.rb +1 -1
- data/lib/reform/form/composition.rb +2 -2
- data/lib/reform/form/dry.rb +10 -86
- data/lib/reform/form/dry/input_hash.rb +37 -0
- data/lib/reform/form/dry/new_api.rb +58 -0
- data/lib/reform/form/dry/old_api.rb +61 -0
- data/lib/reform/form/populator.rb +9 -11
- data/lib/reform/form/prepopulate.rb +3 -2
- data/lib/reform/form/validate.rb +19 -12
- data/lib/reform/result.rb +36 -9
- data/lib/reform/validation.rb +10 -8
- data/lib/reform/validation/groups.rb +2 -3
- data/lib/reform/version.rb +1 -1
- data/reform.gemspec +10 -9
- data/test/benchmarking.rb +10 -11
- data/test/call_new_api.rb +23 -0
- data/test/{call_test.rb → call_old_api.rb} +3 -3
- data/test/changed_test.rb +7 -7
- data/test/coercion_test.rb +50 -18
- data/test/composition_new_api.rb +186 -0
- data/test/{composition_test.rb → composition_old_api.rb} +23 -26
- data/test/contract/custom_error_test.rb +55 -0
- data/test/contract_new_api.rb +77 -0
- data/test/{contract_test.rb → contract_old_api.rb} +8 -8
- data/test/default_test.rb +1 -1
- data/test/deserialize_test.rb +8 -11
- data/test/errors_new_api.rb +225 -0
- data/test/errors_old_api.rb +230 -0
- data/test/feature_test.rb +7 -9
- data/test/fixtures/dry_error_messages.yml +5 -2
- data/test/fixtures/dry_new_api_error_messages.yml +104 -0
- data/test/form_new_api.rb +57 -0
- data/test/{form_test.rb → form_old_api.rb} +2 -2
- data/test/form_option_new_api.rb +24 -0
- data/test/{form_option_test.rb → form_option_old_api.rb} +1 -1
- data/test/from_test.rb +8 -12
- data/test/inherit_new_api.rb +105 -0
- data/test/{inherit_test.rb → inherit_old_api.rb} +10 -17
- data/test/module_new_api.rb +137 -0
- data/test/{module_test.rb → module_old_api.rb} +19 -15
- data/test/parse_option_test.rb +5 -5
- data/test/parse_pipeline_test.rb +2 -2
- data/test/populate_new_api.rb +304 -0
- data/test/{populate_test.rb → populate_old_api.rb} +28 -34
- data/test/populator_skip_test.rb +1 -2
- data/test/prepopulator_test.rb +5 -6
- data/test/read_only_test.rb +12 -1
- data/test/readable_test.rb +5 -5
- data/test/reform_new_api.rb +204 -0
- data/test/{reform_test.rb → reform_old_api.rb} +17 -23
- data/test/save_new_api.rb +101 -0
- data/test/{save_test.rb → save_old_api.rb} +10 -13
- data/test/setup_test.rb +6 -6
- data/test/{skip_if_test.rb → skip_if_new_api.rb} +20 -9
- data/test/skip_if_old_api.rb +92 -0
- data/test/skip_setter_and_getter_test.rb +2 -3
- data/test/test_helper.rb +13 -5
- data/test/validate_new_api.rb +408 -0
- data/test/{validate_test.rb → validate_old_api.rb} +43 -53
- data/test/validation/dry_validation_new_api.rb +826 -0
- data/test/validation/{dry_validation_test.rb → dry_validation_old_api.rb} +223 -116
- data/test/validation/result_test.rb +20 -22
- data/test/validation_library_provided_test.rb +3 -3
- data/test/virtual_test.rb +46 -6
- data/test/writeable_test.rb +7 -7
- metadata +101 -51
- data/test/errors_test.rb +0 -180
- data/test/readonly_test.rb +0 -14
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require "test_helper"
|
|
2
|
+
|
|
3
|
+
class FormOptionTest < MiniTest::Spec
|
|
4
|
+
Song = Struct.new(:title)
|
|
5
|
+
Album = Struct.new(:song)
|
|
6
|
+
|
|
7
|
+
class SongForm < TestForm
|
|
8
|
+
property :title
|
|
9
|
+
validation do
|
|
10
|
+
params { required(:title).filled }
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class AlbumForm < TestForm
|
|
15
|
+
property :song, form: SongForm
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it do
|
|
19
|
+
form = AlbumForm.new(Album.new(Song.new("When It Comes To You")))
|
|
20
|
+
form.song.title.must_equal "When It Comes To You"
|
|
21
|
+
|
|
22
|
+
form.validate(song: {title: "Run For Cover"})
|
|
23
|
+
end
|
|
24
|
+
end
|
data/test/from_test.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "test_helper"
|
|
2
2
|
|
|
3
3
|
class AsTest < BaseTest
|
|
4
4
|
class AlbumForm < TestForm
|
|
@@ -19,15 +19,15 @@ 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
|
|
|
@@ -36,10 +36,8 @@ class AsTest < BaseTest
|
|
|
36
36
|
it { subject.tracks[0].name.must_equal "Fallout" }
|
|
37
37
|
it { subject.tracks[1].name.must_equal "Roxanne" }
|
|
38
38
|
|
|
39
|
-
|
|
40
39
|
describe "#validate" do
|
|
41
40
|
|
|
42
|
-
|
|
43
41
|
before { subject.validate(params) }
|
|
44
42
|
|
|
45
43
|
it { subject.name.must_equal "Best Of The Police" }
|
|
@@ -48,17 +46,15 @@ class AsTest < BaseTest
|
|
|
48
46
|
it { subject.tracks[1].name.must_equal "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
55
|
it { song2.title.must_equal "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.must_equal({"title"=>"Best Of The Police", "hit"=>{"title"=>"So Lonely"}, "songs"=>[{"title"=>"Message In A Bottle"}, {"title"=>"Roxanne"}], "band"=> nil})
|
|
68
|
+
hash.must_equal({"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
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
require "test_helper"
|
|
2
|
+
require "representable/json"
|
|
3
|
+
|
|
4
|
+
class InheritTest < BaseTest
|
|
5
|
+
Populator = Reform::Form::Populator
|
|
6
|
+
|
|
7
|
+
class SkipParse
|
|
8
|
+
include Uber::Callable
|
|
9
|
+
def call(*_args)
|
|
10
|
+
false
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class AlbumForm < TestForm
|
|
15
|
+
property :title, deserializer: {instance: "Instance"}, skip_if: "skip_if in AlbumForm" # allow direct configuration of :deserializer.
|
|
16
|
+
|
|
17
|
+
property :hit, populate_if_empty: ->(*) { Song.new } do
|
|
18
|
+
property :title
|
|
19
|
+
validation do
|
|
20
|
+
params { required(:title).filled }
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
collection :songs, populate_if_empty: -> {}, skip_if: :all_blank do
|
|
25
|
+
property :title
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
property :band, populate_if_empty: -> {} do
|
|
29
|
+
def band_id
|
|
30
|
+
1
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class CompilationForm < AlbumForm
|
|
36
|
+
property :title, inherit: true, skip_if: "skip_if from CompilationForm"
|
|
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
|
|
43
|
+
|
|
44
|
+
# NO collection here, this is entirely inherited.
|
|
45
|
+
|
|
46
|
+
property :band, inherit: true do # inherit everything, but explicitely.
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
let(:album) { Album.new(nil, Song.new, [], Band.new) }
|
|
51
|
+
subject { CompilationForm.new(album) }
|
|
52
|
+
|
|
53
|
+
it do
|
|
54
|
+
subject.validate("hit" => {"title" => "LA Drone", "rating" => 10})
|
|
55
|
+
subject.hit.title.must_equal "LA Drone"
|
|
56
|
+
subject.hit.rating.must_equal 10
|
|
57
|
+
subject.errors.messages.must_equal({})
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it do
|
|
61
|
+
subject.validate({})
|
|
62
|
+
assert_nil subject.model.hit.title
|
|
63
|
+
assert_nil subject.model.hit.rating
|
|
64
|
+
subject.errors.messages.must_equal("hit.title": ["must be filled"], "hit.rating": ["must be filled"])
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "xxx" do
|
|
68
|
+
# sub hashes like :deserializer must be properly cloned when inheriting.
|
|
69
|
+
AlbumForm.options_for(:title)[:deserializer].object_id.wont_equal CompilationForm.options_for(:title)[:deserializer].object_id
|
|
70
|
+
|
|
71
|
+
# don't overwrite direct deserializer: {} configuration.
|
|
72
|
+
AlbumForm.options_for(:title)[:internal_populator].must_be_instance_of Reform::Form::Populator::Sync
|
|
73
|
+
AlbumForm.options_for(:title)[:deserializer][:skip_parse].must_equal "skip_if in AlbumForm"
|
|
74
|
+
|
|
75
|
+
# AlbumForm.options_for(:hit)[:internal_populator].inspect.must_match /Reform::Form::Populator:.+ @user_proc="Populator"/
|
|
76
|
+
# AlbumForm.options_for(:hit)[:deserializer][:instance].inspect.must_be_instance_with Reform::Form::Populator, user_proc: "Populator"
|
|
77
|
+
|
|
78
|
+
AlbumForm.options_for(:songs)[:internal_populator].must_be_instance_of Reform::Form::Populator::IfEmpty
|
|
79
|
+
AlbumForm.options_for(:songs)[:deserializer][:skip_parse].must_be_instance_of Reform::Form::Validate::Skip::AllBlank
|
|
80
|
+
|
|
81
|
+
AlbumForm.options_for(:band)[:internal_populator].must_be_instance_of Reform::Form::Populator::IfEmpty
|
|
82
|
+
|
|
83
|
+
CompilationForm.options_for(:title)[:deserializer][:skip_parse].must_equal "skip_if from CompilationForm"
|
|
84
|
+
# pp CompilationForm.options_for(:songs)
|
|
85
|
+
CompilationForm.options_for(:songs)[:internal_populator].must_be_instance_of Reform::Form::Populator::IfEmpty
|
|
86
|
+
|
|
87
|
+
CompilationForm.options_for(:band)[:internal_populator].must_be_instance_of Reform::Form::Populator::IfEmpty
|
|
88
|
+
|
|
89
|
+
# completely overwrite inherited.
|
|
90
|
+
CompilationForm.options_for(:hit)[:deserializer][:skip_parse].must_be_instance_of SkipParse
|
|
91
|
+
|
|
92
|
+
# inherit: true with block will still inherit the original class.
|
|
93
|
+
AlbumForm.new(OpenStruct.new(band: OpenStruct.new)).band.band_id.must_equal 1
|
|
94
|
+
CompilationForm.new(OpenStruct.new(band: OpenStruct.new)).band.band_id.must_equal 1
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
class CDForm < AlbumForm
|
|
98
|
+
# override :band's original populate_if_empty but with :inherit.
|
|
99
|
+
property :band, inherit: true, populator: "CD Populator" do
|
|
100
|
+
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it { CDForm.options_for(:band)[:internal_populator].instance_variable_get(:@user_proc).must_equal "CD Populator" }
|
|
105
|
+
end
|
|
@@ -1,12 +1,12 @@
|
|
|
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
7
|
class SkipParse
|
|
8
8
|
include Uber::Callable
|
|
9
|
-
def call(*
|
|
9
|
+
def call(*_args)
|
|
10
10
|
false
|
|
11
11
|
end
|
|
12
12
|
end
|
|
@@ -14,19 +14,18 @@ class InheritTest < BaseTest
|
|
|
14
14
|
class AlbumForm < TestForm
|
|
15
15
|
property :title, deserializer: {instance: "Instance"}, skip_if: "skip_if in AlbumForm" # allow direct configuration of :deserializer.
|
|
16
16
|
|
|
17
|
-
property :hit, populate_if_empty: ->
|
|
17
|
+
property :hit, populate_if_empty: ->(*) { Song.new } do
|
|
18
18
|
property :title
|
|
19
19
|
validation do
|
|
20
20
|
required(:title).filled
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
collection :songs, populate_if_empty:
|
|
24
|
+
collection :songs, populate_if_empty: -> {}, skip_if: :all_blank do
|
|
25
25
|
property :title
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
property :band, populate_if_empty:
|
|
29
|
-
|
|
28
|
+
property :band, populate_if_empty: -> {} do
|
|
30
29
|
def band_id
|
|
31
30
|
1
|
|
32
31
|
end
|
|
@@ -35,7 +34,7 @@ class InheritTest < BaseTest
|
|
|
35
34
|
|
|
36
35
|
class CompilationForm < AlbumForm
|
|
37
36
|
property :title, inherit: true, skip_if: "skip_if from CompilationForm"
|
|
38
|
-
property :hit, :
|
|
37
|
+
property :hit, inherit: true, populate_if_empty: ->(*) { Song.new }, skip_if: SkipParse.new do
|
|
39
38
|
property :rating
|
|
40
39
|
validation do
|
|
41
40
|
required(:rating).filled
|
|
@@ -48,11 +47,11 @@ class InheritTest < BaseTest
|
|
|
48
47
|
end
|
|
49
48
|
end
|
|
50
49
|
|
|
51
|
-
let
|
|
50
|
+
let(:album) { Album.new(nil, Song.new, [], Band.new) }
|
|
52
51
|
subject { CompilationForm.new(album) }
|
|
53
52
|
|
|
54
53
|
it do
|
|
55
|
-
subject.validate(
|
|
54
|
+
subject.validate("hit" => {"title" => "LA Drone", "rating" => 10})
|
|
56
55
|
subject.hit.title.must_equal "LA Drone"
|
|
57
56
|
subject.hit.rating.must_equal 10
|
|
58
57
|
subject.errors.messages.must_equal({})
|
|
@@ -62,7 +61,7 @@ class InheritTest < BaseTest
|
|
|
62
61
|
subject.validate({})
|
|
63
62
|
assert_nil subject.model.hit.title
|
|
64
63
|
assert_nil subject.model.hit.rating
|
|
65
|
-
subject.errors.messages.must_equal(
|
|
64
|
+
subject.errors.messages.must_equal("hit.title": ["must be filled"], "hit.rating": ["must be filled"])
|
|
66
65
|
end
|
|
67
66
|
|
|
68
67
|
it "xxx" do
|
|
@@ -76,31 +75,25 @@ class InheritTest < BaseTest
|
|
|
76
75
|
# AlbumForm.options_for(:hit)[:internal_populator].inspect.must_match /Reform::Form::Populator:.+ @user_proc="Populator"/
|
|
77
76
|
# AlbumForm.options_for(:hit)[:deserializer][:instance].inspect.must_be_instance_with Reform::Form::Populator, user_proc: "Populator"
|
|
78
77
|
|
|
79
|
-
|
|
80
78
|
AlbumForm.options_for(:songs)[:internal_populator].must_be_instance_of Reform::Form::Populator::IfEmpty
|
|
81
79
|
AlbumForm.options_for(:songs)[:deserializer][:skip_parse].must_be_instance_of Reform::Form::Validate::Skip::AllBlank
|
|
82
80
|
|
|
83
81
|
AlbumForm.options_for(:band)[:internal_populator].must_be_instance_of Reform::Form::Populator::IfEmpty
|
|
84
82
|
|
|
85
|
-
|
|
86
|
-
|
|
87
83
|
CompilationForm.options_for(:title)[:deserializer][:skip_parse].must_equal "skip_if from CompilationForm"
|
|
88
84
|
# pp CompilationForm.options_for(:songs)
|
|
89
85
|
CompilationForm.options_for(:songs)[:internal_populator].must_be_instance_of Reform::Form::Populator::IfEmpty
|
|
90
86
|
|
|
91
|
-
|
|
92
87
|
CompilationForm.options_for(:band)[:internal_populator].must_be_instance_of Reform::Form::Populator::IfEmpty
|
|
93
88
|
|
|
94
89
|
# completely overwrite inherited.
|
|
95
90
|
CompilationForm.options_for(:hit)[:deserializer][:skip_parse].must_be_instance_of SkipParse
|
|
96
91
|
|
|
97
|
-
|
|
98
92
|
# inherit: true with block will still inherit the original class.
|
|
99
93
|
AlbumForm.new(OpenStruct.new(band: OpenStruct.new)).band.band_id.must_equal 1
|
|
100
94
|
CompilationForm.new(OpenStruct.new(band: OpenStruct.new)).band.band_id.must_equal 1
|
|
101
95
|
end
|
|
102
96
|
|
|
103
|
-
|
|
104
97
|
class CDForm < AlbumForm
|
|
105
98
|
# override :band's original populate_if_empty but with :inherit.
|
|
106
99
|
property :band, inherit: true, populator: "CD Populator" do
|
|
@@ -0,0 +1,137 @@
|
|
|
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 :band do
|
|
9
|
+
property :title
|
|
10
|
+
|
|
11
|
+
validation do
|
|
12
|
+
params { required(:title).filled }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def id # gets mixed into Form, too.
|
|
16
|
+
2
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def id # gets mixed into Form, too.
|
|
21
|
+
1
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
validation do
|
|
25
|
+
params { required(:band).filled }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
include Dry::Types.module # allows using Types::* in module.
|
|
29
|
+
property :cool, type: DRY_TYPES_CONSTANT::Bool # test coercion.
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# TODO: test if works, move stuff into inherit_schema!
|
|
33
|
+
module AirplaysPropertyForm
|
|
34
|
+
include Reform::Form::Module
|
|
35
|
+
|
|
36
|
+
collection :airplays do
|
|
37
|
+
property :station
|
|
38
|
+
validation do
|
|
39
|
+
params { required(:station).filled }
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
validation do
|
|
43
|
+
params { required(:airplays).filled }
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# test:
|
|
48
|
+
# by including BandPropertyForm into multiple classes we assure that options hashes don't get messed up by AM:V.
|
|
49
|
+
class HitForm < TestForm
|
|
50
|
+
include BandPropertyForm
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class SongForm < TestForm
|
|
54
|
+
include Coercion
|
|
55
|
+
property :title
|
|
56
|
+
|
|
57
|
+
include BandPropertyForm
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
let(:song) { OpenStruct.new(band: OpenStruct.new(title: "Time Again")) }
|
|
61
|
+
|
|
62
|
+
# nested form from module is present and creates accessor.
|
|
63
|
+
it { SongForm.new(song).band.title.must_equal "Time Again" }
|
|
64
|
+
|
|
65
|
+
# methods from module get included.
|
|
66
|
+
it { SongForm.new(song).id.must_equal 1 }
|
|
67
|
+
it { SongForm.new(song).band.id.must_equal 2 }
|
|
68
|
+
|
|
69
|
+
# validators get inherited.
|
|
70
|
+
it do
|
|
71
|
+
form = SongForm.new(OpenStruct.new)
|
|
72
|
+
form.validate({})
|
|
73
|
+
form.errors.messages.must_equal(band: ["must be filled"])
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# coercion works
|
|
77
|
+
it do
|
|
78
|
+
form = SongForm.new(OpenStruct.new)
|
|
79
|
+
form.validate(cool: "1")
|
|
80
|
+
form.cool.must_equal true
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# include a module into a module into a class :)
|
|
84
|
+
module AlbumFormModule
|
|
85
|
+
include Reform::Form::Module
|
|
86
|
+
include BandPropertyForm
|
|
87
|
+
|
|
88
|
+
property :name
|
|
89
|
+
validation do
|
|
90
|
+
params { required(:name).filled }
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
class AlbumForm < TestForm
|
|
95
|
+
include AlbumFormModule
|
|
96
|
+
|
|
97
|
+
# pp heritage
|
|
98
|
+
property :band, inherit: true do
|
|
99
|
+
property :label
|
|
100
|
+
validation do
|
|
101
|
+
params { required(:label).filled }
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it do
|
|
107
|
+
form = AlbumForm.new(OpenStruct.new(band: OpenStruct.new))
|
|
108
|
+
form.validate("band" => {})
|
|
109
|
+
form.errors.messages.must_equal("band.title": ["must be filled"], "band.label": ["must be filled"], name: ["must be filled"])
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
describe "module with custom accessors" do
|
|
113
|
+
module SongModule
|
|
114
|
+
include Reform::Form::Module
|
|
115
|
+
|
|
116
|
+
property :id # no custom accessor for id.
|
|
117
|
+
property :title # has custom accessor.
|
|
118
|
+
|
|
119
|
+
module InstanceMethods
|
|
120
|
+
def title
|
|
121
|
+
super.upcase
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
class IncludingSongForm < TestForm
|
|
127
|
+
include SongModule
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
let(:song) { OpenStruct.new(id: 1, title: "Instant Mash") }
|
|
131
|
+
|
|
132
|
+
it do
|
|
133
|
+
IncludingSongForm.new(song).id.must_equal 1
|
|
134
|
+
IncludingSongForm.new(song).title.must_equal "INSTANT MASH"
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
require "test_helper"
|
|
2
|
-
require
|
|
2
|
+
require "reform/form/coercion"
|
|
3
3
|
|
|
4
4
|
class ModuleInclusionTest < MiniTest::Spec
|
|
5
5
|
module BandPropertyForm
|
|
6
6
|
include Reform::Form::Module
|
|
7
7
|
|
|
8
|
+
property :artist
|
|
8
9
|
property :band do
|
|
9
10
|
property :title
|
|
10
11
|
|
|
@@ -26,7 +27,14 @@ class ModuleInclusionTest < MiniTest::Spec
|
|
|
26
27
|
end
|
|
27
28
|
|
|
28
29
|
include Dry::Types.module # allows using Types::* in module.
|
|
29
|
-
property :cool, type:
|
|
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
|
|
30
38
|
end
|
|
31
39
|
|
|
32
40
|
# TODO: test if works, move stuff into inherit_schema!
|
|
@@ -44,7 +52,6 @@ class ModuleInclusionTest < MiniTest::Spec
|
|
|
44
52
|
end
|
|
45
53
|
end
|
|
46
54
|
|
|
47
|
-
|
|
48
55
|
# test:
|
|
49
56
|
# by including BandPropertyForm into multiple classes we assure that options hashes don't get messed up by AM:V.
|
|
50
57
|
class HitForm < TestForm
|
|
@@ -58,11 +65,11 @@ class ModuleInclusionTest < MiniTest::Spec
|
|
|
58
65
|
include BandPropertyForm
|
|
59
66
|
end
|
|
60
67
|
|
|
61
|
-
|
|
62
|
-
let (:song) { OpenStruct.new(:band => OpenStruct.new(:title => "Time Again")) }
|
|
68
|
+
let(:song) { OpenStruct.new(band: OpenStruct.new(title: "Time Again"), artist: "Ketama") }
|
|
63
69
|
|
|
64
70
|
# nested form from module is present and creates accessor.
|
|
65
71
|
it { SongForm.new(song).band.title.must_equal "Time Again" }
|
|
72
|
+
it { SongForm.new(song).artist.must_equal "Ketama" }
|
|
66
73
|
|
|
67
74
|
# methods from module get included.
|
|
68
75
|
it { SongForm.new(song).id.must_equal 1 }
|
|
@@ -71,8 +78,8 @@ class ModuleInclusionTest < MiniTest::Spec
|
|
|
71
78
|
# validators get inherited.
|
|
72
79
|
it do
|
|
73
80
|
form = SongForm.new(OpenStruct.new)
|
|
74
|
-
form.validate(
|
|
75
|
-
form.errors.messages.must_equal(
|
|
81
|
+
form.validate(artist: nil)
|
|
82
|
+
form.errors.messages.must_equal(artist: ["this needs to be filled"], band: ["must be filled"])
|
|
76
83
|
end
|
|
77
84
|
|
|
78
85
|
# coercion works
|
|
@@ -82,7 +89,6 @@ class ModuleInclusionTest < MiniTest::Spec
|
|
|
82
89
|
form.cool.must_equal true
|
|
83
90
|
end
|
|
84
91
|
|
|
85
|
-
|
|
86
92
|
# include a module into a module into a class :)
|
|
87
93
|
module AlbumFormModule
|
|
88
94
|
include Reform::Form::Module
|
|
@@ -98,7 +104,7 @@ class ModuleInclusionTest < MiniTest::Spec
|
|
|
98
104
|
include AlbumFormModule
|
|
99
105
|
|
|
100
106
|
# pp heritage
|
|
101
|
-
property :band, :
|
|
107
|
+
property :band, inherit: true do
|
|
102
108
|
property :label
|
|
103
109
|
validation do
|
|
104
110
|
required(:label).filled
|
|
@@ -107,12 +113,11 @@ class ModuleInclusionTest < MiniTest::Spec
|
|
|
107
113
|
end
|
|
108
114
|
|
|
109
115
|
it do
|
|
110
|
-
form = AlbumForm.new(OpenStruct.new(:
|
|
111
|
-
form.validate(
|
|
112
|
-
form.errors.messages.must_equal(
|
|
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"])
|
|
113
119
|
end
|
|
114
120
|
|
|
115
|
-
|
|
116
121
|
describe "module with custom accessors" do
|
|
117
122
|
module SongModule
|
|
118
123
|
include Reform::Form::Module
|
|
@@ -131,7 +136,7 @@ class ModuleInclusionTest < MiniTest::Spec
|
|
|
131
136
|
include SongModule
|
|
132
137
|
end
|
|
133
138
|
|
|
134
|
-
let
|
|
139
|
+
let(:song) { OpenStruct.new(id: 1, title: "Instant Mash") }
|
|
135
140
|
|
|
136
141
|
it do
|
|
137
142
|
IncludingSongForm.new(song).id.must_equal 1
|
|
@@ -139,4 +144,3 @@ class ModuleInclusionTest < MiniTest::Spec
|
|
|
139
144
|
end
|
|
140
145
|
end
|
|
141
146
|
end
|
|
142
|
-
|