reform 2.3.0.rc1 → 2.5.0
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 +7 -11
- data/CHANGES.md +43 -3
- data/Gemfile +2 -5
- data/ISSUE_TEMPLATE.md +1 -1
- data/LICENSE.txt +1 -1
- data/README.md +7 -9
- data/Rakefile +6 -10
- data/lib/reform/contract.rb +7 -7
- data/lib/reform/contract/custom_error.rb +41 -0
- data/lib/reform/contract/validate.rb +10 -6
- 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 +22 -60
- data/lib/reform/form/dry/input_hash.rb +37 -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 -4
- data/lib/reform/version.rb +1 -1
- data/reform.gemspec +9 -9
- data/test/benchmarking.rb +10 -11
- data/test/call_test.rb +8 -8
- data/test/changed_test.rb +13 -13
- data/test/coercion_test.rb +56 -24
- data/test/composition_test.rb +49 -51
- data/test/contract/custom_error_test.rb +55 -0
- data/test/contract_test.rb +18 -18
- data/test/default_test.rb +3 -3
- data/test/deserialize_test.rb +14 -17
- data/test/docs/validation_test.rb +134 -0
- data/test/errors_test.rb +131 -86
- data/test/feature_test.rb +9 -11
- data/test/fixtures/dry_error_messages.yml +65 -52
- data/test/form_option_test.rb +3 -3
- data/test/form_test.rb +6 -6
- data/test/from_test.rb +17 -21
- data/test/inherit_test.rb +28 -35
- data/test/module_test.rb +23 -28
- data/test/parse_option_test.rb +12 -12
- data/test/parse_pipeline_test.rb +3 -3
- data/test/populate_test.rb +146 -93
- data/test/populator_skip_test.rb +3 -4
- data/test/prepopulator_test.rb +20 -21
- data/test/read_only_test.rb +12 -1
- data/test/readable_test.rb +7 -7
- data/test/reform_test.rb +38 -42
- data/test/save_test.rb +16 -19
- data/test/setup_test.rb +15 -15
- data/test/skip_if_test.rb +30 -19
- data/test/skip_setter_and_getter_test.rb +8 -9
- data/test/test_helper.rb +12 -5
- data/test/validate_test.rb +160 -140
- data/test/validation/dry_validation_test.rb +407 -236
- data/test/validation/result_test.rb +29 -31
- data/test/validation_library_provided_test.rb +3 -3
- data/test/virtual_test.rb +46 -6
- data/test/writeable_test.rb +13 -13
- metadata +32 -29
- data/test/readonly_test.rb +0 -14
@@ -8,72 +8,70 @@ class ErrorsResultTest < Minitest::Spec
|
|
8
8
|
# TODO: errors(args) not tested.
|
9
9
|
|
10
10
|
describe "Contract::Result#success?" do
|
11
|
-
let
|
12
|
-
let
|
11
|
+
let(:failed) { MyResult.new(false) }
|
12
|
+
let(:succeeded) { MyResult.new(true) }
|
13
13
|
|
14
|
-
it { Reform::Contract::Result.new([failed, failed]).success
|
15
|
-
it { Reform::Contract::Result.new([succeeded, failed]).success
|
16
|
-
it { Reform::Contract::Result.new([failed, succeeded]).success
|
17
|
-
it { Reform::Contract::Result.new([succeeded, succeeded]).success
|
14
|
+
it { assert_equal Reform::Contract::Result.new([failed, failed]).success?, false }
|
15
|
+
it { assert_equal Reform::Contract::Result.new([succeeded, failed]).success?, false }
|
16
|
+
it { assert_equal Reform::Contract::Result.new([failed, succeeded]).success?, false }
|
17
|
+
it { assert Reform::Contract::Result.new([succeeded, succeeded]).success? }
|
18
18
|
end
|
19
19
|
|
20
20
|
describe "Contract::Result#errors" do
|
21
|
-
let
|
21
|
+
let(:results) do
|
22
22
|
[
|
23
|
-
MyResult.new(false, {
|
24
|
-
MyResult.new(false, {
|
23
|
+
MyResult.new(false, {length: ["no Int"]}),
|
24
|
+
MyResult.new(false, {title: ["must be filled"], nested: {something: []}}),
|
25
|
+
MyResult.new(false, {title: ["must be filled"], nested: {something: []}}),
|
26
|
+
MyResult.new(false, {title: ["something more"], nested: {something: []}})
|
25
27
|
]
|
26
|
-
|
28
|
+
end
|
27
29
|
|
28
|
-
it { Reform::Contract::Result.new(results).errors
|
30
|
+
it { assert_equal Reform::Contract::Result.new(results).errors, {title: ["must be filled", "something more"], length: ["no Int"]} }
|
29
31
|
end
|
30
32
|
|
31
33
|
describe "Result::Pointer" do
|
32
|
-
let
|
34
|
+
let(:errors) do # dry result #errors format.
|
33
35
|
{
|
34
36
|
title: ["ignore"],
|
35
|
-
artist: {
|
37
|
+
artist: {age: ["too old"],
|
36
38
|
bands: {
|
37
|
-
0 => {
|
38
|
-
1 => {
|
39
|
+
0 => {name: "too new school"},
|
40
|
+
1 => {name: "too boring"},
|
39
41
|
}
|
40
42
|
}
|
41
43
|
}
|
42
44
|
end
|
43
45
|
|
44
|
-
let
|
45
|
-
it { top.success
|
46
|
-
it { top.errors
|
46
|
+
let(:top) { Reform::Contract::Result::Pointer.new(MyResult.new(false, errors), []) }
|
47
|
+
it { assert_equal top.success?, false }
|
48
|
+
it { assert_equal top.errors, errors }
|
47
49
|
|
48
|
-
let
|
49
|
-
it { artist.success
|
50
|
-
it { artist.errors
|
50
|
+
let(:artist) { Reform::Contract::Result::Pointer.new(MyResult.new(false, errors), [:artist]) }
|
51
|
+
it { assert_equal artist.success?, false }
|
52
|
+
it { assert_equal artist.errors,({age: ["too old"], bands: {0 => {name: "too new school"}, 1 => {name: "too boring"}}}) }
|
51
53
|
|
52
|
-
let
|
53
|
-
it { band.success
|
54
|
-
it { band.errors
|
54
|
+
let(:band) { Reform::Contract::Result::Pointer.new(MyResult.new(false, errors), [:artist, :bands, 1]) }
|
55
|
+
it { assert_equal band.success?, false }
|
56
|
+
it { assert_equal band.errors,({name: "too boring"}) }
|
55
57
|
|
56
58
|
describe "advance" do
|
57
59
|
let(:advanced) { artist.advance(:bands, 1) }
|
58
60
|
|
59
|
-
it { advanced.success
|
60
|
-
it { advanced.errors
|
61
|
+
it { assert_equal advanced.success?, false }
|
62
|
+
it { assert_equal advanced.errors,({name: "too boring"}) }
|
61
63
|
|
62
|
-
it { artist.advance([
|
64
|
+
it { assert_nil artist.advance(%i[absolute nonsense]) }
|
63
65
|
end
|
64
66
|
end
|
65
67
|
end
|
66
68
|
|
67
|
-
|
68
69
|
# validation group:
|
69
70
|
|
70
71
|
# form.errors/messages/hint(*args) ==> {:title: [..]}
|
71
72
|
# @call_result.errors/messages/hint(*args) }
|
72
73
|
|
73
|
-
|
74
|
-
|
75
74
|
# # result = Result(original_result => [:band, :label], my_local_result => [] )
|
76
75
|
# # result.messages(locale: :en) merges original_result and my_local_result
|
77
76
|
|
78
77
|
# form.errors => Result(fetch tree of all nested forms.messages(*args))
|
79
|
-
|
@@ -1,8 +1,8 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "reform"
|
2
|
+
require "minitest/autorun"
|
3
3
|
|
4
4
|
class ValidationLibraryProvidedTest < MiniTest::Spec
|
5
|
-
it
|
5
|
+
it "no validation library loaded" do
|
6
6
|
assert_raises Reform::Validation::NoValidationLibraryError do
|
7
7
|
class PersonForm < Reform::Form
|
8
8
|
property :name
|
data/test/virtual_test.rb
CHANGED
@@ -1,16 +1,20 @@
|
|
1
|
-
require
|
1
|
+
require "test_helper"
|
2
2
|
|
3
3
|
class VirtualTest < MiniTest::Spec
|
4
4
|
class CreditCardForm < TestForm
|
5
5
|
property :credit_card_number, virtual: true # no read, no write, it's virtual.
|
6
|
+
collection :transactions, virtual: true, populate_if_empty: OpenStruct do
|
7
|
+
property :id
|
8
|
+
end
|
6
9
|
end
|
7
10
|
|
8
|
-
let
|
11
|
+
let(:form) { CreditCardForm.new(Object.new) }
|
9
12
|
|
10
13
|
it {
|
11
|
-
form.validate(
|
14
|
+
form.validate(credit_card_number: "123", transactions: [id: 1])
|
12
15
|
|
13
|
-
form.credit_card_number
|
16
|
+
assert_equal form.credit_card_number, "123" # this is still readable in the UI.
|
17
|
+
assert_equal form.transactions.first.id, 1 # this is still readable in the UI.
|
14
18
|
|
15
19
|
form.sync
|
16
20
|
|
@@ -19,6 +23,42 @@ class VirtualTest < MiniTest::Spec
|
|
19
23
|
hash = nested
|
20
24
|
end
|
21
25
|
|
22
|
-
hash
|
26
|
+
assert_equal hash, "credit_card_number" => "123", "transactions" => ["id" => 1]
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
class VirtualAndDefaultTest < MiniTest::Spec
|
31
|
+
class CreditCardForm < TestForm
|
32
|
+
property :credit_card_number, virtual: true, default: "123" # no read, no write, it's virtual.
|
33
|
+
collection :transactions, virtual: true, populate_if_empty: OpenStruct, default: [OpenStruct.new(id: 2)] do
|
34
|
+
property :id
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def hash(form)
|
39
|
+
hash = {}
|
40
|
+
form.save do |nested|
|
41
|
+
hash = nested
|
42
|
+
end
|
43
|
+
hash
|
44
|
+
end
|
45
|
+
|
46
|
+
let(:form) { CreditCardForm.new(Object.new) }
|
47
|
+
|
48
|
+
it {
|
49
|
+
form = CreditCardForm.new(Object.new)
|
50
|
+
form.validate({})
|
51
|
+
|
52
|
+
assert_equal hash(form), "credit_card_number" => "123", "transactions" => ["id" => 2]
|
53
|
+
|
54
|
+
form = CreditCardForm.new(Object.new)
|
55
|
+
form.validate(credit_card_number: "123", transactions: [id: 1])
|
56
|
+
|
57
|
+
assert_equal form.credit_card_number, "123" # this is still readable in the UI.
|
58
|
+
assert_equal form.transactions.first.id, 1 # this is still readable in the UI.
|
59
|
+
|
60
|
+
form.sync
|
61
|
+
|
62
|
+
assert_equal hash(form), "credit_card_number" => "123", "transactions" => ["id" => 1]
|
23
63
|
}
|
24
|
-
end
|
64
|
+
end
|
data/test/writeable_test.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "test_helper"
|
2
2
|
|
3
3
|
class WriteableTest < MiniTest::Spec
|
4
4
|
Location = Struct.new(:country)
|
@@ -7,24 +7,24 @@ class WriteableTest < MiniTest::Spec
|
|
7
7
|
property :country, writeable: false
|
8
8
|
end
|
9
9
|
|
10
|
-
let
|
11
|
-
let
|
10
|
+
let(:loc) { Location.new("Australia") }
|
11
|
+
let(:form) { LocationForm.new(loc) }
|
12
12
|
|
13
13
|
it do
|
14
|
-
form.country
|
14
|
+
assert_equal form.country, "Australia"
|
15
15
|
|
16
16
|
form.validate("country" => "Germany") # this usually won't change when submitting.
|
17
|
-
form.country
|
17
|
+
assert_equal form.country, "Germany"
|
18
18
|
|
19
19
|
form.sync
|
20
|
-
loc.country
|
20
|
+
assert_equal loc.country, "Australia" # the writer wasn't called.
|
21
21
|
|
22
22
|
hash = {}
|
23
23
|
form.save do |nested|
|
24
24
|
hash = nested
|
25
25
|
end
|
26
26
|
|
27
|
-
hash
|
27
|
+
assert_equal hash, "country" => "Germany"
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -36,23 +36,23 @@ class WritableTest < MiniTest::Spec
|
|
36
36
|
property :country, writable: false
|
37
37
|
end
|
38
38
|
|
39
|
-
let
|
40
|
-
let
|
39
|
+
let(:loc) { Location.new("Australia") }
|
40
|
+
let(:form) { LocationForm.new(loc) }
|
41
41
|
|
42
42
|
it do
|
43
|
-
form.country
|
43
|
+
assert_equal form.country, "Australia"
|
44
44
|
|
45
45
|
form.validate("country" => "Germany") # this usually won't change when submitting.
|
46
|
-
form.country
|
46
|
+
assert_equal form.country, "Germany"
|
47
47
|
|
48
48
|
form.sync
|
49
|
-
loc.country
|
49
|
+
assert_equal loc.country, "Australia" # the writer wasn't called.
|
50
50
|
|
51
51
|
hash = {}
|
52
52
|
form.save do |nested|
|
53
53
|
hash = nested
|
54
54
|
end
|
55
55
|
|
56
|
-
hash
|
56
|
+
assert_equal hash, "country" => "Germany"
|
57
57
|
end
|
58
58
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reform
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Sutterer
|
8
8
|
- Fran Worley
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2021-02-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: disposable
|
@@ -32,39 +32,39 @@ dependencies:
|
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 0.5.0
|
34
34
|
- !ruby/object:Gem::Dependency
|
35
|
-
name:
|
35
|
+
name: representable
|
36
36
|
requirement: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.4.0
|
38
41
|
- - "<"
|
39
42
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
43
|
+
version: 3.1.0
|
41
44
|
type: :runtime
|
42
45
|
prerelease: false
|
43
46
|
version_requirements: !ruby/object:Gem::Requirement
|
44
47
|
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: 2.4.0
|
45
51
|
- - "<"
|
46
52
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
53
|
+
version: 3.1.0
|
48
54
|
- !ruby/object:Gem::Dependency
|
49
|
-
name:
|
55
|
+
name: uber
|
50
56
|
requirement: !ruby/object:Gem::Requirement
|
51
57
|
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: 2.4.0
|
55
58
|
- - "<"
|
56
59
|
- !ruby/object:Gem::Version
|
57
|
-
version:
|
60
|
+
version: 0.2.0
|
58
61
|
type: :runtime
|
59
62
|
prerelease: false
|
60
63
|
version_requirements: !ruby/object:Gem::Requirement
|
61
64
|
requirements:
|
62
|
-
- - ">="
|
63
|
-
- !ruby/object:Gem::Version
|
64
|
-
version: 2.4.0
|
65
65
|
- - "<"
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version:
|
67
|
+
version: 0.2.0
|
68
68
|
- !ruby/object:Gem::Dependency
|
69
69
|
name: bundler
|
70
70
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,7 +80,7 @@ dependencies:
|
|
80
80
|
- !ruby/object:Gem::Version
|
81
81
|
version: '0'
|
82
82
|
- !ruby/object:Gem::Dependency
|
83
|
-
name:
|
83
|
+
name: minitest
|
84
84
|
requirement: !ruby/object:Gem::Requirement
|
85
85
|
requirements:
|
86
86
|
- - ">="
|
@@ -94,7 +94,7 @@ dependencies:
|
|
94
94
|
- !ruby/object:Gem::Version
|
95
95
|
version: '0'
|
96
96
|
- !ruby/object:Gem::Dependency
|
97
|
-
name: minitest
|
97
|
+
name: minitest-line
|
98
98
|
requirement: !ruby/object:Gem::Requirement
|
99
99
|
requirements:
|
100
100
|
- - ">="
|
@@ -108,7 +108,7 @@ dependencies:
|
|
108
108
|
- !ruby/object:Gem::Version
|
109
109
|
version: '0'
|
110
110
|
- !ruby/object:Gem::Dependency
|
111
|
-
name:
|
111
|
+
name: pry-byebug
|
112
112
|
requirement: !ruby/object:Gem::Requirement
|
113
113
|
requirements:
|
114
114
|
- - ">="
|
@@ -136,19 +136,19 @@ dependencies:
|
|
136
136
|
- !ruby/object:Gem::Version
|
137
137
|
version: '0'
|
138
138
|
- !ruby/object:Gem::Dependency
|
139
|
-
name:
|
139
|
+
name: rake
|
140
140
|
requirement: !ruby/object:Gem::Requirement
|
141
141
|
requirements:
|
142
142
|
- - ">="
|
143
143
|
- !ruby/object:Gem::Version
|
144
|
-
version: 0
|
144
|
+
version: '0'
|
145
145
|
type: :development
|
146
146
|
prerelease: false
|
147
147
|
version_requirements: !ruby/object:Gem::Requirement
|
148
148
|
requirements:
|
149
149
|
- - ">="
|
150
150
|
- !ruby/object:Gem::Version
|
151
|
-
version: 0
|
151
|
+
version: '0'
|
152
152
|
description: Form object decoupled from models.
|
153
153
|
email:
|
154
154
|
- apotonick@gmail.com
|
@@ -169,6 +169,7 @@ files:
|
|
169
169
|
- TODO.md
|
170
170
|
- lib/reform.rb
|
171
171
|
- lib/reform/contract.rb
|
172
|
+
- lib/reform/contract/custom_error.rb
|
172
173
|
- lib/reform/contract/validate.rb
|
173
174
|
- lib/reform/errors.rb
|
174
175
|
- lib/reform/form.rb
|
@@ -176,6 +177,7 @@ files:
|
|
176
177
|
- lib/reform/form/coercion.rb
|
177
178
|
- lib/reform/form/composition.rb
|
178
179
|
- lib/reform/form/dry.rb
|
180
|
+
- lib/reform/form/dry/input_hash.rb
|
179
181
|
- lib/reform/form/module.rb
|
180
182
|
- lib/reform/form/populator.rb
|
181
183
|
- lib/reform/form/prepopulate.rb
|
@@ -190,9 +192,11 @@ files:
|
|
190
192
|
- test/changed_test.rb
|
191
193
|
- test/coercion_test.rb
|
192
194
|
- test/composition_test.rb
|
195
|
+
- test/contract/custom_error_test.rb
|
193
196
|
- test/contract_test.rb
|
194
197
|
- test/default_test.rb
|
195
198
|
- test/deserialize_test.rb
|
199
|
+
- test/docs/validation_test.rb
|
196
200
|
- test/errors_test.rb
|
197
201
|
- test/feature_test.rb
|
198
202
|
- test/fixtures/dry_error_messages.yml
|
@@ -208,7 +212,6 @@ files:
|
|
208
212
|
- test/prepopulator_test.rb
|
209
213
|
- test/read_only_test.rb
|
210
214
|
- test/readable_test.rb
|
211
|
-
- test/readonly_test.rb
|
212
215
|
- test/reform_test.rb
|
213
216
|
- test/save_test.rb
|
214
217
|
- test/setup_test.rb
|
@@ -225,7 +228,7 @@ homepage: https://github.com/trailblazer/reform
|
|
225
228
|
licenses:
|
226
229
|
- MIT
|
227
230
|
metadata: {}
|
228
|
-
post_install_message:
|
231
|
+
post_install_message:
|
229
232
|
rdoc_options: []
|
230
233
|
require_paths:
|
231
234
|
- lib
|
@@ -236,13 +239,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
236
239
|
version: '0'
|
237
240
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
238
241
|
requirements:
|
239
|
-
- - "
|
242
|
+
- - ">="
|
240
243
|
- !ruby/object:Gem::Version
|
241
|
-
version:
|
244
|
+
version: '0'
|
242
245
|
requirements: []
|
243
|
-
|
244
|
-
|
245
|
-
signing_key:
|
246
|
+
rubygems_version: 3.0.3
|
247
|
+
signing_key:
|
246
248
|
specification_version: 4
|
247
249
|
summary: Form object decoupled from models with validation, population and presentation.
|
248
250
|
test_files:
|
@@ -251,9 +253,11 @@ test_files:
|
|
251
253
|
- test/changed_test.rb
|
252
254
|
- test/coercion_test.rb
|
253
255
|
- test/composition_test.rb
|
256
|
+
- test/contract/custom_error_test.rb
|
254
257
|
- test/contract_test.rb
|
255
258
|
- test/default_test.rb
|
256
259
|
- test/deserialize_test.rb
|
260
|
+
- test/docs/validation_test.rb
|
257
261
|
- test/errors_test.rb
|
258
262
|
- test/feature_test.rb
|
259
263
|
- test/fixtures/dry_error_messages.yml
|
@@ -269,7 +273,6 @@ test_files:
|
|
269
273
|
- test/prepopulator_test.rb
|
270
274
|
- test/read_only_test.rb
|
271
275
|
- test/readable_test.rb
|
272
|
-
- test/readonly_test.rb
|
273
276
|
- test/reform_test.rb
|
274
277
|
- test/save_test.rb
|
275
278
|
- test/setup_test.rb
|