st_validation 0.1.0 → 0.2.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 +4 -4
- data/.travis.yml +3 -0
- data/README.org +43 -0
- data/lib/st_validation/abstract_validator.rb +13 -1
- data/lib/st_validation/rspec.rb +21 -0
- data/lib/st_validation/validator_factory.rb +22 -1
- data/lib/st_validation/validators/array_validator.rb +8 -0
- data/lib/st_validation/validators/class_validator.rb +8 -0
- data/lib/st_validation/validators/hash_validator.rb +17 -2
- data/lib/st_validation/validators/union_validator.rb +6 -0
- data/lib/st_validation/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 187366e9fd5c511c575246ccfbc2034ca4e06479b9d29d9d0d462fb58fab4d45
|
4
|
+
data.tar.gz: 43691275ad1ebf833137919ac3096289129de3ea7da6eb06b750e0c9c1cffae2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f18f89aeea5ac68140c1f2c99ca1ea76201a9d8303688eb1318ca373abb2db116a1fc73cf70c29adc15ecdc0d2f0f2d81d3a989669397df701f66ae195e7450c
|
7
|
+
data.tar.gz: 1de6b46630ef92a01706d6e37d76f47f63a76f01b4a9540a3a4a99a7b13bd748d19fb37b5804abd8eeca8e9d38522840231c3012220004350158733aa2827062
|
data/.travis.yml
CHANGED
data/README.org
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
#+TITLE: St. Validation
|
2
2
|
|
3
|
+
[[https://rubygems.org/gems/st_validation][https://badge.fury.io/rb/st_validation.svg]] [[https://travis-ci.org/Nondv/st_validation.rb][https://travis-ci.org/Nondv/st_validation.rb.svg?branch=master]]
|
4
|
+
|
3
5
|
Incredibly simple and customisable validation DSL
|
4
6
|
|
5
7
|
#+BEGIN_SRC ruby
|
@@ -37,6 +39,8 @@ is_valid_user.call(
|
|
37
39
|
- [[#maybe-optional-values][Maybe (optional values)]]
|
38
40
|
- [[#tinkering-dsl][Tinkering DSL]]
|
39
41
|
- [[#important-note][Important note!]]
|
42
|
+
- [[#explain][explain]]
|
43
|
+
- [[#testing][Testing]]
|
40
44
|
- [[#contributing][Contributing]]
|
41
45
|
- [[#license][License]]
|
42
46
|
|
@@ -182,6 +186,45 @@ The process stops when no transformation changed the blueprint.
|
|
182
186
|
|
183
187
|
Do *not* rely on order; it's not guarantueed.
|
184
188
|
|
189
|
+
** explain
|
190
|
+
|
191
|
+
For development purposes there's a =#explain= method defined in =StValidation::AbstractValidator=.
|
192
|
+
The purpose of it is to show why a value didn't pass validation.
|
193
|
+
|
194
|
+
For your custom validators you should implement =#generate_explanation(value)= method.
|
195
|
+
|
196
|
+
#+BEGIN_SRC ruby
|
197
|
+
validator = StValidation.build(
|
198
|
+
id: Integer,
|
199
|
+
email: String,
|
200
|
+
)
|
201
|
+
|
202
|
+
validator.explain(
|
203
|
+
id: '123',
|
204
|
+
email: 'user@example.com'
|
205
|
+
)
|
206
|
+
# ==> { id: 'Expected Integer got String' }
|
207
|
+
#+END_SRC
|
208
|
+
|
209
|
+
** Testing
|
210
|
+
|
211
|
+
There's a rspec matcher:
|
212
|
+
|
213
|
+
#+BEGIN_SRC ruby
|
214
|
+
require 'st_validation/rspec'
|
215
|
+
|
216
|
+
RSpec.describe 'user hash' do
|
217
|
+
it 'matches schema' do
|
218
|
+
user = build_user_hash
|
219
|
+
expect(user).to pass_st_validation(
|
220
|
+
id: Integer,
|
221
|
+
name: String,
|
222
|
+
age: Set[NilClass, Integer]
|
223
|
+
)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
#+END_SRC
|
185
228
|
|
186
229
|
* Contributing
|
187
230
|
|
@@ -1,11 +1,23 @@
|
|
1
1
|
module StValidation
|
2
2
|
class AbstractValidator
|
3
|
-
def call
|
3
|
+
def call(_value)
|
4
4
|
raise 'implement this'
|
5
5
|
end
|
6
6
|
|
7
7
|
def to_proc
|
8
8
|
->(x) { call(x) }
|
9
9
|
end
|
10
|
+
|
11
|
+
def explain(value)
|
12
|
+
generate_explanation(value)
|
13
|
+
rescue StandardError => error
|
14
|
+
"#explain failed with #{error.class}: #{error.message}"
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def generate_explanation(_value)
|
20
|
+
raise "#{self.class}#generate_explanation is not implemented"
|
21
|
+
end
|
10
22
|
end
|
11
23
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'rspec/expectations'
|
3
|
+
|
4
|
+
RSpec::Matchers.define :pass_st_validation do |validator|
|
5
|
+
unless validator.is_a?(StValidation::AbstractValidator)
|
6
|
+
validator = StValidation.build(validator)
|
7
|
+
end
|
8
|
+
|
9
|
+
match do |actual|
|
10
|
+
validator.call(actual)
|
11
|
+
end
|
12
|
+
|
13
|
+
failure_message do |actual|
|
14
|
+
output = PP.pp(validator.explain(actual), '')
|
15
|
+
"value didn't pass St. Validation. #explain output:\n#{output}"
|
16
|
+
end
|
17
|
+
|
18
|
+
failure_message_when_negated do |_actual|
|
19
|
+
"value wasn't supposed pass St. Validation"
|
20
|
+
end
|
21
|
+
end
|
@@ -1,5 +1,25 @@
|
|
1
|
+
require_relative 'abstract_validator'
|
2
|
+
|
1
3
|
module StValidation
|
2
4
|
class ValidatorFactory
|
5
|
+
class ProcValidatorWrapper < AbstractValidator
|
6
|
+
def initialize(proc_object)
|
7
|
+
@proc_object = proc_object
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(value)
|
11
|
+
@proc_object.call(value)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def generate_explanation(value)
|
17
|
+
return nil if call(value)
|
18
|
+
|
19
|
+
@proc_object.source_location
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
3
23
|
attr_reader :transformations
|
4
24
|
|
5
25
|
def initialize(transformations = [])
|
@@ -13,8 +33,9 @@ module StValidation
|
|
13
33
|
result = transformations.reduce(result) { |res, t| t.call(res, self) }
|
14
34
|
break if result == old
|
15
35
|
end
|
36
|
+
result = ProcValidatorWrapper.new(result) if result.is_a?(Proc)
|
16
37
|
|
17
|
-
raise InvalidBlueprintError unless result.is_a?(
|
38
|
+
raise InvalidBlueprintError unless result.is_a?(AbstractValidator)
|
18
39
|
|
19
40
|
result
|
20
41
|
end
|
@@ -8,8 +8,7 @@ module StValidation
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def call(value)
|
11
|
-
return false unless value.is_a?(Hash) &&
|
12
|
-
(value.keys - validators.keys).empty?
|
11
|
+
return false unless value.is_a?(Hash) && extra_keys(value).empty?
|
13
12
|
|
14
13
|
validators.each { |k, v| return false unless v.call(value[k]) }
|
15
14
|
true
|
@@ -18,6 +17,22 @@ module StValidation
|
|
18
17
|
private
|
19
18
|
|
20
19
|
attr_reader :validators
|
20
|
+
|
21
|
+
def generate_explanation(value)
|
22
|
+
return 'not a hash' unless value.is_a?(Hash)
|
23
|
+
|
24
|
+
result = validators
|
25
|
+
.reduce({}) { |a, (k, v)| a.merge(k => v.explain(value[k])) }
|
26
|
+
.compact
|
27
|
+
|
28
|
+
extra_keys(value).each { |k| result[k] = 'extra key detected' }
|
29
|
+
|
30
|
+
result.empty? ? nil : result
|
31
|
+
end
|
32
|
+
|
33
|
+
def extra_keys(hash)
|
34
|
+
hash.keys - validators.keys
|
35
|
+
end
|
21
36
|
end
|
22
37
|
end
|
23
38
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: st_validation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dmitry Non
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-12-
|
11
|
+
date: 2019-12-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -71,6 +71,7 @@ files:
|
|
71
71
|
- lib/st_validation.rb
|
72
72
|
- lib/st_validation/abstract_validator.rb
|
73
73
|
- lib/st_validation/errors.rb
|
74
|
+
- lib/st_validation/rspec.rb
|
74
75
|
- lib/st_validation/validator_factory.rb
|
75
76
|
- lib/st_validation/validators/array_validator.rb
|
76
77
|
- lib/st_validation/validators/class_validator.rb
|