reform 2.2.4 → 2.3.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 +5 -5
- data/.gitignore +5 -1
- data/.rubocop.yml +30 -0
- data/.rubocop_todo.yml +460 -0
- data/.travis.yml +11 -6
- data/Appraisals +8 -0
- data/CHANGES.md +54 -4
- 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 +18 -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 +46 -0
- data/lib/reform/form/dry/old_api.rb +61 -0
- data/lib/reform/form/populator.rb +11 -27
- data/lib/reform/form/prepopulate.rb +4 -3
- 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 +15 -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 +408 -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 +127 -56
- 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
@@ -1,34 +1,33 @@
|
|
1
|
-
require
|
1
|
+
require "test_helper"
|
2
2
|
|
3
|
-
# TODO: this test should be removed.
|
4
3
|
class ReformTest < Minitest::Spec
|
5
|
-
let
|
4
|
+
let(:comp) { OpenStruct.new(name: "Duran Duran", title: "Rio") }
|
6
5
|
|
7
|
-
let
|
6
|
+
let(:form) { SongForm.new(comp) }
|
8
7
|
|
9
|
-
class SongForm <
|
8
|
+
class SongForm < TestForm
|
10
9
|
property :name
|
11
10
|
property :title
|
12
11
|
|
13
12
|
validation do
|
14
|
-
|
13
|
+
required(:name).filled
|
15
14
|
end
|
16
15
|
end
|
17
16
|
|
18
17
|
describe "(new) form with empty models" do
|
19
|
-
let
|
18
|
+
let(:comp) { OpenStruct.new }
|
20
19
|
|
21
20
|
it "returns empty fields" do
|
22
|
-
form.title
|
23
|
-
form.name.
|
21
|
+
assert_nil form.title
|
22
|
+
form.name.must_be_nil
|
24
23
|
end
|
25
24
|
|
26
25
|
describe "and submitted values" do
|
27
26
|
it "returns filled-out fields" do
|
28
27
|
form.validate("name" => "Duran Duran")
|
29
28
|
|
30
|
-
form.title
|
31
|
-
form.name.must_equal
|
29
|
+
assert_nil form.title
|
30
|
+
form.name.must_equal "Duran Duran"
|
32
31
|
end
|
33
32
|
end
|
34
33
|
end
|
@@ -41,7 +40,7 @@ class ReformTest < Minitest::Spec
|
|
41
40
|
end
|
42
41
|
|
43
42
|
describe "#validate" do
|
44
|
-
let
|
43
|
+
let(:comp) { OpenStruct.new }
|
45
44
|
|
46
45
|
it "ignores unmapped fields in input" do
|
47
46
|
form.validate("name" => "Duran Duran", :genre => "80s")
|
@@ -63,21 +62,21 @@ class ReformTest < Minitest::Spec
|
|
63
62
|
it "doesn't change model properties" do
|
64
63
|
form.validate("name" => "Duran Duran")
|
65
64
|
|
66
|
-
comp.name
|
65
|
+
assert_nil comp.name # don't touch model, yet.
|
67
66
|
end
|
68
67
|
|
69
68
|
# TODO: test errors. test valid.
|
70
69
|
describe "invalid input" do
|
71
|
-
class ValidatingForm <
|
70
|
+
class ValidatingForm < TestForm
|
72
71
|
property :name
|
73
72
|
property :title
|
74
73
|
|
75
74
|
validation do
|
76
|
-
|
77
|
-
|
75
|
+
required(:name).filled
|
76
|
+
required(:title).filled
|
78
77
|
end
|
79
78
|
end
|
80
|
-
let
|
79
|
+
let(:form) { ValidatingForm.new(comp) }
|
81
80
|
|
82
81
|
it "returns false when invalid" do
|
83
82
|
form.validate({}).must_equal false
|
@@ -85,29 +84,14 @@ class ReformTest < Minitest::Spec
|
|
85
84
|
|
86
85
|
it "populates errors" do
|
87
86
|
form.validate({})
|
88
|
-
form.errors.messages.must_equal({:
|
87
|
+
form.errors.messages.must_equal({name: ["must be filled"], title: ["must be filled"]})
|
89
88
|
end
|
90
89
|
end
|
91
90
|
end
|
92
91
|
|
93
|
-
# FIXME: add this test to reform-rails.
|
94
|
-
describe "#errors" do
|
95
|
-
before { form.validate({})}
|
96
|
-
|
97
|
-
it { form.errors.must_be_kind_of Reform::Contract::Errors }
|
98
|
-
|
99
|
-
it { form.errors.messages.must_equal({}) }
|
100
|
-
|
101
|
-
it do
|
102
|
-
form.validate({"name"=>""})
|
103
|
-
form.errors.messages.must_equal({:name=>["must be filled"]})
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
|
108
92
|
describe "#save" do
|
109
|
-
let
|
110
|
-
let
|
93
|
+
let(:comp) { OpenStruct.new }
|
94
|
+
let(:form) { SongForm.new(comp) }
|
111
95
|
|
112
96
|
before { form.validate("name" => "Diesel Boy") }
|
113
97
|
|
@@ -115,7 +99,7 @@ class ReformTest < Minitest::Spec
|
|
115
99
|
form.save
|
116
100
|
|
117
101
|
comp.name.must_equal "Diesel Boy"
|
118
|
-
comp.title
|
102
|
+
assert_nil comp.title
|
119
103
|
end
|
120
104
|
|
121
105
|
describe "#save with block" do
|
@@ -126,42 +110,39 @@ class ReformTest < Minitest::Spec
|
|
126
110
|
hash = map
|
127
111
|
end
|
128
112
|
|
129
|
-
hash.must_equal({"name"=>"Diesel Boy"})
|
113
|
+
hash.must_equal({"name" => "Diesel Boy", "title" => nil})
|
130
114
|
end
|
131
115
|
end
|
132
116
|
end
|
133
117
|
|
134
|
-
|
135
118
|
describe "#model" do
|
136
119
|
it { form.model.must_equal comp }
|
137
120
|
end
|
138
121
|
|
139
|
-
|
140
122
|
describe "inheritance" do
|
141
123
|
class HitForm < SongForm
|
142
124
|
property :position
|
143
125
|
validation do
|
144
|
-
|
126
|
+
required(:position).filled
|
145
127
|
end
|
146
128
|
end
|
147
129
|
|
148
|
-
let
|
130
|
+
let(:form) { HitForm.new(OpenStruct.new()) }
|
149
131
|
it do
|
150
132
|
form.validate({"title" => "The Body"})
|
151
133
|
form.title.must_equal "The Body"
|
152
|
-
form.position
|
153
|
-
form.errors.messages.must_equal({:
|
134
|
+
assert_nil form.position
|
135
|
+
form.errors.messages.must_equal({name: ["must be filled"], position: ["must be filled"]})
|
154
136
|
end
|
155
137
|
end
|
156
138
|
end
|
157
139
|
|
158
|
-
|
159
140
|
class OverridingAccessorsTest < BaseTest
|
160
|
-
class SongForm <
|
141
|
+
class SongForm < TestForm
|
161
142
|
property :title
|
162
143
|
|
163
144
|
def title=(v) # used in #validate.
|
164
|
-
super v*2
|
145
|
+
super v * 2
|
165
146
|
end
|
166
147
|
|
167
148
|
def title # used in #sync.
|
@@ -169,13 +150,12 @@ class OverridingAccessorsTest < BaseTest
|
|
169
150
|
end
|
170
151
|
end
|
171
152
|
|
172
|
-
let
|
153
|
+
let(:song) { Song.new("Pray") }
|
173
154
|
subject { SongForm.new(song) }
|
174
155
|
|
175
156
|
# override reader for presentation.
|
176
157
|
it { subject.title.must_equal "pray" }
|
177
158
|
|
178
|
-
|
179
159
|
describe "#save" do
|
180
160
|
before { subject.validate("title" => "Hey Little World") }
|
181
161
|
|
@@ -198,9 +178,8 @@ class OverridingAccessorsTest < BaseTest
|
|
198
178
|
end
|
199
179
|
end
|
200
180
|
|
201
|
-
|
202
181
|
class MethodInFormTest < MiniTest::Spec
|
203
|
-
class AlbumForm <
|
182
|
+
class AlbumForm < TestForm
|
204
183
|
property :title
|
205
184
|
|
206
185
|
def title
|
@@ -217,7 +196,7 @@ class MethodInFormTest < MiniTest::Spec
|
|
217
196
|
end
|
218
197
|
|
219
198
|
# methods can be used instead of created accessors.
|
220
|
-
subject { AlbumForm.new(OpenStruct.new(:
|
199
|
+
subject { AlbumForm.new(OpenStruct.new(hit: OpenStruct.new)) }
|
221
200
|
it { subject.title.must_equal "The Suffer And The Witness" }
|
222
201
|
it { subject.hit.title.must_equal "Drones" }
|
223
202
|
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class SaveTest < BaseTest
|
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
|
10
|
+
validation do
|
11
|
+
params { required(:name).filled }
|
12
|
+
end
|
13
|
+
|
14
|
+
collection :songs do
|
15
|
+
property :title
|
16
|
+
validation do
|
17
|
+
params { required(:title).filled }
|
18
|
+
end
|
19
|
+
|
20
|
+
property :composer do
|
21
|
+
property :name
|
22
|
+
validation do
|
23
|
+
params { required(:name).filled }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
property :artist, save: false do
|
29
|
+
property :name
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module Saveable
|
34
|
+
def save
|
35
|
+
@saved = true
|
36
|
+
end
|
37
|
+
|
38
|
+
def saved?
|
39
|
+
defined?(@saved) && @saved
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
let(:song) { Song.new("Broken").extend(Saveable) }
|
44
|
+
# let(:song_with_composer) { Song.new("Resist Stance", nil, composer).extend(Saveable) }
|
45
|
+
let(:composer) { Artist.new("Greg Graffin").extend(Saveable) }
|
46
|
+
let(:artist) { Artist.new("Bad Religion").extend(Saveable).extend(Saveable) }
|
47
|
+
let(:album) { Album.new("The Dissent Of Man", [song], artist).extend(Saveable) }
|
48
|
+
|
49
|
+
let(:form) { AlbumForm.new(album) }
|
50
|
+
|
51
|
+
it do
|
52
|
+
form.validate("songs" => [{"title" => "Fixed"}])
|
53
|
+
|
54
|
+
form.save
|
55
|
+
|
56
|
+
album.saved?.must_equal true
|
57
|
+
album.songs[0].title.must_equal "Fixed"
|
58
|
+
album.songs[0].saved?.must_equal true
|
59
|
+
assert_nil album.artist.saved?
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#sync with block" do
|
63
|
+
it do
|
64
|
+
form = AlbumForm.new(Album.new("Greatest Hits"))
|
65
|
+
|
66
|
+
form.validate(name: nil) # nil-out the title.
|
67
|
+
|
68
|
+
nested_hash = nil
|
69
|
+
form.sync do |hash|
|
70
|
+
nested_hash = hash
|
71
|
+
end
|
72
|
+
|
73
|
+
nested_hash.must_equal({"name" => nil, "artist" => nil})
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# class SaveWithDynamicOptionsTest < MiniTest::Spec
|
79
|
+
# Song = Struct.new(:id, :title, :length) do
|
80
|
+
# include Saveable
|
81
|
+
# end
|
82
|
+
|
83
|
+
# class SongForm < TestForm
|
84
|
+
# property :title#, save: false
|
85
|
+
# property :length, virtual: true
|
86
|
+
# end
|
87
|
+
|
88
|
+
# let(:song) { Song.new }
|
89
|
+
# let(:form) { SongForm.new(song) }
|
90
|
+
|
91
|
+
# # we have access to original input value and outside parameters.
|
92
|
+
# it "xxx" do
|
93
|
+
# form.validate("title" => "A Poor Man's Memory", "length" => 10)
|
94
|
+
# length_seconds = 120
|
95
|
+
# form.save(length: lambda { |value, options| form.model.id = "#{value}: #{length_seconds}" })
|
96
|
+
|
97
|
+
# song.title.must_equal "A Poor Man's Memory"
|
98
|
+
# assert_nil song.length
|
99
|
+
# song.id.must_equal "10: 120"
|
100
|
+
# end
|
101
|
+
# end
|
@@ -1,26 +1,26 @@
|
|
1
|
-
require
|
1
|
+
require "test_helper"
|
2
2
|
|
3
3
|
class SaveTest < BaseTest
|
4
4
|
Song = Struct.new(:title, :album, :composer)
|
5
5
|
Album = Struct.new(:name, :songs, :artist)
|
6
6
|
Artist = Struct.new(:name)
|
7
7
|
|
8
|
-
class AlbumForm <
|
8
|
+
class AlbumForm < TestForm
|
9
9
|
property :name
|
10
10
|
validation do
|
11
|
-
|
11
|
+
required(:name).filled
|
12
12
|
end
|
13
13
|
|
14
14
|
collection :songs do
|
15
15
|
property :title
|
16
16
|
validation do
|
17
|
-
|
17
|
+
required(:title).filled
|
18
18
|
end
|
19
19
|
|
20
20
|
property :composer do
|
21
21
|
property :name
|
22
22
|
validation do
|
23
|
-
|
23
|
+
required(:name).filled
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
@@ -36,19 +36,17 @@ class SaveTest < BaseTest
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def saved?
|
39
|
-
@saved
|
39
|
+
defined?(@saved) && @saved
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
+
let(:song) { Song.new("Broken").extend(Saveable) }
|
44
|
+
# let(:song_with_composer) { Song.new("Resist Stance", nil, composer).extend(Saveable) }
|
45
|
+
let(:composer) { Artist.new("Greg Graffin").extend(Saveable) }
|
46
|
+
let(:artist) { Artist.new("Bad Religion").extend(Saveable).extend(Saveable) }
|
47
|
+
let(:album) { Album.new("The Dissent Of Man", [song], artist).extend(Saveable) }
|
43
48
|
|
44
|
-
let
|
45
|
-
# let (:song_with_composer) { Song.new("Resist Stance", nil, composer).extend(Saveable) }
|
46
|
-
let (:composer) { Artist.new("Greg Graffin").extend(Saveable) }
|
47
|
-
let (:artist) { Artist.new("Bad Religion").extend(Saveable).extend(Saveable) }
|
48
|
-
let (:album) { Album.new("The Dissent Of Man", [song], artist).extend(Saveable) }
|
49
|
-
|
50
|
-
let (:form) { AlbumForm.new(album) }
|
51
|
-
|
49
|
+
let(:form) { AlbumForm.new(album) }
|
52
50
|
|
53
51
|
it do
|
54
52
|
form.validate("songs" => [{"title" => "Fixed"}])
|
@@ -58,23 +56,37 @@ class SaveTest < BaseTest
|
|
58
56
|
album.saved?.must_equal true
|
59
57
|
album.songs[0].title.must_equal "Fixed"
|
60
58
|
album.songs[0].saved?.must_equal true
|
61
|
-
album.artist.saved
|
59
|
+
assert_nil album.artist.saved?
|
62
60
|
end
|
63
|
-
end
|
64
61
|
|
62
|
+
describe "#sync with block" do
|
63
|
+
it do
|
64
|
+
form = AlbumForm.new(Album.new("Greatest Hits"))
|
65
|
+
|
66
|
+
form.validate(name: nil) # nil-out the title.
|
67
|
+
|
68
|
+
nested_hash = nil
|
69
|
+
form.sync do |hash|
|
70
|
+
nested_hash = hash
|
71
|
+
end
|
72
|
+
|
73
|
+
nested_hash.must_equal({"name" => nil, "artist" => nil})
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
65
77
|
|
66
78
|
# class SaveWithDynamicOptionsTest < MiniTest::Spec
|
67
79
|
# Song = Struct.new(:id, :title, :length) do
|
68
80
|
# include Saveable
|
69
81
|
# end
|
70
82
|
|
71
|
-
# class SongForm <
|
83
|
+
# class SongForm < TestForm
|
72
84
|
# property :title#, save: false
|
73
85
|
# property :length, virtual: true
|
74
86
|
# end
|
75
87
|
|
76
|
-
# let
|
77
|
-
# let
|
88
|
+
# let(:song) { Song.new }
|
89
|
+
# let(:form) { SongForm.new(song) }
|
78
90
|
|
79
91
|
# # we have access to original input value and outside parameters.
|
80
92
|
# it "xxx" do
|
@@ -83,7 +95,7 @@ end
|
|
83
95
|
# form.save(length: lambda { |value, options| form.model.id = "#{value}: #{length_seconds}" })
|
84
96
|
|
85
97
|
# song.title.must_equal "A Poor Man's Memory"
|
86
|
-
# song.length
|
98
|
+
# assert_nil song.length
|
87
99
|
# song.id.must_equal "10: 120"
|
88
100
|
# end
|
89
101
|
# end
|
data/test/setup_test.rb
CHANGED
@@ -5,7 +5,7 @@ class SetupTest < MiniTest::Spec
|
|
5
5
|
Album = Struct.new(:name, :songs, :artist)
|
6
6
|
Artist = Struct.new(:name)
|
7
7
|
|
8
|
-
class AlbumForm <
|
8
|
+
class AlbumForm < TestForm
|
9
9
|
property :name
|
10
10
|
collection :songs do
|
11
11
|
property :title
|
@@ -20,20 +20,20 @@ class SetupTest < MiniTest::Spec
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
let
|
24
|
-
let
|
25
|
-
let
|
26
|
-
let
|
23
|
+
let(:song) { Song.new("Broken") }
|
24
|
+
let(:song_with_composer) { Song.new("Resist Stance", nil, composer) }
|
25
|
+
let(:composer) { Artist.new("Greg Graffin") }
|
26
|
+
let(:artist) { Artist.new("Bad Religion") }
|
27
27
|
|
28
28
|
describe "with nested objects" do
|
29
|
-
let
|
29
|
+
let(:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
|
30
30
|
|
31
31
|
it do
|
32
32
|
form = AlbumForm.new(album)
|
33
33
|
|
34
34
|
form.name.must_equal "The Dissent Of Man"
|
35
35
|
form.songs[0].title.must_equal "Broken"
|
36
|
-
form.songs[0].composer
|
36
|
+
assert_nil form.songs[0].composer
|
37
37
|
form.songs[1].title.must_equal "Resist Stance"
|
38
38
|
form.songs[1].composer.name.must_equal "Greg Graffin"
|
39
39
|
form.artist.name.must_equal "Bad Religion"
|
@@ -45,4 +45,4 @@ class SetupTest < MiniTest::Spec
|
|
45
45
|
form.artist.must_be_kind_of Reform::Form
|
46
46
|
end
|
47
47
|
end
|
48
|
-
end
|
48
|
+
end
|