reform 2.2.3 → 2.3.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/.gitignore +5 -1
- data/.travis.yml +11 -6
- data/Appraisals +8 -0
- data/CHANGES.md +56 -0
- data/CONTRIBUTING.md +31 -0
- data/Gemfile +2 -16
- data/ISSUE_TEMPLATE.md +25 -0
- data/LICENSE.txt +1 -1
- data/README.md +5 -7
- data/Rakefile +16 -9
- data/gemfiles/0.13.0.gemfile +8 -0
- data/gemfiles/1.5.0.gemfile +9 -0
- data/lib/reform.rb +1 -0
- data/lib/reform/contract.rb +7 -17
- data/lib/reform/contract/custom_error.rb +41 -0
- data/lib/reform/contract/validate.rb +53 -23
- data/lib/reform/errors.rb +61 -0
- data/lib/reform/form.rb +36 -10
- data/lib/reform/form/call.rb +1 -1
- data/lib/reform/form/composition.rb +2 -2
- data/lib/reform/form/dry.rb +10 -58
- data/lib/reform/form/dry/input_hash.rb +37 -0
- data/lib/reform/form/dry/new_api.rb +47 -0
- data/lib/reform/form/dry/old_api.rb +61 -0
- data/lib/reform/form/populator.rb +11 -29
- data/lib/reform/form/prepopulate.rb +5 -4
- data/lib/reform/form/validate.rb +28 -13
- data/lib/reform/result.rb +90 -0
- data/lib/reform/validation.rb +19 -11
- data/lib/reform/validation/groups.rb +12 -27
- data/lib/reform/version.rb +1 -1
- data/reform.gemspec +13 -13
- data/test/benchmarking.rb +39 -6
- data/test/call_new_api.rb +23 -0
- data/test/{call_test.rb → call_old_api.rb} +4 -4
- data/test/changed_test.rb +8 -8
- data/test/coercion_test.rb +51 -19
- data/test/composition_new_api.rb +186 -0
- data/test/{composition_test.rb → composition_old_api.rb} +66 -31
- 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} +13 -13
- data/test/default_test.rb +2 -2
- data/test/deserialize_test.rb +11 -14
- data/test/errors_new_api.rb +225 -0
- data/test/errors_old_api.rb +230 -0
- data/test/feature_test.rb +8 -10
- data/test/fixtures/dry_error_messages.yml +73 -23
- 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} +5 -5
- data/test/form_option_new_api.rb +24 -0
- data/test/{form_option_test.rb → form_option_old_api.rb} +4 -4
- data/test/from_test.rb +9 -13
- data/test/inherit_new_api.rb +105 -0
- data/test/inherit_old_api.rb +105 -0
- data/test/{module_test.rb → module_new_api.rb} +20 -25
- data/test/module_old_api.rb +146 -0
- data/test/parse_option_test.rb +40 -0
- data/test/parse_pipeline_test.rb +3 -3
- data/test/populate_new_api.rb +304 -0
- data/test/{populate_test.rb → populate_old_api.rb} +83 -49
- data/test/populator_skip_test.rb +9 -9
- data/test/prepopulator_test.rb +8 -9
- data/test/read_only_test.rb +12 -1
- data/test/readable_test.rb +7 -7
- data/test/reform_new_api.rb +204 -0
- data/test/{reform_test.rb → reform_old_api.rb} +30 -51
- data/test/save_new_api.rb +101 -0
- data/test/{save_test.rb → save_old_api.rb} +32 -20
- data/test/setup_test.rb +8 -8
- data/test/{skip_if_test.rb → skip_if_new_api.rb} +23 -12
- data/test/skip_if_old_api.rb +92 -0
- data/test/skip_setter_and_getter_test.rb +3 -4
- data/test/test_helper.rb +25 -14
- data/test/validate_new_api.rb +453 -0
- data/test/{validate_test.rb → validate_old_api.rb} +59 -69
- data/test/validation/dry_validation_new_api.rb +836 -0
- data/test/validation/dry_validation_old_api.rb +772 -0
- 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 +35 -6
- metadata +101 -72
- 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/errors_test.rb +0 -165
- data/test/inherit_test.rb +0 -119
- data/test/readonly_test.rb +0 -14
- data/test/validation/dry_test.rb +0 -60
- data/test/validation/dry_validation_test.rb +0 -352
- data/test/validation/errors.yml +0 -4
@@ -0,0 +1,57 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class FormTest < MiniTest::Spec
|
4
|
+
Artist = Struct.new(:name)
|
5
|
+
|
6
|
+
class AlbumForm < TestForm
|
7
|
+
property :title
|
8
|
+
|
9
|
+
property :hit do
|
10
|
+
property :title
|
11
|
+
end
|
12
|
+
|
13
|
+
collection :songs do
|
14
|
+
property :title
|
15
|
+
end
|
16
|
+
|
17
|
+
property :band do # yepp, people do crazy stuff like that.
|
18
|
+
property :label do
|
19
|
+
property :name
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "::dup" do
|
25
|
+
let(:cloned) { AlbumForm.clone }
|
26
|
+
|
27
|
+
# #dup is called in Op.inheritable_attr(:contract_class), it must be subclass of the original one.
|
28
|
+
it { cloned.wont_equal AlbumForm }
|
29
|
+
it { AlbumForm.definitions.wont_equal cloned.definitions }
|
30
|
+
|
31
|
+
it do
|
32
|
+
# currently, forms need a name for validation, even without AM.
|
33
|
+
cloned.singleton_class.class_eval do
|
34
|
+
def name
|
35
|
+
"Album"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
cloned.validation do
|
40
|
+
params { required(:title).filled }
|
41
|
+
end
|
42
|
+
|
43
|
+
cloned.new(OpenStruct.new).validate({})
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#initialize" do
|
48
|
+
class ArtistForm < TestForm
|
49
|
+
property :name
|
50
|
+
property :current_user, virtual: true
|
51
|
+
end
|
52
|
+
|
53
|
+
it "allows injecting :virtual options" do
|
54
|
+
ArtistForm.new(Artist.new, current_user: Object).current_user.must_equal Object
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -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,7 +22,7 @@ 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
28
|
it { cloned.wont_equal AlbumForm }
|
@@ -37,7 +37,7 @@ class FormTest < MiniTest::Spec
|
|
37
37
|
end
|
38
38
|
|
39
39
|
cloned.validation do
|
40
|
-
|
40
|
+
required(:title).filled
|
41
41
|
end
|
42
42
|
|
43
43
|
cloned.new(OpenStruct.new).validate({})
|
@@ -45,7 +45,7 @@ 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
|
@@ -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
|
@@ -1,17 +1,17 @@
|
|
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
|
+
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
|
|
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,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"}]})
|
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
|
@@ -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
|
+
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
|
+
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,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
28
|
include Dry::Types.module # allows using Types::* in module.
|
29
|
-
property :cool, type:
|
29
|
+
property :cool, type: DRY_TYPES_CONSTANT::Bool # test coercion.
|
30
30
|
end
|
31
31
|
|
32
32
|
# TODO: test if works, move stuff into inherit_schema!
|
@@ -36,30 +36,28 @@ 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
63
|
it { SongForm.new(song).band.title.must_equal "Time Again" }
|
@@ -72,17 +70,16 @@ class ModuleInclusionTest < MiniTest::Spec
|
|
72
70
|
it do
|
73
71
|
form = SongForm.new(OpenStruct.new)
|
74
72
|
form.validate({})
|
75
|
-
form.errors.messages.must_equal(
|
73
|
+
form.errors.messages.must_equal(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(
|
79
|
+
form.validate(cool: "1")
|
82
80
|
form.cool.must_equal true
|
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.must_equal(
|
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"])
|
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,11 +123,11 @@ 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
133
|
IncludingSongForm.new(song).id.must_equal 1
|
@@ -139,4 +135,3 @@ class ModuleInclusionTest < MiniTest::Spec
|
|
139
135
|
end
|
140
136
|
end
|
141
137
|
end
|
142
|
-
|