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