nxt_schema 0.1.2 → 1.0.0
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 +32 -29
- data/README.md +186 -116
- data/lib/nxt_schema.rb +56 -49
- data/lib/nxt_schema/{node.rb → application.rb} +1 -1
- data/lib/nxt_schema/application/any_of.rb +40 -0
- data/lib/nxt_schema/application/base.rb +116 -0
- data/lib/nxt_schema/application/collection.rb +57 -0
- data/lib/nxt_schema/application/error_store.rb +57 -0
- data/lib/nxt_schema/application/errors/schema_error.rb +15 -0
- data/lib/nxt_schema/application/errors/validation_error.rb +15 -0
- data/lib/nxt_schema/application/leaf.rb +15 -0
- data/lib/nxt_schema/application/schema.rb +114 -0
- 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/invalid.rb +16 -0
- data/lib/nxt_schema/errors/{error.rb → invalid_options.rb} +1 -2
- data/lib/nxt_schema/missing_input.rb +9 -0
- data/lib/nxt_schema/node/any_of.rb +51 -0
- data/lib/nxt_schema/node/base.rb +135 -233
- data/lib/nxt_schema/node/collection.rb +10 -65
- data/lib/nxt_schema/node/has_sub_nodes.rb +81 -0
- data/lib/nxt_schema/node/leaf.rb +1 -31
- data/lib/nxt_schema/node/maybe_evaluator.rb +15 -10
- data/lib/nxt_schema/node/on_evaluator.rb +25 -0
- data/lib/nxt_schema/node/schema.rb +8 -134
- data/lib/nxt_schema/node/sub_nodes.rb +22 -0
- data/lib/nxt_schema/node/type_system_resolver.rb +22 -0
- data/lib/nxt_schema/types.rb +1 -1
- data/lib/nxt_schema/validators/attribute.rb +3 -3
- data/lib/nxt_schema/validators/{equality.rb → equal_to.rb} +5 -5
- data/lib/nxt_schema/validators/error_messages.rb +42 -0
- data/lib/nxt_schema/{error_messages → validators/error_messages}/en.yaml +3 -3
- data/lib/nxt_schema/validators/{excluded.rb → excluded_in.rb} +4 -4
- data/lib/nxt_schema/validators/excludes.rb +3 -3
- data/lib/nxt_schema/validators/greater_than.rb +3 -3
- data/lib/nxt_schema/validators/greater_than_or_equal.rb +3 -3
- data/lib/nxt_schema/validators/{included.rb → included_in.rb} +4 -4
- data/lib/nxt_schema/validators/includes.rb +3 -3
- data/lib/nxt_schema/validators/less_than.rb +3 -3
- data/lib/nxt_schema/validators/less_than_or_equal.rb +3 -3
- data/lib/nxt_schema/validators/optional_node.rb +13 -8
- data/lib/nxt_schema/validators/pattern.rb +3 -3
- data/lib/nxt_schema/validators/query.rb +4 -4
- data/lib/nxt_schema/validators/registry.rb +1 -7
- data/lib/nxt_schema/{node → validators}/validate_with_proxy.rb +8 -8
- data/lib/nxt_schema/validators/validator.rb +2 -2
- data/lib/nxt_schema/version.rb +1 -1
- data/nxt_schema.gemspec +1 -0
- metadata +42 -22
- 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/template_store.rb +0 -15
- data/lib/nxt_schema/registry.rb +0 -85
- data/lib/nxt_schema/undefined.rb +0 -7
@@ -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,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
|
data/lib/nxt_schema/registry.rb
DELETED
@@ -1,85 +0,0 @@
|
|
1
|
-
module NxtSchema
|
2
|
-
class Registry
|
3
|
-
def initialize(namespace_separator: '::', namespace: '')
|
4
|
-
@store = ActiveSupport::HashWithIndifferentAccess.new
|
5
|
-
@namespace_separator = namespace_separator
|
6
|
-
@namespace = namespace
|
7
|
-
end
|
8
|
-
|
9
|
-
delegate_missing_to :store
|
10
|
-
|
11
|
-
# register('strict::string')
|
12
|
-
# Registry[:strict].register
|
13
|
-
|
14
|
-
def register(key, value)
|
15
|
-
key = key.to_s
|
16
|
-
ensure_key_not_registered_already(key)
|
17
|
-
namespaced_store(key)[flat_key(key)] = value
|
18
|
-
end
|
19
|
-
|
20
|
-
def resolve(key, *args)
|
21
|
-
value = resolve_value(key)
|
22
|
-
return value unless value.respond_to?(:call)
|
23
|
-
|
24
|
-
value.call(*args)
|
25
|
-
end
|
26
|
-
|
27
|
-
def resolve_value(key)
|
28
|
-
key = key.to_s
|
29
|
-
parts = namespaced_key_parts(key)[0..-2]
|
30
|
-
|
31
|
-
namespaced_store = parts.inject(store) do |acc, key|
|
32
|
-
acc.fetch(key)
|
33
|
-
rescue KeyError
|
34
|
-
raise KeyError, "No registry found at #{key} in #{acc}"
|
35
|
-
end
|
36
|
-
|
37
|
-
begin
|
38
|
-
namespaced_store.fetch(flat_key(key))
|
39
|
-
rescue KeyError
|
40
|
-
raise KeyError, "Could not find #{flat_key(key)} in #{namespaced_store}"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
private
|
45
|
-
|
46
|
-
attr_reader :store, :namespace_separator, :namespace
|
47
|
-
|
48
|
-
def namespaced_store(key)
|
49
|
-
parts = namespaced_key_parts(key)
|
50
|
-
|
51
|
-
current_parts = []
|
52
|
-
|
53
|
-
parts[0..-2].inject(store) do |acc, namespace|
|
54
|
-
current_parts << namespace
|
55
|
-
current_namespace = current_parts.join(namespace_separator)
|
56
|
-
|
57
|
-
acc.fetch(namespace) do
|
58
|
-
acc[namespace] = Registry.new(namespace: current_namespace)
|
59
|
-
acc = acc[namespace]
|
60
|
-
acc
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def namespaced_key_parts(key)
|
66
|
-
key.downcase.split(namespace_separator)
|
67
|
-
end
|
68
|
-
|
69
|
-
def flat_key(key)
|
70
|
-
namespaced_key_parts(key).last
|
71
|
-
end
|
72
|
-
|
73
|
-
def ensure_key_not_registered_already(key)
|
74
|
-
return unless namespaced_store(key).key?(flat_key(key))
|
75
|
-
|
76
|
-
raise KeyError, "Key: #{flat_key(key)} already registered in #{namespaced_store(key)}"
|
77
|
-
end
|
78
|
-
|
79
|
-
def to_s
|
80
|
-
identifier = 'NxtSchema::Registry'
|
81
|
-
identifier << "#{namespace_separator}#{namespace}" unless namespace.blank?
|
82
|
-
identifier
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|