nxt_schema 0.1.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -0
  3. data/Gemfile +0 -1
  4. data/Gemfile.lock +32 -29
  5. data/README.md +186 -116
  6. data/lib/nxt_schema.rb +56 -49
  7. data/lib/nxt_schema/{node.rb → application.rb} +1 -1
  8. data/lib/nxt_schema/application/any_of.rb +40 -0
  9. data/lib/nxt_schema/application/base.rb +116 -0
  10. data/lib/nxt_schema/application/collection.rb +57 -0
  11. data/lib/nxt_schema/application/error_store.rb +57 -0
  12. data/lib/nxt_schema/application/errors/schema_error.rb +15 -0
  13. data/lib/nxt_schema/application/errors/validation_error.rb +15 -0
  14. data/lib/nxt_schema/application/leaf.rb +15 -0
  15. data/lib/nxt_schema/application/schema.rb +114 -0
  16. data/lib/nxt_schema/callable.rb +21 -55
  17. data/lib/nxt_schema/dsl.rb +41 -31
  18. data/lib/nxt_schema/error.rb +4 -0
  19. data/lib/nxt_schema/errors/invalid.rb +16 -0
  20. data/lib/nxt_schema/errors/{error.rb → invalid_options.rb} +1 -2
  21. data/lib/nxt_schema/missing_input.rb +9 -0
  22. data/lib/nxt_schema/node/any_of.rb +51 -0
  23. data/lib/nxt_schema/node/base.rb +135 -233
  24. data/lib/nxt_schema/node/collection.rb +10 -65
  25. data/lib/nxt_schema/node/has_sub_nodes.rb +81 -0
  26. data/lib/nxt_schema/node/leaf.rb +1 -31
  27. data/lib/nxt_schema/node/maybe_evaluator.rb +15 -10
  28. data/lib/nxt_schema/node/on_evaluator.rb +25 -0
  29. data/lib/nxt_schema/node/schema.rb +8 -134
  30. data/lib/nxt_schema/node/sub_nodes.rb +22 -0
  31. data/lib/nxt_schema/node/type_system_resolver.rb +22 -0
  32. data/lib/nxt_schema/types.rb +1 -1
  33. data/lib/nxt_schema/validators/attribute.rb +3 -3
  34. data/lib/nxt_schema/validators/{equality.rb → equal_to.rb} +5 -5
  35. data/lib/nxt_schema/validators/error_messages.rb +42 -0
  36. data/lib/nxt_schema/{error_messages → validators/error_messages}/en.yaml +3 -3
  37. data/lib/nxt_schema/validators/{excluded.rb → excluded_in.rb} +4 -4
  38. data/lib/nxt_schema/validators/excludes.rb +3 -3
  39. data/lib/nxt_schema/validators/greater_than.rb +3 -3
  40. data/lib/nxt_schema/validators/greater_than_or_equal.rb +3 -3
  41. data/lib/nxt_schema/validators/{included.rb → included_in.rb} +4 -4
  42. data/lib/nxt_schema/validators/includes.rb +3 -3
  43. data/lib/nxt_schema/validators/less_than.rb +3 -3
  44. data/lib/nxt_schema/validators/less_than_or_equal.rb +3 -3
  45. data/lib/nxt_schema/validators/optional_node.rb +13 -8
  46. data/lib/nxt_schema/validators/pattern.rb +3 -3
  47. data/lib/nxt_schema/validators/query.rb +4 -4
  48. data/lib/nxt_schema/validators/registry.rb +1 -7
  49. data/lib/nxt_schema/{node → validators}/validate_with_proxy.rb +8 -8
  50. data/lib/nxt_schema/validators/validator.rb +2 -2
  51. data/lib/nxt_schema/version.rb +1 -1
  52. data/nxt_schema.gemspec +1 -0
  53. metadata +42 -22
  54. data/lib/nxt_schema/callable_or_value.rb +0 -72
  55. data/lib/nxt_schema/error_messages.rb +0 -40
  56. data/lib/nxt_schema/errors.rb +0 -4
  57. data/lib/nxt_schema/errors/invalid_options_error.rb +0 -5
  58. data/lib/nxt_schema/errors/schema_not_applied_error.rb +0 -5
  59. data/lib/nxt_schema/node/constructor.rb +0 -9
  60. data/lib/nxt_schema/node/default_value_evaluator.rb +0 -20
  61. data/lib/nxt_schema/node/error.rb +0 -13
  62. data/lib/nxt_schema/node/has_subnodes.rb +0 -97
  63. data/lib/nxt_schema/node/template_store.rb +0 -15
  64. data/lib/nxt_schema/registry.rb +0 -85
  65. data/lib/nxt_schema/undefined.rb +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 83dae4e0a58a5ec9ec18b68fe441ab358496912b26c8993f7a29eb1fc8079504
4
- data.tar.gz: bc82ad37116553668920606298b5e5739a15e6647245c68befba798d96a7f771
3
+ metadata.gz: 36a741174bf1669b013e32f2b3693c99cae2b4e479378cb1494069dd66f1af44
4
+ data.tar.gz: 2984ab8830a495bf1a694cd369216dee00e0dc5cc2cf1c87c173dd5c1e984963
5
5
  SHA512:
6
- metadata.gz: e03262430dcb11ab76da8ec2a6dc295d964a59e679a9fd8ba5492e5618a43769d16e9282b13091656aeb9cad932fa2adc5a31899b4b9ca8963eceb5b47b34b41
7
- data.tar.gz: 28755070f8df4c055a14f3129d95bf5fdbc306d49737b21125ea94cff82ee419e34894517fb77c0a12e793ce338a2d6a502fb218a25b62103b502ed2befc758a
6
+ metadata.gz: f1924005010c80140b9d545fb307ef373cb237a31e166195d6e959af56b41208d49db1d48ff3ab68c77ad45bdee3941821e9c2584cfe50cd2da47134a15a1eac
7
+ data.tar.gz: '001459e22044cfef5aded2ade7d9b8b0fe15c944c4bb886a992578a82886777c2a92e5ce1711919414b79910577b68671249b8bdc74526a89ee0c1437ba4c421'
@@ -0,0 +1 @@
1
+ 2.7.0
data/Gemfile CHANGED
@@ -1,6 +1,5 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
-
5
4
  # Specify your gem's dependencies in nxt_schema.gemspec
6
5
  gemspec
@@ -1,35 +1,36 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- nxt_schema (0.1.2)
4
+ nxt_schema (1.0.0)
5
5
  activesupport
6
6
  dry-types
7
+ nxt_init
7
8
  nxt_registry
8
9
 
9
10
  GEM
10
11
  remote: https://rubygems.org/
11
12
  specs:
12
- activesupport (6.0.2.2)
13
+ activesupport (6.0.3.4)
13
14
  concurrent-ruby (~> 1.0, >= 1.0.2)
14
15
  i18n (>= 0.7, < 2)
15
16
  minitest (~> 5.1)
16
17
  tzinfo (~> 1.1)
17
- zeitwerk (~> 2.2)
18
- coderay (1.1.2)
19
- concurrent-ruby (1.1.6)
20
- diff-lcs (1.3)
21
- dry-configurable (0.11.5)
18
+ zeitwerk (~> 2.2, >= 2.2.2)
19
+ coderay (1.1.3)
20
+ concurrent-ruby (1.1.7)
21
+ diff-lcs (1.4.4)
22
+ dry-configurable (0.11.6)
22
23
  concurrent-ruby (~> 1.0)
23
24
  dry-core (~> 0.4, >= 0.4.7)
24
25
  dry-equalizer (~> 0.2)
25
26
  dry-container (0.7.2)
26
27
  concurrent-ruby (~> 1.0)
27
28
  dry-configurable (~> 0.1, >= 0.1.3)
28
- dry-core (0.4.9)
29
+ dry-core (0.4.10)
29
30
  concurrent-ruby (~> 1.0)
30
31
  dry-equalizer (0.3.0)
31
32
  dry-inflector (0.2.0)
32
- dry-logic (1.0.6)
33
+ dry-logic (1.0.8)
33
34
  concurrent-ruby (~> 1.0)
34
35
  dry-core (~> 0.2)
35
36
  dry-equalizer (~> 0.2)
@@ -41,35 +42,37 @@ GEM
41
42
  dry-inflector (~> 0.1, >= 0.1.2)
42
43
  dry-logic (~> 1.0, >= 1.0.2)
43
44
  hirb (0.7.3)
44
- i18n (1.8.2)
45
+ i18n (1.8.5)
45
46
  concurrent-ruby (~> 1.0)
46
47
  method_profiler (2.0.1)
47
48
  hirb (>= 0.6.0)
48
- method_source (0.9.2)
49
- minitest (5.14.0)
50
- nxt_registry (0.1.5)
49
+ method_source (1.0.0)
50
+ minitest (5.14.2)
51
+ nxt_init (0.1.5)
51
52
  activesupport
52
- pry (0.12.2)
53
- coderay (~> 1.1.0)
54
- method_source (~> 0.9.0)
53
+ nxt_registry (0.3.2)
54
+ activesupport
55
+ pry (0.13.1)
56
+ coderay (~> 1.1)
57
+ method_source (~> 1.0)
55
58
  rake (12.3.3)
56
- rspec (3.8.0)
57
- rspec-core (~> 3.8.0)
58
- rspec-expectations (~> 3.8.0)
59
- rspec-mocks (~> 3.8.0)
60
- rspec-core (3.8.2)
61
- rspec-support (~> 3.8.0)
62
- rspec-expectations (3.8.4)
59
+ rspec (3.10.0)
60
+ rspec-core (~> 3.10.0)
61
+ rspec-expectations (~> 3.10.0)
62
+ rspec-mocks (~> 3.10.0)
63
+ rspec-core (3.10.0)
64
+ rspec-support (~> 3.10.0)
65
+ rspec-expectations (3.10.0)
63
66
  diff-lcs (>= 1.2.0, < 2.0)
64
- rspec-support (~> 3.8.0)
65
- rspec-mocks (3.8.1)
67
+ rspec-support (~> 3.10.0)
68
+ rspec-mocks (3.10.0)
66
69
  diff-lcs (>= 1.2.0, < 2.0)
67
- rspec-support (~> 3.8.0)
68
- rspec-support (3.8.2)
70
+ rspec-support (~> 3.10.0)
71
+ rspec-support (3.10.0)
69
72
  thread_safe (0.3.6)
70
- tzinfo (1.2.7)
73
+ tzinfo (1.2.8)
71
74
  thread_safe (~> 0.1)
72
- zeitwerk (2.3.0)
75
+ zeitwerk (2.4.1)
73
76
 
74
77
  PLATFORMS
75
78
  ruby
data/README.md CHANGED
@@ -16,138 +16,185 @@ Or install it yourself as:
16
16
 
17
17
  $ gem install nxt_schema
18
18
 
19
- ## Usage
19
+ ## What it is for?
20
+
21
+ NxtSchema is a type casting and validation framework that allows you to validate and type cast arbitrary nested
22
+ structures of data.
23
+
24
+ ### Usage
20
25
 
21
26
  ```ruby
22
- # Schema with hash root
23
- schema = NxtSchema.root(:company) do
24
- requires(:name, :String)
25
- requires(:value, :Integer).maybe(nil)
26
- present(:stock_options, :Bool).default(false)
27
-
28
- schema(:address) do
29
- requires(:street, :String)
30
- requires(:street_number, :Integer)
31
- end
27
+ PERSON = NxtSchema.schema(:person) do
28
+ node(:first_name, :String)
29
+ node(:last_name, :String)
30
+ node(:email, :String, optional: true).validate(:includes, '@')
31
+ end
32
32
 
33
- # Use nodes to create an array of typed nodes
34
- # The following simple means an array of strings
35
- nodes(:products) do
36
- node(:product, :String)
37
- end
33
+ input = {
34
+ first_name: 'Andy',
35
+ last_name: 'Robecke',
36
+ email: 'andreas@robecke.de'
37
+ }
38
38
 
39
-
40
- nodes(:employees) do
41
- hash(:employee) do
42
- POSITIONS = %w[senior junior intern]
39
+ result = PERSON.apply(input: input)
43
40
 
44
- requires(:first_name, :String)
45
- requires(:last_name, :String)
46
- optional(:email, :String).validate(:format, /\A.*@.*\z/)
47
- requires(:position, NxtSchema::Types::Enums[*POSITIONS])
48
- end
49
- end
50
- end
51
-
52
- # Schema with array root
53
- schema = NxtSchema.roots(:companies) do
54
- schema(:company) do
55
- requires(:name, :String)
56
- requires(:value, :Integer).maybe(nil)
57
- end
58
- end
41
+ result.valid? # => true
42
+ result.output # => input
43
+ ```
59
44
 
60
- schema.apply(your: 'values here')
61
- schema.errors # { 'name.spaced.key': ['all the errors'] }
45
+ ### Nodes
46
+
47
+ A schema consists of a number of nodes. Every node has a name and an associated type for casting it's input when the
48
+ schema is applied. Schemas can consist of 4 different kinds of nodes:
49
+
50
+ ```ruby
51
+ NxtSchema::Node::Schema # => Hash of values
52
+ NxtSchema::Node::Collection # => Array of values
53
+ NxtSchema::Node::AnyOf # => Any of the defined schemas
54
+ NxtSchema::Node::Leaf # => Node without sub nodes
62
55
  ```
63
56
 
64
- ### DSL
57
+ The kind of node dictates how the schema is applied to the input. On the root level the following methods are available
58
+ to create schemas:
65
59
 
66
- Create a new schema with `NxtSchema.root { ... }` or in case you have an array node as root,
67
- use `NxtSchema.roots { ... }`. Within the schema you can create node simply with the `node(name, type_or_node, **options)`
68
- method. Each node requires a name and a type and accepts additional options. Node are required per default.
69
- But you can make them optional by providing the optional option.
60
+ ```ruby
61
+ NxtSchema.schema { ... } # => Create a schema node
62
+ NxtSchema.collection { ... } # => Create an array of nodes
63
+ NxtSchema.any_of { ... } # => Create a collection of allowed schemas
64
+ ```
70
65
 
71
- #### Nodes
66
+ #### Node predicate aliases
67
+
68
+ Of course these nodes can be combined and nested in arbitrary manner. When defining nodes within a schema, nodes are
69
+ always required per default. You can create nodes with the node method or several useful helper methods.
72
70
 
73
71
  ```ruby
74
- NxtSchema.root do
75
- node(:first_name, :String)
76
- node(:last_name, :String, optional: true)
77
- node(:email, :String, presence: true)
72
+ NxtSchema.schema(:person) do
73
+ required(:first_name, :String) # => same as node(:first_name, :String)
74
+ optional(:last_name, :String) # => same as node(:first_name, :String, optional: true)
75
+ omnipresent(:email, :String) # => same as node(:first_name, :String, omnipresent: true)
78
76
  end
79
77
  ```
80
78
 
81
- In order to make the schema more readable you can make use of several predicate aliases to create required, optional or
82
- (omni)present nodes.
79
+ **NOTE: The methods above only apply to the keys of your schema and do not make any assumptions about values!**
83
80
 
84
- #### Predicate aliases
81
+ In other word this means that making a node optional only makes your node optional. When your input contains the key but
82
+ the value is nil, you will still get an error in case there is no default or maybe expression that applies. Omnipresent
83
+ node also only inject the node into the schema but do not inject a default value. In order to inject a key with value
84
+ into a schema you also have to combine the node predicates with default value method described below. For clarification
85
+ check out the examples below:
85
86
 
86
87
  ```ruby
87
- NxtSchema.root do
88
- required(:first_name, :String)
89
- optional(:last_name, :String)
90
- present(:email, :String)
88
+ schema = NxtSchema.schema(:person) do
89
+ optional(:email, :String)
91
90
  end
91
+
92
+ result = schema.apply(input: { email: nil })
93
+ result.errors # => {"person.email"=>["nil violates constraints (type?(String, nil) failed)"]}
94
+ result.output # => {:email=>nil}
95
+
96
+ result = schema.apply(input: {})
97
+ result.errors # => {}
98
+ result.output # => {}
92
99
  ```
93
100
 
94
- ### Nodes
101
+ ```ruby
102
+ schema = NxtSchema.schema(:person) do
103
+ optional(:email, :String).default('andreas@robecke.de')
104
+ end
95
105
 
96
- The following types of nodes exist
106
+ result = schema.apply(input: { email: nil })
107
+ result.errors # => {}
97
108
 
98
- #### Schema Nodes
109
+ result = schema.apply(input: {})
110
+ result.errors # => {}
111
+ result.output # => {:email=>"andreas@robecke.de"}
112
+ ```
99
113
 
100
114
  ```ruby
101
- # Create schema nodes with:
102
- required(:test, :Schema) do ... end
103
- schema(:test) do ... end
104
- hash(:test) do ... end
105
- ```
115
+ schema = NxtSchema.schema(:person) do
116
+ omnipresent(:email, :String)
117
+ end
106
118
 
107
- #### Collection Nodes
119
+ result = schema.apply(input: {})
120
+ result.errors # => {}
121
+ result.output # => {:email=>NxtSchema::MissingInput}
122
+ ```
108
123
 
109
124
  ```ruby
110
- # Create collection (array) nodes with:
111
- required(:test, :Collection) do ... end
112
-
113
- nodes(:test) do
114
- # For type checking of array items you can simply add a node with the expected type.
115
- # As always you need to give it a name. This would result in an array of string items
116
- required(:item, :String)
125
+ schema = NxtSchema.schema(:person) do
126
+ # make sure a node is always present and at least nil even though the type is String
127
+ omnipresent(:email, :String).default(nil).maybe(:nil?)
117
128
  end
118
129
 
119
- array(:test) do ... end
130
+ result = schema.apply(input: {})
131
+ result.errors # => {}
132
+ result.output # => {:email=>nil}
133
+
134
+ result = schema.apply(input: { email: 'andreas@robecke.de' })
135
+ result.errors # => {}
136
+ result.output # => {:email=>"andreas@robecke.de"}
120
137
  ```
121
138
 
122
- #### Leaf Nodes
139
+ ##### Conditionally optional nodes
140
+
141
+ You can also pass a proc as the optional option. This will add a validator to the parent node that makes sure thar the
142
+ key is present if the optional condition does not apply.
123
143
 
124
144
  ```ruby
125
- # Create leaf nodes with a basic type
126
- required(:test, :String) do ... end
127
- ```
145
+ schema = NxtSchema.schema(:contact) do
146
+ required(:first_name, :String)
147
+ required(:last_name, :String)
148
+ node(:email, :String, optional: ->(node) { node.up[:last_name].input == 'Robecke' })
149
+ end
150
+
151
+ result = schema.apply(input: { first_name: 'Andy', last_name: 'Other' })
152
+ result.errors # => {"contact"=>["Required key :email is missing"]}
153
+
154
+ result = schema.apply(input: { first_name: 'Andy', last_name: 'Robecke' })
155
+ result.errors # => {}
156
+ ```
157
+
158
+ #### Combining Schemas
128
159
 
129
- #### Struct Nodes
160
+ You can also simply reuse a schema by passing it to the node method as the type of a node. When doing so the schema
161
+ will be cloned with the same options and configuration as the schema passed in.
130
162
 
131
163
  ```ruby
132
- # Create structs from hash inputs
133
- struct(:test) do ... end
164
+ ADDRESS = NxtSchema.schema(:address) do
165
+ required(:street, :String)
166
+ required(:town, :String)
167
+ required(:zip_code, :String)
168
+ end
169
+
170
+ PERSON = NxtSchema.schema(:person) do
171
+ required(:first_name, :String)
172
+ required(:last_name, :String)
173
+ optional(:address, ADDRESS)
174
+ end
134
175
  ```
135
176
 
136
177
  ### Types
137
178
 
138
- The type system is built with dry-types from the amazing https://dry-rb.org/ eco system. Even though dry-types also
179
+ The type system is built with dry-types from the amazing https://dry-rb.org eco system. Even though dry-types also
139
180
  offers features such as default values for types as well as maybe types, these features are built directly into
140
- NxtSchema. Dry.rb also has a gem for schemas and another one dedicated to validations. You should probably
141
- check those out! However, in NxtSchema every node has a type and you can either provide a symbol that will be resolved
142
- through the type system of the schema. But you can also directly provide an instance of dry type and thus use your
143
- custom types.
181
+ NxtSchema.
182
+
183
+ Please note that Dry.rb also has a gem for schemas: https://dry-rb.org/gems/dry-schema and another one dedicated to
184
+ validations explicitly https://dry-rb.org/gems/dry-validation. You should probably go and check those out! NxtSchema
185
+ is trying to implement a simpler solution that is easy to understand yet powerful enough for most tasks.
186
+
187
+ In NxtSchema every node has a type and you can either provide a symbol that will be resolved
188
+ through the type system of the schema or you can directly provide an instance of dry type and thus use your
189
+ custom types. This means you can basically build any kind of objects such as structs and models from your data and
190
+ you are not limited to just hashes arrays and primitives.
144
191
 
145
192
  #### Default type system
146
193
 
147
194
  You can tell your schema which default type system it should use. Dry-Types comes with a few built in type systems.
148
195
  Per default NxtSchema will use nominal types if not specified otherwise. If the type cannot be resolved from the default
149
- type system that was specified, NxtSchema will again try to fallback to nominal types. In theory you can provide
150
- a separate type system per node if that's what you want :-D
196
+ type system that was specified NxtSchema will always fallback to nominal types. In theory you can provide
197
+ a separate type system per node if that's what you need.
151
198
 
152
199
  ```ruby
153
200
  NxtSchema.root do
@@ -188,7 +235,7 @@ NxtSchema.register_type(
188
235
  # once registered you can use the type in your schema
189
236
 
190
237
  NxtSchema.root(:company) do
191
- required(:name, NxtSchema::Types::MyCustomStrippedString)
238
+ required(:name, :MyCustomStrippedString)
192
239
  end
193
240
  ```
194
241
 
@@ -198,34 +245,41 @@ end
198
245
 
199
246
  ```ruby
200
247
  # Define default values as options or with the default method
201
- required(:test, :String).default(value_or_proc)
202
- required(:test, :String, default: value_or_proc) do ... end
248
+ required(:test, :DateTime).default(-> { Time.current })
249
+ required(:test, :String, default: 'Andy')
203
250
  ```
204
251
 
205
252
  #### Maybe values
206
253
 
207
- Allow specific values that are not being coerced
254
+ With maybe you can allow your values to be of a certain type and halt conversion. **Note: This means that your output
255
+ will simply be set to the input without coercing the value!**
208
256
 
209
257
  ```ruby
210
258
  # Define maybe values (values that do not match the type)
211
- required(:test, :String).maybe(value_or_proc)
212
- required(:test, :String, maybe: value_or_proc) do ... end
259
+ required(:test, :String).maybe(:nil?)
260
+
261
+ nodes(:tests).maybe(:empty?) do # will allow the collection to be empty
262
+ required(:test, :String)
263
+ end
264
+
213
265
  ```
214
266
 
215
267
  ### Validations
216
268
 
217
269
  NxtSchema comes with a simple validation system and ships with a small set of useful validators. Every node in a schema
218
270
  implements the `:validate` method. Similar to ActiveModel::Validations it allows you to simply add errors to a node
219
- based on some condition.
271
+ based on some condition. When the node is yielded to your validation proc you have access to the nodes input with
272
+ `node.input` and `node.index` when the node is within a collection of nodes as well as `node.name`. Furthermore you have
273
+ access to the context that was passed in when defining the schema or passed to the apply method later.
220
274
 
221
275
  ```ruby
222
- # Simple validation
223
- required(:test, :String).validate -> (node, value) { node.add_error("#{value} is not valid") if value == 'not allowed' }
276
+ # Simple custom validation
277
+ required(:test, :String).validate(-> (node) { node.add_error("#{node.input} is not valid") if node.input == 'not allowed' })
224
278
  # Built in validations
225
279
  required(:test, :String).validate(:attribute, :size, ->(s) { s < 7 })
226
- required(:test, :String).validate(:equality, 'same')
227
- required(:test, :String).validate(:excluded, %w[not_allowed]) # excluded in the target: %w[not_allowed]
228
- required(:test, :String).validate(:included, %w[allowed]) # included in the target: %w[allowed]
280
+ required(:test, :String).validate(:equal_to, 'same')
281
+ required(:test, :String).validate(:excluded_in, %w[not_allowed]) # excluded in the target: %w[not_allowed]
282
+ required(:test, :String).validate(:included_in, %w[allowed]) # included in the target: %w[allowed]
229
283
  required(:test, :Array).validate(:excludes, 'excluded') # array value itself must exclude 'excluded'
230
284
  required(:test, :Array).validate(:includes, 'included') # array value itself must include 'included'
231
285
  required(:test, :Integer).validate(:greater_than, 1)
@@ -323,7 +377,7 @@ schema = NxtSchema.root(additional_keys: :allow) do
323
377
  required(:test, :String)
324
378
  end
325
379
 
326
- schema.apply(test: 'getsafe', other: 'Heidelberg')
380
+ schema.apply(input: {test: 'getsafe', other: 'Heidelberg'})
327
381
  schema.valid? # => true
328
382
  schema.value # => { test: 'getsafe', other: 'Heidelberg' }
329
383
  ```
@@ -334,12 +388,12 @@ You may want to transform the keys from your input. Therefore specify the transf
334
388
  when you want your schema to return only symbolized keys for example.
335
389
 
336
390
  ```ruby
337
- schema = NxtSchema.root(transform_keys: :to_sym) do
391
+ schema = NxtSchema.root(transform_keys: ->(key) { key.to_sym}) do
338
392
  required(:test, :String)
339
393
  end
340
394
 
341
- schema.apply('test' => 'getsafe') # => {:test=>"getsafe"}
342
- schema.apply(test: 'getsafe') # => {:test=>"getsafe"}
395
+ schema.apply(input: { 'test' => 'getsafe' }) # => {:test=>"getsafe"}
396
+ schema.apply(input: { test: 'getsafe' }) # => {:test=>"getsafe"}
343
397
  ```
344
398
 
345
399
  #### Adding meta data to nodes
@@ -356,10 +410,18 @@ schema = NxtSchema.root do
356
410
  required(:test, :String).meta(ERROR_MESSAGES).validate ->(node) { node.add_error(node.meta.fetch(node.name)) }
357
411
  end
358
412
 
359
- schema.apply(test: 'getsafe')
413
+ schema.apply(input: { test: 'getsafe' })
360
414
  schema.error # {"root.test"=>["This is always broken"]}
361
415
  ```
362
416
 
417
+ #### Contexts
418
+
419
+ # TODO
420
+
421
+ ##### Build time
422
+
423
+ ##### Apply time
424
+
363
425
  ## Development
364
426
 
365
427
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -368,22 +430,30 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
368
430
 
369
431
  ## Contributing
370
432
 
371
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/nxt_schema.
433
+ Bug reports and pull requests are welcome on GitHub at https://github.com/getand.
372
434
 
373
435
  ## License
374
436
 
375
437
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
376
438
 
377
- ### TODO:
378
-
379
- - Flatten schema errors like validation errors
380
- - Conditionally required keys:
381
- required bool => required
382
- required conditionally => condition applies => required
383
- required conditionally => condition does not apply => not allowed
384
-
385
- - Explain the difference between array nodes and typed array nodes
386
- - Should we translate coercion errors as well?
387
- - Test the different scenarios of merging schemas array, hash, ...
388
- - Structure Errors
389
- - NxtSchema::Json => Use json types, maybe even parse Json with Oj
439
+ ## TODO:
440
+
441
+ - Allow to disable validation when applying
442
+ --> Are there attributes that should be moved to apply time?
443
+ - Should we have a global and a local registry for validators?
444
+ --> Would be cool to register things for the schema only
445
+ --> Would be cool if this was extendable
446
+ - Do we need all off in order to combine multiple schemas?
447
+ - Think about a good implementation of params framework for controllers
448
+
449
+ ```ruby
450
+ PARAMS = NxtRegistry::Registry.new do
451
+ register(:create) do
452
+ NxtSchema.params do
453
+
454
+ end
455
+ end
456
+ end
457
+
458
+ PARAMS.resolve(:create).apply(input: params)
459
+ ```