definition 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/Changelog.md +11 -0
- data/README.md +53 -3
- data/lib/definition/conform_result.rb +17 -7
- data/lib/definition/dsl.rb +19 -0
- data/lib/definition/types/and.rb +1 -0
- data/lib/definition/types/keys.rb +13 -3
- data/lib/definition/types/type.rb +2 -0
- data/lib/definition/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2e17d7407705fa6a48ed0a3852b73abe91688fbe
|
4
|
+
data.tar.gz: 118a8ad2dc4663c8666a25b68614f89f8546ab16
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fe00bb7ab22dbc910ab68df1e054e5d15618d3e02d91a266c2f1fb07c48a4d95553c0071fbe3f5e3274d446d833491efd1753cca8d6ef625c25aa17747c129c6
|
7
|
+
data.tar.gz: 5cee41aff7c8c40cb54c533f6424046152fdcdfd9a971e17fc11209ec833b21e3834d77158c200430678d9683e9fcdc510aac0527838276fc502a74ab91b5451
|
data/Changelog.md
CHANGED
@@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## [0.5.0] - 2019-03-28
|
8
|
+
### Added
|
9
|
+
- CoercibleValueObject Definition for better nesting of ValueObjects
|
10
|
+
- Nilable Definition as shortcut for nil OR some other definition
|
11
|
+
- Option for Keys Definition to ignore unexpected keys
|
12
|
+
### Fixed
|
13
|
+
- Error hash was missing some errors in a few cases
|
14
|
+
- `ConformResult.error_hash` was empty for Definitions without any `Keys` Definition
|
15
|
+
### Changed
|
16
|
+
- And Definition stops processing after the first failure
|
17
|
+
|
7
18
|
## [0.4.0] - 2019-03-22
|
8
19
|
### Added
|
9
20
|
- Added support for default values to Keys Definition
|
data/README.md
CHANGED
@@ -111,6 +111,28 @@ IntegerArray.new([1,2,"3"]) # => Definition::InvalidValueObjectError: Not all it
|
|
111
111
|
|
112
112
|
You can access the conform result object via `InvalidValueObjectError#conform_result`
|
113
113
|
|
114
|
+
#### Nesting value Objects
|
115
|
+
|
116
|
+
Value objects can be nested by either using the value object itself as type definition,
|
117
|
+
or by using the `CoercibleValueObject` Definition. The latter would convert input
|
118
|
+
hashes that conform with the value objects schema to an instance of the value object.
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
class IntegerArray < Definition::ValueObject
|
122
|
+
definition(Definition.Each(Definition.Type(Integer)))
|
123
|
+
end
|
124
|
+
|
125
|
+
class User < Definition::ValueObject
|
126
|
+
definition(Definition.Keys do
|
127
|
+
required :username, Definition.Type(String)
|
128
|
+
required :scores, Definition.CoercibleValueObject(IntegerArray)
|
129
|
+
end)
|
130
|
+
end
|
131
|
+
|
132
|
+
object = User.new(username: "John", scores: [1,2,3])
|
133
|
+
object.scores.class.name # => IntegerArray
|
134
|
+
```
|
135
|
+
|
114
136
|
### Conforming Hashes
|
115
137
|
|
116
138
|
Hashes can be conformed by using the `Keys` definition. It allows you to configure
|
@@ -130,6 +152,25 @@ Definition.Keys do
|
|
130
152
|
end
|
131
153
|
```
|
132
154
|
|
155
|
+
#### Ignoring unexpected keys
|
156
|
+
|
157
|
+
By default the `Keys` Definition does not conform with input hashes that contains
|
158
|
+
keys that are not defined in the Definition. You can set the `:ignore_extra_keys`
|
159
|
+
option to disable this.
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
schema = Definition.Keys do
|
163
|
+
option :ignore_extra_keys
|
164
|
+
|
165
|
+
required :title, Definition.NonEmptyString
|
166
|
+
optional :publication_date, Definition.Type(Time)
|
167
|
+
end
|
168
|
+
|
169
|
+
conform_result = schema.conform({title: "My first blog post", body: "Shortest one ever!", publication_date: Time.new})
|
170
|
+
conform_result.passed? # => true
|
171
|
+
conform_result.value # => {title: "My first blog post", publication_date: 2018-12-30 11:43:00 UTC}
|
172
|
+
```
|
173
|
+
|
133
174
|
### Validating types
|
134
175
|
|
135
176
|
This will validate that the value is of the specified type.
|
@@ -159,17 +200,17 @@ Definition.CoercibleType(Float).conform("0.1").value # => 0.1
|
|
159
200
|
### Combining multiple definitions with "And"
|
160
201
|
|
161
202
|
```ruby
|
162
|
-
Definition.And(definition1, definition2)
|
203
|
+
Definition.And(definition1, definition2, ...)
|
163
204
|
```
|
164
205
|
|
165
206
|
This definition will only conform if all definitions conform. The definitions will
|
166
207
|
be processed from left to right and the output of the previous will be the input
|
167
|
-
of the next.
|
208
|
+
of the next. Processing of the And-Definition stops as soon as one definition does not conform.
|
168
209
|
|
169
210
|
### Combining multiple definitions with "Or"
|
170
211
|
|
171
212
|
```ruby
|
172
|
-
Definition.Or(definition1, definition2)
|
213
|
+
Definition.Or(definition1, definition2, ...)
|
173
214
|
```
|
174
215
|
|
175
216
|
This definition will conform if at least one definition conforms. The definitions will
|
@@ -291,11 +332,20 @@ Definition.NonEmpty.conform({ a: 1 }) # => pass
|
|
291
332
|
Definition.Nil.conform(nil) # => pass
|
292
333
|
```
|
293
334
|
|
335
|
+
#### Boolean
|
336
|
+
|
337
|
+
```ruby
|
338
|
+
Definition.Boolean.conform(tru) # => pass
|
339
|
+
```
|
340
|
+
|
294
341
|
#### All types
|
295
342
|
|
296
343
|
```ruby
|
297
344
|
Definition.Equal(5).conform(5) # => pass
|
298
345
|
Definition.Equal("foo").conform("foo") # => pass
|
346
|
+
|
347
|
+
Definition.Nilable(Definition.Type(String)).conform(nil) # => pass
|
348
|
+
Definition.Nilable(Definition.Type(String)).conform("foo") # => pass
|
299
349
|
```
|
300
350
|
|
301
351
|
### Examples
|
@@ -33,14 +33,14 @@ module Definition
|
|
33
33
|
def error_hash
|
34
34
|
{}.tap do |error_hash|
|
35
35
|
errors.each do |error|
|
36
|
-
|
36
|
+
path_hash = if error.error_path.empty?
|
37
|
+
{ "" => error }
|
38
|
+
else
|
39
|
+
error.error_path.reverse
|
40
|
+
.inject([error]) { |errors, key| { key => errors } }
|
41
|
+
end
|
37
42
|
|
38
|
-
path_hash
|
39
|
-
.inject([error]) { |errors, key| { key => errors } }
|
40
|
-
|
41
|
-
error_hash.deep_merge!(path_hash) do |_key, old, new|
|
42
|
-
old + new if old.is_a?(Array) && new.is_a?(Array) # concat arrays during deep_merge
|
43
|
-
end
|
43
|
+
merge_error_hash(error_hash, path_hash)
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
@@ -51,6 +51,16 @@ module Definition
|
|
51
51
|
|
52
52
|
private
|
53
53
|
|
54
|
+
def merge_error_hash(hash, new_hash)
|
55
|
+
hash.deep_merge!(new_hash) do |_key, old, new|
|
56
|
+
if old.is_a?(Array) && new.is_a?(Hash) # Dont replace Hashes with arrays
|
57
|
+
new
|
58
|
+
elsif old.is_a?(Array) && new.is_a?(Array) # concat arrays during deep_merge
|
59
|
+
old + new
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
54
64
|
def find_next_parent_key_error(error)
|
55
65
|
current = error
|
56
66
|
loop do
|
data/lib/definition/dsl.rb
CHANGED
@@ -76,5 +76,24 @@ module Definition
|
|
76
76
|
def Boolean # rubocop:disable Style/MethodName
|
77
77
|
Types::Or.new(:boolean, Type(TrueClass), Type(FalseClass))
|
78
78
|
end
|
79
|
+
|
80
|
+
# Example:
|
81
|
+
# CoercibleValueObject(ValueObjectClass)
|
82
|
+
def CoercibleValueObject(klass) # rubocop:disable Style/MethodName
|
83
|
+
Types::Or.new(:coercible_value_object,
|
84
|
+
Definition.Type(klass), # If its of ther correct type already this will let it pass already
|
85
|
+
And(
|
86
|
+
klass, # First make sure that the input could be coerced to 'klass'
|
87
|
+
Lambda("value_object_coercion", context: { value_object_class: klass }) do |value|
|
88
|
+
conform_with(klass.new(value)) # Actually coerce the input to klass
|
89
|
+
end
|
90
|
+
))
|
91
|
+
end
|
92
|
+
|
93
|
+
# Example:
|
94
|
+
# Nilable(Definition.Type(Integer))
|
95
|
+
def Nilable(definition) # rubocop:disable Style/MethodName
|
96
|
+
Types::Or.new(:nullable, Nil(), definition)
|
97
|
+
end
|
79
98
|
end
|
80
99
|
end
|
data/lib/definition/types/and.rb
CHANGED
@@ -22,16 +22,26 @@ module Definition
|
|
22
22
|
def default(key, value)
|
23
23
|
defaults[key] = value
|
24
24
|
end
|
25
|
+
|
26
|
+
def option(option_name)
|
27
|
+
case option_name
|
28
|
+
when :ignore_extra_keys
|
29
|
+
self.ignore_extra_keys = true
|
30
|
+
else
|
31
|
+
raise "Option #{option_name} is not defined"
|
32
|
+
end
|
33
|
+
end
|
25
34
|
end
|
26
35
|
|
27
36
|
include Dsl
|
28
|
-
attr_accessor :required_definitions, :optional_definitions, :defaults
|
37
|
+
attr_accessor :required_definitions, :optional_definitions, :defaults, :ignore_extra_keys
|
29
38
|
|
30
|
-
def initialize(name, req: {}, opt: {}, defaults: {})
|
39
|
+
def initialize(name, req: {}, opt: {}, defaults: {}, options: {})
|
31
40
|
super(name)
|
32
41
|
self.required_definitions = req
|
33
42
|
self.optional_definitions = opt
|
34
43
|
self.defaults = defaults
|
44
|
+
self.ignore_extra_keys = options.fetch(:ignore_extra_keys, false)
|
35
45
|
end
|
36
46
|
|
37
47
|
def conform(value)
|
@@ -50,7 +60,7 @@ module Definition
|
|
50
60
|
end
|
51
61
|
|
52
62
|
def conform
|
53
|
-
add_extra_key_errors
|
63
|
+
add_extra_key_errors unless definition.ignore_extra_keys
|
54
64
|
add_missing_key_errors
|
55
65
|
values = conform_all_keys
|
56
66
|
|
data/lib/definition/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: definition
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dominik Goltermann
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-03-
|
11
|
+
date: 2019-03-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -299,7 +299,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
299
299
|
version: '0'
|
300
300
|
requirements: []
|
301
301
|
rubyforge_project:
|
302
|
-
rubygems_version: 2.
|
302
|
+
rubygems_version: 2.2.2
|
303
303
|
signing_key:
|
304
304
|
specification_version: 4
|
305
305
|
summary: Simple and composable validation and coercion of data structures inspired
|