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.
- 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
|