nxt_schema 0.1.0 → 1.0.2
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/.ruby-version +1 -0
- data/Gemfile +0 -1
- data/Gemfile.lock +40 -42
- data/README.md +267 -121
- data/lib/nxt_schema.rb +60 -51
- data/lib/nxt_schema/callable.rb +21 -55
- data/lib/nxt_schema/dsl.rb +41 -31
- data/lib/nxt_schema/error.rb +4 -0
- data/lib/nxt_schema/errors/{error.rb → coercion_error.rb} +1 -2
- data/lib/nxt_schema/errors/invalid.rb +16 -0
- data/lib/nxt_schema/errors/invalid_options.rb +6 -0
- data/lib/nxt_schema/node/any_of.rb +39 -0
- data/lib/nxt_schema/node/base.rb +66 -267
- data/lib/nxt_schema/node/collection.rb +40 -56
- data/lib/nxt_schema/node/error_store.rb +41 -0
- data/lib/nxt_schema/node/errors/schema_error.rb +15 -0
- data/lib/nxt_schema/node/errors/validation_error.rb +15 -0
- data/lib/nxt_schema/node/leaf.rb +8 -36
- data/lib/nxt_schema/node/schema.rb +70 -103
- data/lib/nxt_schema/registry.rb +12 -74
- data/lib/nxt_schema/registry/proxy.rb +21 -0
- data/lib/nxt_schema/template/any_of.rb +50 -0
- data/lib/nxt_schema/template/base.rb +220 -0
- data/lib/nxt_schema/template/collection.rb +23 -0
- data/lib/nxt_schema/template/has_sub_nodes.rb +87 -0
- data/lib/nxt_schema/template/leaf.rb +13 -0
- data/lib/nxt_schema/template/maybe_evaluator.rb +28 -0
- data/lib/nxt_schema/template/on_evaluator.rb +25 -0
- data/lib/nxt_schema/template/schema.rb +22 -0
- data/lib/nxt_schema/template/sub_nodes.rb +22 -0
- data/lib/nxt_schema/template/type_resolver.rb +39 -0
- data/lib/nxt_schema/template/type_system_resolver.rb +22 -0
- data/lib/nxt_schema/types.rb +7 -4
- data/lib/nxt_schema/undefined.rb +4 -2
- data/lib/nxt_schema/validators/{equality.rb → equal_to.rb} +2 -2
- data/lib/nxt_schema/validators/error_messages.rb +42 -0
- data/lib/nxt_schema/{error_messages → validators/error_messages}/en.yaml +6 -5
- data/lib/nxt_schema/validators/{excluded.rb → excluded_in.rb} +1 -1
- data/lib/nxt_schema/validators/{included.rb → included_in.rb} +1 -1
- data/lib/nxt_schema/validators/includes.rb +1 -1
- data/lib/nxt_schema/validators/optional_node.rb +11 -6
- data/lib/nxt_schema/validators/registry.rb +1 -7
- data/lib/nxt_schema/{node → validators}/validate_with_proxy.rb +3 -3
- data/lib/nxt_schema/validators/validator.rb +2 -2
- data/lib/nxt_schema/version.rb +1 -1
- data/nxt_schema.gemspec +1 -0
- metadata +44 -21
- data/lib/nxt_schema/callable_or_value.rb +0 -72
- data/lib/nxt_schema/error_messages.rb +0 -40
- data/lib/nxt_schema/errors.rb +0 -4
- data/lib/nxt_schema/errors/invalid_options_error.rb +0 -5
- data/lib/nxt_schema/errors/schema_not_applied_error.rb +0 -5
- data/lib/nxt_schema/node/constructor.rb +0 -9
- data/lib/nxt_schema/node/default_value_evaluator.rb +0 -20
- data/lib/nxt_schema/node/error.rb +0 -13
- data/lib/nxt_schema/node/has_subnodes.rb +0 -97
- data/lib/nxt_schema/node/maybe_evaluator.rb +0 -23
- data/lib/nxt_schema/node/template_store.rb +0 -15
- data/lib/nxt_schema/node/type_resolver.rb +0 -24
@@ -1,72 +0,0 @@
|
|
1
|
-
module NxtSchema
|
2
|
-
class CallableOrValue
|
3
|
-
def initialize(callee)
|
4
|
-
@callee = callee
|
5
|
-
|
6
|
-
if callee.is_a?(Symbol)
|
7
|
-
self.type = :method
|
8
|
-
elsif callee.respond_to?(:call)
|
9
|
-
self.type = :proc
|
10
|
-
self.context = callee.binding
|
11
|
-
else
|
12
|
-
self.type = :value
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def bind(execution_context = nil)
|
17
|
-
self.context = execution_context
|
18
|
-
ensure_context_not_missing
|
19
|
-
self
|
20
|
-
end
|
21
|
-
|
22
|
-
# NOTE: Currently we only allow arguments! Not keyword args or **options
|
23
|
-
# If we would allow **options and we would pass a hash as the only argument it would
|
24
|
-
# automatically be parsed as the options!
|
25
|
-
def call(*args)
|
26
|
-
return callee if value?
|
27
|
-
|
28
|
-
ensure_context_not_missing
|
29
|
-
|
30
|
-
args = args.take(arity)
|
31
|
-
|
32
|
-
if method?
|
33
|
-
context.send(callee, *args)
|
34
|
-
else
|
35
|
-
context.instance_exec(*args, &callee)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def arity
|
40
|
-
if proc?
|
41
|
-
callee.arity
|
42
|
-
elsif method?
|
43
|
-
method = context.send(:method, callee)
|
44
|
-
method.arity
|
45
|
-
else
|
46
|
-
raise ArgumentError, "Can't resolve arity from #{callee}"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
def proc?
|
53
|
-
type == :proc
|
54
|
-
end
|
55
|
-
|
56
|
-
def method?
|
57
|
-
type == :method
|
58
|
-
end
|
59
|
-
|
60
|
-
def value?
|
61
|
-
type == :value
|
62
|
-
end
|
63
|
-
|
64
|
-
def ensure_context_not_missing
|
65
|
-
return if context
|
66
|
-
|
67
|
-
raise ArgumentError, "Missing context: #{context}"
|
68
|
-
end
|
69
|
-
|
70
|
-
attr_accessor :context, :callee, :type
|
71
|
-
end
|
72
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
module NxtSchema
|
2
|
-
class ErrorMessages
|
3
|
-
class << self
|
4
|
-
def values
|
5
|
-
@values ||= {}
|
6
|
-
end
|
7
|
-
|
8
|
-
def values=(value)
|
9
|
-
@values = value
|
10
|
-
end
|
11
|
-
|
12
|
-
def load(paths = files)
|
13
|
-
Array(paths).each do |path|
|
14
|
-
new_values = YAML.load(ERB.new(File.read(path)).result).with_indifferent_access
|
15
|
-
self.values = values.deep_merge!(new_values)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def resolve(locale, key, **options)
|
20
|
-
message = begin
|
21
|
-
values.fetch(locale).fetch(key)
|
22
|
-
rescue KeyError
|
23
|
-
raise "Could not resolve error message for #{locale}->#{key}"
|
24
|
-
end
|
25
|
-
|
26
|
-
message % options
|
27
|
-
end
|
28
|
-
|
29
|
-
def files
|
30
|
-
@files ||= begin
|
31
|
-
files = Dir.entries(File.expand_path('../error_messages/', __FILE__)).map do |filename|
|
32
|
-
File.expand_path("../error_messages/#{filename}", __FILE__)
|
33
|
-
end
|
34
|
-
|
35
|
-
files.select { |f| !File.directory? f }
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
data/lib/nxt_schema/errors.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
module NxtSchema
|
2
|
-
module Node
|
3
|
-
class DefaultValueEvaluator
|
4
|
-
def initialize(node, evaluator_or_value)
|
5
|
-
@node = node
|
6
|
-
@evaluator_or_value = evaluator_or_value
|
7
|
-
end
|
8
|
-
|
9
|
-
attr_reader :node, :evaluator_or_value
|
10
|
-
|
11
|
-
def call
|
12
|
-
if evaluator_or_value.respond_to?(:call)
|
13
|
-
Callable.new(evaluator_or_value).call(node)
|
14
|
-
else
|
15
|
-
evaluator_or_value
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,97 +0,0 @@
|
|
1
|
-
require_relative 'schema'
|
2
|
-
require_relative 'collection'
|
3
|
-
require_relative 'constructor'
|
4
|
-
require_relative 'leaf'
|
5
|
-
|
6
|
-
module NxtSchema
|
7
|
-
module Node
|
8
|
-
module HasSubNodes
|
9
|
-
attr_accessor :template_store, :value_store
|
10
|
-
|
11
|
-
# TODO: Would be cool if we could register custom node types!
|
12
|
-
def node(name, type_or_node, **options, &block)
|
13
|
-
child_node = case type_or_node.to_s.to_sym
|
14
|
-
when :Schema
|
15
|
-
NxtSchema::Node::Schema.new(name: name, type: NxtSchema::Types::Strict::Hash, parent_node: self, **options, &block)
|
16
|
-
when :Collection
|
17
|
-
NxtSchema::Node::Collection.new(name: name, type: NxtSchema::Types::Strict::Array, parent_node: self, **options, &block)
|
18
|
-
when :Struct
|
19
|
-
NxtSchema::Node::Constructor.new(
|
20
|
-
name: name,
|
21
|
-
type: NxtSchema::Types::Constructor(::Struct) { |hash| ::Struct.new(*hash.keys).new(*hash.values) },
|
22
|
-
parent_node: self,
|
23
|
-
**options,
|
24
|
-
&block
|
25
|
-
)
|
26
|
-
when :OpenStruct
|
27
|
-
NxtSchema::Node::Constructor.new(
|
28
|
-
name: name,
|
29
|
-
type: NxtSchema::Types::Constructor(::OpenStruct),
|
30
|
-
parent_node: self,
|
31
|
-
**options,
|
32
|
-
&block
|
33
|
-
)
|
34
|
-
else
|
35
|
-
if type_or_node.is_a?(NxtSchema::Node::Base)
|
36
|
-
node = type_or_node.clone
|
37
|
-
node.options.merge!(options)
|
38
|
-
node.name = name
|
39
|
-
node.parent_node = self
|
40
|
-
node
|
41
|
-
else
|
42
|
-
NxtSchema::Node::Leaf.new(name: name, type: type_or_node, parent_node: self, **options)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
# TODO: Should we check if there is a
|
47
|
-
raise KeyError, "Duplicate registration for key: #{name}" if template_store.key?(name)
|
48
|
-
template_store.push(child_node)
|
49
|
-
|
50
|
-
child_node
|
51
|
-
end
|
52
|
-
|
53
|
-
def required(name, type, **options, &block)
|
54
|
-
node(name, type, options, &block)
|
55
|
-
end
|
56
|
-
|
57
|
-
alias_method :requires, :required
|
58
|
-
|
59
|
-
def nodes(name, **options, &block)
|
60
|
-
node(name, :Collection, options, &block)
|
61
|
-
end
|
62
|
-
|
63
|
-
alias_method :array, :nodes
|
64
|
-
|
65
|
-
def schema(name, **options, &block)
|
66
|
-
node(name, :Schema, options, &block)
|
67
|
-
end
|
68
|
-
|
69
|
-
alias_method :hash, :schema
|
70
|
-
|
71
|
-
def struct(name, **options, &block)
|
72
|
-
node(name, NxtSchema::Types::Constructor(::OpenStruct), options, &block)
|
73
|
-
end
|
74
|
-
|
75
|
-
def dup
|
76
|
-
result = super
|
77
|
-
result.template_store = template_store.deep_dup
|
78
|
-
result.options = options.deep_dup
|
79
|
-
result
|
80
|
-
end
|
81
|
-
|
82
|
-
delegate_missing_to :value_store
|
83
|
-
|
84
|
-
private
|
85
|
-
|
86
|
-
def value_violates_emptiness?(value)
|
87
|
-
return true unless value.respond_to?(:empty?)
|
88
|
-
|
89
|
-
value.empty?
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
NxtSchema::Node::Schema.include(::NxtSchema::Node::HasSubNodes)
|
96
|
-
NxtSchema::Node::Collection.include(::NxtSchema::Node::HasSubNodes)
|
97
|
-
NxtSchema::Node::Constructor.include(::NxtSchema::Node::HasSubNodes)
|
@@ -1,23 +0,0 @@
|
|
1
|
-
module NxtSchema
|
2
|
-
module Node
|
3
|
-
class MaybeEvaluator
|
4
|
-
def initialize(node, evaluator, value)
|
5
|
-
@node = node
|
6
|
-
@evaluator = evaluator
|
7
|
-
@value = value
|
8
|
-
end
|
9
|
-
|
10
|
-
attr_reader :node, :evaluator, :value
|
11
|
-
|
12
|
-
def call
|
13
|
-
if evaluator.respond_to?(:call)
|
14
|
-
Callable.new(evaluator).call(node, value)
|
15
|
-
elsif value.is_a?(Symbol) && value.respond_to?(evaluator)
|
16
|
-
Callable.new(evaluator).bind(value).call(node, value)
|
17
|
-
else
|
18
|
-
value == evaluator
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
module NxtSchema
|
2
|
-
module Node
|
3
|
-
class TemplateStore < ::Hash
|
4
|
-
def push(node)
|
5
|
-
node_name = node.name
|
6
|
-
raise_key_error(node_name) if key?(node_name)
|
7
|
-
self[node_name] = node
|
8
|
-
end
|
9
|
-
|
10
|
-
def raise_key_error(key)
|
11
|
-
raise KeyError, "Node with name '#{key}' already registered! Node names must be unique!"
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
module NxtSchema
|
2
|
-
module Node
|
3
|
-
class TypeResolver
|
4
|
-
def resolve(type_system, type)
|
5
|
-
@resolve ||= {}
|
6
|
-
@resolve[type] ||= begin
|
7
|
-
if type.is_a?(Dry::Types::Type)
|
8
|
-
type
|
9
|
-
else
|
10
|
-
# Try to resolve in type system
|
11
|
-
type = type_system.const_get(type.to_s.classify)
|
12
|
-
|
13
|
-
if type.is_a?(Dry::Types::Type)
|
14
|
-
type
|
15
|
-
else
|
16
|
-
# in case it does not exist fallback to Types::Nominal
|
17
|
-
"NxtSchema::Types::Nominal::#{type.to_s.classify}".constantize
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|