nxt_schema 0.1.0 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -0
  3. data/Gemfile +0 -1
  4. data/Gemfile.lock +40 -42
  5. data/README.md +267 -121
  6. data/lib/nxt_schema.rb +60 -51
  7. data/lib/nxt_schema/callable.rb +21 -55
  8. data/lib/nxt_schema/dsl.rb +41 -31
  9. data/lib/nxt_schema/error.rb +4 -0
  10. data/lib/nxt_schema/errors/{error.rb → coercion_error.rb} +1 -2
  11. data/lib/nxt_schema/errors/invalid.rb +16 -0
  12. data/lib/nxt_schema/errors/invalid_options.rb +6 -0
  13. data/lib/nxt_schema/node/any_of.rb +39 -0
  14. data/lib/nxt_schema/node/base.rb +66 -267
  15. data/lib/nxt_schema/node/collection.rb +40 -56
  16. data/lib/nxt_schema/node/error_store.rb +41 -0
  17. data/lib/nxt_schema/node/errors/schema_error.rb +15 -0
  18. data/lib/nxt_schema/node/errors/validation_error.rb +15 -0
  19. data/lib/nxt_schema/node/leaf.rb +8 -36
  20. data/lib/nxt_schema/node/schema.rb +70 -103
  21. data/lib/nxt_schema/registry.rb +12 -74
  22. data/lib/nxt_schema/registry/proxy.rb +21 -0
  23. data/lib/nxt_schema/template/any_of.rb +50 -0
  24. data/lib/nxt_schema/template/base.rb +220 -0
  25. data/lib/nxt_schema/template/collection.rb +23 -0
  26. data/lib/nxt_schema/template/has_sub_nodes.rb +87 -0
  27. data/lib/nxt_schema/template/leaf.rb +13 -0
  28. data/lib/nxt_schema/template/maybe_evaluator.rb +28 -0
  29. data/lib/nxt_schema/template/on_evaluator.rb +25 -0
  30. data/lib/nxt_schema/template/schema.rb +22 -0
  31. data/lib/nxt_schema/template/sub_nodes.rb +22 -0
  32. data/lib/nxt_schema/template/type_resolver.rb +39 -0
  33. data/lib/nxt_schema/template/type_system_resolver.rb +22 -0
  34. data/lib/nxt_schema/types.rb +7 -4
  35. data/lib/nxt_schema/undefined.rb +4 -2
  36. data/lib/nxt_schema/validators/{equality.rb → equal_to.rb} +2 -2
  37. data/lib/nxt_schema/validators/error_messages.rb +42 -0
  38. data/lib/nxt_schema/{error_messages → validators/error_messages}/en.yaml +6 -5
  39. data/lib/nxt_schema/validators/{excluded.rb → excluded_in.rb} +1 -1
  40. data/lib/nxt_schema/validators/{included.rb → included_in.rb} +1 -1
  41. data/lib/nxt_schema/validators/includes.rb +1 -1
  42. data/lib/nxt_schema/validators/optional_node.rb +11 -6
  43. data/lib/nxt_schema/validators/registry.rb +1 -7
  44. data/lib/nxt_schema/{node → validators}/validate_with_proxy.rb +3 -3
  45. data/lib/nxt_schema/validators/validator.rb +2 -2
  46. data/lib/nxt_schema/version.rb +1 -1
  47. data/nxt_schema.gemspec +1 -0
  48. metadata +44 -21
  49. data/lib/nxt_schema/callable_or_value.rb +0 -72
  50. data/lib/nxt_schema/error_messages.rb +0 -40
  51. data/lib/nxt_schema/errors.rb +0 -4
  52. data/lib/nxt_schema/errors/invalid_options_error.rb +0 -5
  53. data/lib/nxt_schema/errors/schema_not_applied_error.rb +0 -5
  54. data/lib/nxt_schema/node/constructor.rb +0 -9
  55. data/lib/nxt_schema/node/default_value_evaluator.rb +0 -20
  56. data/lib/nxt_schema/node/error.rb +0 -13
  57. data/lib/nxt_schema/node/has_subnodes.rb +0 -97
  58. data/lib/nxt_schema/node/maybe_evaluator.rb +0 -23
  59. data/lib/nxt_schema/node/template_store.rb +0 -15
  60. data/lib/nxt_schema/node/type_resolver.rb +0 -24
@@ -0,0 +1,13 @@
1
+ module NxtSchema
2
+ module Template
3
+ class Leaf < Template::Base
4
+ def initialize(name:, type: :String, parent_node:, **options, &block)
5
+ super
6
+ end
7
+
8
+ def leaf?
9
+ true
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,28 @@
1
+ module NxtSchema
2
+ module Template
3
+ class MaybeEvaluator
4
+ def initialize(value:)
5
+ @value = value
6
+ end
7
+
8
+ def call(target = nil, *args)
9
+ evaluator = evaluator(target, *args)
10
+
11
+ if evaluator.value?
12
+ # When a value was given we check if this equals to the input
13
+ evaluator.call == target
14
+ else
15
+ evaluator.call
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def evaluator(target, *args)
22
+ Callable.new(value, target, *args)
23
+ end
24
+
25
+ attr_reader :value
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,25 @@
1
+ module NxtSchema
2
+ module Template
3
+ class OnEvaluator
4
+ def initialize(condition:, value:)
5
+ @condition = condition
6
+ @value = value
7
+ end
8
+
9
+ def call(target = nil, *args, &block)
10
+ return unless condition_applies?(target, *args)
11
+
12
+ result = Callable.new(value, target, *args).call
13
+ block.yield(result)
14
+ end
15
+
16
+ private
17
+
18
+ def condition_applies?(target, *args)
19
+ Callable.new(condition, target, *args).call
20
+ end
21
+
22
+ attr_reader :condition, :value
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ module NxtSchema
2
+ module Template
3
+ class Schema < Template::Base
4
+ include HasSubNodes
5
+
6
+ DEFAULT_TYPE = NxtSchema::Types::Strict::Hash
7
+
8
+ def initialize(name:, type: DEFAULT_TYPE, parent_node:, **options, &block)
9
+ super
10
+ ensure_sub_nodes_present
11
+ end
12
+
13
+ def optional(name, node_or_type_of_node, **options, &block)
14
+ node(name, node_or_type_of_node, **options.merge(optional: true), &block)
15
+ end
16
+
17
+ def omnipresent(name, node_or_type_of_node, **options, &block)
18
+ node(name, node_or_type_of_node, **options.merge(omnipresent: true), &block)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ module NxtSchema
2
+ module Template
3
+ class SubNodes < ::Hash
4
+ def initialize
5
+ super
6
+ transform_keys { |k| k.to_sym }
7
+ end
8
+
9
+ def add(node)
10
+ node_name = node.name
11
+ ensure_node_name_free(node_name)
12
+ self[node_name] = node
13
+ end
14
+
15
+ def ensure_node_name_free(name)
16
+ return unless key?(name)
17
+
18
+ raise KeyError, "Node with name '#{name}' already exists! Node names must be unique!"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,39 @@
1
+ module NxtSchema
2
+ module Template
3
+ class TypeResolver
4
+ def resolve(type_system, type)
5
+ @resolve ||= {}
6
+ @resolve[type] ||= begin
7
+ if type.is_a?(Symbol)
8
+ resolve_type_from_symbol(type, type_system)
9
+ elsif type.respond_to?(:call)
10
+ type
11
+ else
12
+ raise_type_not_resolvable_error(type)
13
+ end
14
+ rescue NxtRegistry::Errors::KeyNotRegisteredError => error
15
+ raise_type_not_resolvable_error(type)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def resolve_type_from_symbol(type, type_system)
22
+ classified_type = type.to_s.classify
23
+
24
+ return type_system.const_get(classified_type) if type_defined_in_type_system?(type, type_system)
25
+ return NxtSchema::Types::Nominal.const_get(classified_type) if type_defined_in_type_system?(type, NxtSchema::Types::Nominal)
26
+
27
+ NxtSchema::Types.registry(:types).resolve!(type)
28
+ end
29
+
30
+ def type_defined_in_type_system?(type, type_system)
31
+ type_system.constants.include?(type)
32
+ end
33
+
34
+ def raise_type_not_resolvable_error(type)
35
+ raise ArgumentError, "Can't resolve type: #{type}"
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,22 @@
1
+ module NxtSchema
2
+ module Template
3
+ class TypeSystemResolver
4
+ include NxtInit
5
+ attr_init :node
6
+
7
+ delegate_missing_to :node
8
+
9
+ def call
10
+ type_system = options.fetch(:type_system) { parent_node&.type_system }
11
+
12
+ if type_system.is_a?(Module)
13
+ type_system
14
+ elsif type_system.is_a?(Symbol) || type_system.is_a?(String)
15
+ "NxtSchema::Types::#{type_system.to_s.classify}".constantize
16
+ else
17
+ NxtSchema::Types
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,10 +1,13 @@
1
1
  module NxtSchema
2
2
  module Types
3
3
  include Dry.Types()
4
+ extend NxtRegistry
4
5
 
5
- StrippedString = Strict::String.constructor(->(string) { string&.strip })
6
- StrippedNonBlankString = StrippedString.constrained(min_size: 1)
7
- Enums = -> (*values) { Strict::String.enum(*values) } # Use as NxtSchema::Types::Enums[*ROLES]
8
- SymbolizedEnums = -> (*values) { Coercible::Symbol.enum(*values) } # Use as NxtSchema::Types::SymboleEnums[*ROLES]
6
+ registry(:types, call: false) do
7
+ register(:StrippedString, Strict::String.constructor(->(string) { string&.strip }))
8
+ register(:LengthyStrippedString, resolve!(:StrippedString).constrained(min_size: 1))
9
+ register(:Enum, -> (*values) { Strict::String.enum(*values) })
10
+ register(:SymbolizedEnum, -> (*values) { Coercible::Symbol.enum(*values) })
11
+ end
9
12
  end
10
13
  end
@@ -1,7 +1,9 @@
1
1
  module NxtSchema
2
2
  class Undefined
3
3
  def inspect
4
- 'undefined'
4
+ self.class.name
5
5
  end
6
+
7
+ alias to_s inspect
6
8
  end
7
- end
9
+ end
@@ -5,7 +5,7 @@ module NxtSchema
5
5
  @expectation = expectation
6
6
  end
7
7
 
8
- register_as :equality, :eql
8
+ register_as :equal_to, :eql
9
9
  attr_reader :expectation
10
10
 
11
11
  # Query for equality validator(:equality, 3)
@@ -13,7 +13,7 @@ module NxtSchema
13
13
 
14
14
  def build
15
15
  lambda do |node, value|
16
- expected_value = expectation.respond_to?(:call) ? Callable.new(expectation).call(node, value) : expectation
16
+ expected_value = Callable.new(expectation, nil, value).call
17
17
 
18
18
  if value == expected_value
19
19
  true
@@ -0,0 +1,42 @@
1
+ module NxtSchema
2
+ module Validators
3
+ class ErrorMessages
4
+ class << self
5
+ def values
6
+ @values ||= {}
7
+ end
8
+
9
+ def values=(value)
10
+ @values = value
11
+ end
12
+
13
+ def load(paths = files)
14
+ Array(paths).each do |path|
15
+ new_values = YAML.load(ERB.new(File.read(path)).result).with_indifferent_access
16
+ self.values = values.deep_merge!(new_values)
17
+ end
18
+ end
19
+
20
+ def resolve(locale, key, **options)
21
+ message = begin
22
+ values.fetch(locale).fetch(key)
23
+ rescue KeyError
24
+ raise "Could not resolve error message for #{locale}->#{key}"
25
+ end
26
+
27
+ message % options
28
+ end
29
+
30
+ def files
31
+ @files ||= begin
32
+ files = Dir.entries(File.expand_path('../error_messages/', __FILE__)).map do |filename|
33
+ File.expand_path("../error_messages/#{filename}", __FILE__)
34
+ end
35
+
36
+ files.select { |f| !File.directory? f }
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,15 +1,16 @@
1
1
  en:
2
- required_key_missing: "Required key :%{key} is missing in %{target}"
3
- additional_keys_detected: "Additional keys %{keys} not allowed in %{target}"
2
+ required_key_missing: "Required key :%{key} is missing"
3
+ additional_keys_detected: "Additional keys %{keys} not allowed"
4
4
  attribute: "%{attribute} has invalid %{attribute_name} attribute of %{value}"
5
- equality: "%{actual} does not equal %{expected}"
5
+ equal_to: "%{actual} does not equal %{expected}"
6
6
  excludes: "%{value} cannot contain %{target}"
7
7
  includes: "%{value} must include %{target}"
8
- excluded: "%{value} must be excluded in %{target}"
9
- included: "%{value} must be included in %{target}"
8
+ excluded_in: "%{value} must be excluded in %{target}"
9
+ included_in: "%{value} must be included in %{target}"
10
10
  greater_than: "%{value} must be greater than %{threshold}"
11
11
  greater_than_or_equal: "%{value} must be greater than or equal to %{threshold}"
12
12
  less_than: "%{value} must be less than %{threshold}"
13
13
  less_than_or_equal: "%{value} must be less than or equal to %{threshold}"
14
14
  pattern: "%{value} must match pattern %{pattern}"
15
15
  query: "%{value}.%{query} was %{actual} and must be true"
16
+ emptiness: "%{value} cannot not be empty"
@@ -5,7 +5,7 @@ module NxtSchema
5
5
  @target = target
6
6
  end
7
7
 
8
- register_as :excluded
8
+ register_as :excluded_in
9
9
  attr_reader :target
10
10
 
11
11
  def build
@@ -5,7 +5,7 @@ module NxtSchema
5
5
  @target = target
6
6
  end
7
7
 
8
- register_as :included
8
+ register_as :included_in
9
9
  attr_reader :target
10
10
 
11
11
  def build
@@ -13,7 +13,7 @@ module NxtSchema
13
13
  if value.include?(target)
14
14
  true
15
15
  else
16
- message = translate_error(node.locale, value: value, target: target)
16
+ message = translate_error(coerced?.locale, value: value, target: target)
17
17
  node.add_error(message)
18
18
  end
19
19
  end
@@ -13,12 +13,17 @@ module NxtSchema
13
13
  lambda do |node, value|
14
14
  args = [node, value]
15
15
 
16
- if conditional.call(*args.take(conditional.arity))
17
- true
18
- else
19
- message = ErrorMessages.resolve(node.locale, :required_key_missing, key: missing_key, target: node.value)
20
- node.add_error(message)
21
- end
16
+ return if conditional.call(*args.take(conditional.arity))
17
+ return if node.send(:keys).include?(missing_key.to_sym)
18
+
19
+ message = ErrorMessages.resolve(
20
+ node.locale,
21
+ :required_key_missing,
22
+ key: missing_key,
23
+ target: node.input
24
+ )
25
+
26
+ node.add_error(message)
22
27
  end
23
28
  end
24
29
  end
@@ -1,11 +1,5 @@
1
1
  module NxtSchema
2
2
  module Validators
3
- class Registry
4
- extend NxtRegistry
5
-
6
- VALIDATORS = registry :validators, call: false do
7
-
8
- end
9
- end
3
+ REGISTRY = NxtRegistry::Registry.new(call: false)
10
4
  end
11
5
  end
@@ -1,5 +1,5 @@
1
1
  module NxtSchema
2
- module Node
2
+ module Validator
3
3
  class ValidateWithProxy
4
4
  def initialize(node)
5
5
  @node = node
@@ -33,8 +33,8 @@ module NxtSchema
33
33
  attr_reader :aggregated_errors
34
34
 
35
35
  def validator(key, *args)
36
- validator = node.validator(key, *args)
37
- validator.call(self, node.value)
36
+ validator = node.node.send(:validator, key, *args)
37
+ validator.call(self, node.input)
38
38
  end
39
39
  end
40
40
  end
@@ -3,14 +3,14 @@ module NxtSchema
3
3
  class Validator
4
4
  def self.register_as(*keys)
5
5
  keys.each do |key|
6
- NxtSchema::Validators::Registry::VALIDATORS.register(key, self)
6
+ NxtSchema::Validators::REGISTRY.register(key, self)
7
7
  end
8
8
 
9
9
  define_method('key') { @key ||= keys.first }
10
10
  end
11
11
 
12
12
  def translate_error(locale, **options)
13
- NxtSchema::ErrorMessages.resolve(locale, key, **options)
13
+ NxtSchema::Validators::ErrorMessages.resolve(locale, key, **options)
14
14
  end
15
15
  end
16
16
  end
@@ -1,3 +1,3 @@
1
1
  module NxtSchema
2
- VERSION = "0.1.0"
2
+ VERSION = "1.0.2"
3
3
  end
data/nxt_schema.gemspec CHANGED
@@ -38,6 +38,7 @@ Gem::Specification.new do |spec|
38
38
  spec.add_dependency "activesupport"
39
39
  spec.add_dependency "dry-types"
40
40
  spec.add_dependency "nxt_registry"
41
+ spec.add_dependency "nxt_init"
41
42
  spec.add_development_dependency "bundler", "~> 1.17"
42
43
  spec.add_development_dependency "rake", "~> 12.3.3"
43
44
  spec.add_development_dependency "rspec", "~> 3.0"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nxt_schema
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andreas Robecke
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-20 00:00:00.000000000 Z
11
+ date: 2021-03-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: nxt_init
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: bundler
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -131,6 +145,7 @@ extra_rdoc_files: []
131
145
  files:
132
146
  - ".gitignore"
133
147
  - ".rspec"
148
+ - ".ruby-version"
134
149
  - ".travis.yml"
135
150
  - Gemfile
136
151
  - Gemfile.lock
@@ -141,37 +156,44 @@ files:
141
156
  - bin/setup
142
157
  - lib/nxt_schema.rb
143
158
  - lib/nxt_schema/callable.rb
144
- - lib/nxt_schema/callable_or_value.rb
145
159
  - lib/nxt_schema/dsl.rb
146
- - lib/nxt_schema/error_messages.rb
147
- - lib/nxt_schema/error_messages/en.yaml
148
- - lib/nxt_schema/errors.rb
149
- - lib/nxt_schema/errors/error.rb
150
- - lib/nxt_schema/errors/invalid_options_error.rb
151
- - lib/nxt_schema/errors/schema_not_applied_error.rb
160
+ - lib/nxt_schema/error.rb
161
+ - lib/nxt_schema/errors/coercion_error.rb
162
+ - lib/nxt_schema/errors/invalid.rb
163
+ - lib/nxt_schema/errors/invalid_options.rb
152
164
  - lib/nxt_schema/node.rb
165
+ - lib/nxt_schema/node/any_of.rb
153
166
  - lib/nxt_schema/node/base.rb
154
167
  - lib/nxt_schema/node/collection.rb
155
- - lib/nxt_schema/node/constructor.rb
156
- - lib/nxt_schema/node/default_value_evaluator.rb
157
- - lib/nxt_schema/node/error.rb
158
- - lib/nxt_schema/node/has_subnodes.rb
168
+ - lib/nxt_schema/node/error_store.rb
169
+ - lib/nxt_schema/node/errors/schema_error.rb
170
+ - lib/nxt_schema/node/errors/validation_error.rb
159
171
  - lib/nxt_schema/node/leaf.rb
160
- - lib/nxt_schema/node/maybe_evaluator.rb
161
172
  - lib/nxt_schema/node/schema.rb
162
- - lib/nxt_schema/node/template_store.rb
163
- - lib/nxt_schema/node/type_resolver.rb
164
- - lib/nxt_schema/node/validate_with_proxy.rb
165
173
  - lib/nxt_schema/registry.rb
174
+ - lib/nxt_schema/registry/proxy.rb
175
+ - lib/nxt_schema/template/any_of.rb
176
+ - lib/nxt_schema/template/base.rb
177
+ - lib/nxt_schema/template/collection.rb
178
+ - lib/nxt_schema/template/has_sub_nodes.rb
179
+ - lib/nxt_schema/template/leaf.rb
180
+ - lib/nxt_schema/template/maybe_evaluator.rb
181
+ - lib/nxt_schema/template/on_evaluator.rb
182
+ - lib/nxt_schema/template/schema.rb
183
+ - lib/nxt_schema/template/sub_nodes.rb
184
+ - lib/nxt_schema/template/type_resolver.rb
185
+ - lib/nxt_schema/template/type_system_resolver.rb
166
186
  - lib/nxt_schema/types.rb
167
187
  - lib/nxt_schema/undefined.rb
168
188
  - lib/nxt_schema/validators/attribute.rb
169
- - lib/nxt_schema/validators/equality.rb
170
- - lib/nxt_schema/validators/excluded.rb
189
+ - lib/nxt_schema/validators/equal_to.rb
190
+ - lib/nxt_schema/validators/error_messages.rb
191
+ - lib/nxt_schema/validators/error_messages/en.yaml
192
+ - lib/nxt_schema/validators/excluded_in.rb
171
193
  - lib/nxt_schema/validators/excludes.rb
172
194
  - lib/nxt_schema/validators/greater_than.rb
173
195
  - lib/nxt_schema/validators/greater_than_or_equal.rb
174
- - lib/nxt_schema/validators/included.rb
196
+ - lib/nxt_schema/validators/included_in.rb
175
197
  - lib/nxt_schema/validators/includes.rb
176
198
  - lib/nxt_schema/validators/less_than.rb
177
199
  - lib/nxt_schema/validators/less_than_or_equal.rb
@@ -179,6 +201,7 @@ files:
179
201
  - lib/nxt_schema/validators/pattern.rb
180
202
  - lib/nxt_schema/validators/query.rb
181
203
  - lib/nxt_schema/validators/registry.rb
204
+ - lib/nxt_schema/validators/validate_with_proxy.rb
182
205
  - lib/nxt_schema/validators/validator.rb
183
206
  - lib/nxt_schema/version.rb
184
207
  - nxt_schema.gemspec
@@ -204,7 +227,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
204
227
  - !ruby/object:Gem::Version
205
228
  version: '0'
206
229
  requirements: []
207
- rubygems_version: 3.0.3
230
+ rubygems_version: 3.1.2
208
231
  signing_key:
209
232
  specification_version: 4
210
233
  summary: Write a short summary, because RubyGems requires one.