yes 0.0.1 → 1.3.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 +7 -0
- data/CHANGELOG.md +64 -0
- data/LICENSE.txt +21 -0
- data/README.md +2256 -0
- data/lib/yes/version.rb +5 -0
- data/lib/yes.rb +7 -35
- metadata +93 -98
- data/.ruby +0 -41
- data/.yardopts +0 -8
- data/HISTORY.rdoc +0 -31
- data/LICENSE.rdoc +0 -35
- data/QED.rdoc +0 -1036
- data/README.rdoc +0 -144
- data/THANKS.rdoc +0 -10
- data/bin/yes-lint +0 -4
- data/data/yes/yes.yes +0 -21
- data/lib/yes/cli.rb +0 -20
- data/lib/yes/constraints/abstract_constraint.rb +0 -121
- data/lib/yes/constraints/choice.rb +0 -39
- data/lib/yes/constraints/count.rb +0 -38
- data/lib/yes/constraints/exclusive.rb +0 -48
- data/lib/yes/constraints/fnmatch.rb +0 -42
- data/lib/yes/constraints/inclusive.rb +0 -50
- data/lib/yes/constraints/key.rb +0 -55
- data/lib/yes/constraints/kind.rb +0 -34
- data/lib/yes/constraints/length.rb +0 -46
- data/lib/yes/constraints/node_constraint.rb +0 -55
- data/lib/yes/constraints/range.rb +0 -43
- data/lib/yes/constraints/regexp.rb +0 -52
- data/lib/yes/constraints/required.rb +0 -45
- data/lib/yes/constraints/requires.rb +0 -57
- data/lib/yes/constraints/tag.rb +0 -55
- data/lib/yes/constraints/tree_constraint.rb +0 -14
- data/lib/yes/constraints/type.rb +0 -91
- data/lib/yes/constraints/value.rb +0 -62
- data/lib/yes/genclass.rb +0 -2
- data/lib/yes/lint.rb +0 -101
- data/lib/yes/logical_and.rb +0 -13
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
module YES
|
|
2
|
-
|
|
3
|
-
module Constraints
|
|
4
|
-
|
|
5
|
-
# The NodeConstraint class is an abstract class
|
|
6
|
-
# and used for create constraint subclasses that
|
|
7
|
-
# apply constraints on a sigle node.
|
|
8
|
-
#
|
|
9
|
-
class NodeConstraint < AbstractConstraint
|
|
10
|
-
|
|
11
|
-
# Like {Abstract#initialize} but takes a `node` qas well.
|
|
12
|
-
def initialize(spec, tree, node)
|
|
13
|
-
super(spec, tree, [node])
|
|
14
|
-
@node = node
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
public
|
|
18
|
-
|
|
19
|
-
# YAML Node.
|
|
20
|
-
attr :node
|
|
21
|
-
|
|
22
|
-
# Get the applicable node's tag.
|
|
23
|
-
def tag
|
|
24
|
-
node.type_id
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# Get the applicable node's value.
|
|
28
|
-
def value
|
|
29
|
-
node.value
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# # Covert a YAML node (Syck) node into a generic representation.
|
|
33
|
-
# #
|
|
34
|
-
# # TODO: Should `style` be part of this? Also, is `kind` the proper term?
|
|
35
|
-
# def catholic_node(node)
|
|
36
|
-
# n = {}
|
|
37
|
-
# n['tag'] = node.type_id
|
|
38
|
-
# #n['type'] = #base_type_id(node)
|
|
39
|
-
# n['kind'] = node.kind.to_s
|
|
40
|
-
# n['value'] = node.value
|
|
41
|
-
# n['style'] = node.instance_variable_get('@style').to_s
|
|
42
|
-
# n
|
|
43
|
-
# end
|
|
44
|
-
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
def self.applicable?(spec)
|
|
48
|
-
false
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
end
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
module YES
|
|
2
|
-
|
|
3
|
-
module Constraints
|
|
4
|
-
|
|
5
|
-
# Validate the a nodes value is within a certain range.
|
|
6
|
-
# Primarily this works for numeric values, but it can
|
|
7
|
-
# also work for string in ASCII/UTF-8 order, by using
|
|
8
|
-
# a 2-element array for comparison.
|
|
9
|
-
#
|
|
10
|
-
# //note:
|
|
11
|
-
# range: ['A','G']
|
|
12
|
-
#
|
|
13
|
-
# Valid values for are then only A, B, C, D, E, F and G.
|
|
14
|
-
class Range < NodeConstraint
|
|
15
|
-
|
|
16
|
-
#
|
|
17
|
-
# @return [Array<Validaiton>]
|
|
18
|
-
def self.checklist(spec, tree, nodes)
|
|
19
|
-
return [] unless applicable?(spec)
|
|
20
|
-
nodes.map do |node|
|
|
21
|
-
new(spec, tree, node)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
#
|
|
26
|
-
def self.applicable?(spec)
|
|
27
|
-
spec['range']
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# Validate if a node is the only one of it's value in a sequence
|
|
31
|
-
# or mapping.
|
|
32
|
-
#
|
|
33
|
-
# @return [Boolean] validity
|
|
34
|
-
def validate(spec)
|
|
35
|
-
range = spec['range']
|
|
36
|
-
match_delta(range, node.transform) ? true : false
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
end
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
module YES
|
|
2
|
-
|
|
3
|
-
module Constraints
|
|
4
|
-
|
|
5
|
-
# Validate matching values against a regular expression.
|
|
6
|
-
# All values are converted to strings (using #to_s) for comparison.
|
|
7
|
-
#
|
|
8
|
-
# //pin:
|
|
9
|
-
# regexp: /^\d\s\d\d$/
|
|
10
|
-
#
|
|
11
|
-
class Regexp < NodeConstraint
|
|
12
|
-
|
|
13
|
-
#
|
|
14
|
-
# @return [Array<Validaiton>]
|
|
15
|
-
def self.checklist(spec, tree, nodes)
|
|
16
|
-
return [] unless applicable?(spec)
|
|
17
|
-
nodes.map do |node|
|
|
18
|
-
new(spec, tree, node)
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
#
|
|
23
|
-
def self.applicable?(spec)
|
|
24
|
-
spec['regexp']
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# Validate matching values against a regular expression.
|
|
28
|
-
# All values are converted to strings (using #to_s) for comparison.
|
|
29
|
-
#
|
|
30
|
-
# @return [Boolean] validity
|
|
31
|
-
def validate(spec)
|
|
32
|
-
regexp = parse_regexp(spec['regexp'])
|
|
33
|
-
regexp =~ node.value ? true : false
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# The regular expression from `spec`.
|
|
37
|
-
#
|
|
38
|
-
# @return [Regexp] spec's regular expression
|
|
39
|
-
def parse_regexp(re)
|
|
40
|
-
case re
|
|
41
|
-
when /^\/(.*?)\/(\w*)$/
|
|
42
|
-
::Regexp.new($1) # TODO: modifiers
|
|
43
|
-
else
|
|
44
|
-
::Regexp.new(re)
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
end
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
module YES
|
|
2
|
-
|
|
3
|
-
module Constraints
|
|
4
|
-
|
|
5
|
-
#
|
|
6
|
-
# TODO: For the moment this is the same as Inclusive.
|
|
7
|
-
# It was originall inteded to work like {RequiresValidation}
|
|
8
|
-
# but it rpoved hard to work out the validation procedure
|
|
9
|
-
# when matching to the subfield. If we can fix it maybe we will
|
|
10
|
-
# keep, but for now THIS IS NOT USED.
|
|
11
|
-
#
|
|
12
|
-
class Required < TreeConstraint
|
|
13
|
-
|
|
14
|
-
#
|
|
15
|
-
# @return [Array<Constraint>]
|
|
16
|
-
def self.checklist(spec, tree, nodes)
|
|
17
|
-
return [] unless applicable?(spec)
|
|
18
|
-
[new(spec, tree, nodes)]
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# Only applicable if `required` field appears in spec.
|
|
22
|
-
def self.applicable?(spec)
|
|
23
|
-
spec['required']
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# Validates whether a matching node must be present within it's parent.
|
|
27
|
-
#
|
|
28
|
-
# @return [Boolean] validity
|
|
29
|
-
def validate(spec)
|
|
30
|
-
required = spec['required']
|
|
31
|
-
|
|
32
|
-
case required
|
|
33
|
-
when true, false
|
|
34
|
-
nodes.size > 0
|
|
35
|
-
else
|
|
36
|
-
in_nodes = tree.select(required)
|
|
37
|
-
nodes.size == 0 or in_nodes.size > 0
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
end
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
module YES
|
|
2
|
-
|
|
3
|
-
module Constraints
|
|
4
|
-
|
|
5
|
-
# Takes a list of relative YPaths and ensures they are present.
|
|
6
|
-
# This is most useful for ensuring the existance of mapping fields.
|
|
7
|
-
#
|
|
8
|
-
# foo:
|
|
9
|
-
# requires:
|
|
10
|
-
# - bar
|
|
11
|
-
#
|
|
12
|
-
# A valid document would be:
|
|
13
|
-
#
|
|
14
|
-
# foo:
|
|
15
|
-
# bar: true
|
|
16
|
-
#
|
|
17
|
-
# The literal meaing of this example is "if `foo` exists, the make sure
|
|
18
|
-
# `foo/bar` also exists.
|
|
19
|
-
class Requires < NodeConstraint
|
|
20
|
-
|
|
21
|
-
#
|
|
22
|
-
# @return [Array<Constraint>]
|
|
23
|
-
def self.checklist(spec, tree, nodes)
|
|
24
|
-
return [] unless applicable?(spec)
|
|
25
|
-
nodes.map do |node|
|
|
26
|
-
new(spec, tree, node)
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
#
|
|
31
|
-
def self.applicable?(spec)
|
|
32
|
-
spec['requires']
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
# Validates whether a matching node must be present within it's parent.
|
|
36
|
-
#
|
|
37
|
-
# @return [Boolen] validity
|
|
38
|
-
def validate(spec)
|
|
39
|
-
requires = Array(spec['requires'])
|
|
40
|
-
|
|
41
|
-
requires.each do |rq|
|
|
42
|
-
case rq
|
|
43
|
-
when /^\// # absolute path
|
|
44
|
-
rq_nodes = tree.select(rq)
|
|
45
|
-
else
|
|
46
|
-
rq_nodes = node.select(rq)
|
|
47
|
-
end
|
|
48
|
-
return false unless rq_nodes.size > 0
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
end
|
data/lib/yes/constraints/tag.rb
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
module YES
|
|
2
|
-
|
|
3
|
-
module Constraints
|
|
4
|
-
|
|
5
|
-
# Validate that a node has specific tag.
|
|
6
|
-
# This ensure all the matching nodes have the given tag.
|
|
7
|
-
# Be sure to used quotes when starting the tag with `!`.
|
|
8
|
-
#
|
|
9
|
-
# NOTE: the tag should honer %TAG directives in the document, but as of
|
|
10
|
-
# yet this is not supported. Thus fully qualified tags need to be used
|
|
11
|
-
# for anything beyond default !! and ! tags.
|
|
12
|
-
#
|
|
13
|
-
class Tag < NodeConstraint
|
|
14
|
-
|
|
15
|
-
#
|
|
16
|
-
# @return [Array<Constraint>]
|
|
17
|
-
def self.checklist(spec, tree, nodes)
|
|
18
|
-
return [] unless applicable?(spec)
|
|
19
|
-
nodes.map do |node|
|
|
20
|
-
new(spec, tree, node)
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
#
|
|
25
|
-
def self.applicable?(spec)
|
|
26
|
-
spec['tag']
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# Validate the tag.
|
|
30
|
-
#
|
|
31
|
-
# @return [Boolean] validity
|
|
32
|
-
def validate(spec)
|
|
33
|
-
tag = spec['tag']
|
|
34
|
-
match_tag(tag, node)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
private
|
|
38
|
-
|
|
39
|
-
def match_tag(tag, node)
|
|
40
|
-
node_tag = node.type_id || "tag:yaml.org,2002:#{node.kind}"
|
|
41
|
-
case node_tag
|
|
42
|
-
when /^x-private:/
|
|
43
|
-
tag == $' or tag == '!'+$'
|
|
44
|
-
when /^tag:yaml.org,2002:/
|
|
45
|
-
tag == node_tag or tag == '!!'+$'
|
|
46
|
-
else
|
|
47
|
-
tag == node_tag
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
end
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
module YES
|
|
2
|
-
|
|
3
|
-
module Constraints
|
|
4
|
-
|
|
5
|
-
# The TreeValidation class is an abstract class
|
|
6
|
-
# and used for create validation subclasses than
|
|
7
|
-
# needs access to the complete list of matching nodes.
|
|
8
|
-
class TreeConstraint < AbstractConstraint
|
|
9
|
-
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
end
|
data/lib/yes/constraints/type.rb
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
module YES
|
|
2
|
-
|
|
3
|
-
module Constraints
|
|
4
|
-
|
|
5
|
-
# Validate the <i>tag type</i>. This ensure all the matching nodes
|
|
6
|
-
# have the same base type specified. The tag type is the portion
|
|
7
|
-
# of the tag the occcurs after the last non-alphanumeric character,
|
|
8
|
-
# usually a `:`. In essence the tag type is the tag regardless of namespace.
|
|
9
|
-
#
|
|
10
|
-
# Also, `#` is treated specially as a subset fo they type, so it will
|
|
11
|
-
# be used if given in the type comparison.
|
|
12
|
-
#
|
|
13
|
-
# @example
|
|
14
|
-
# 'foo' =~ '!!foo'
|
|
15
|
-
# 'foo' =~ '!<tag:foo.org/bar:foo>'
|
|
16
|
-
# 'foo' =~ '!<tag:foo.org/bar:foo>'
|
|
17
|
-
# 'foo' =~ '!!foo#alt'
|
|
18
|
-
# 'foo#alt' =~ '!!foo#alt'
|
|
19
|
-
#
|
|
20
|
-
class Type < NodeConstraint
|
|
21
|
-
|
|
22
|
-
#
|
|
23
|
-
# @return [Array<Constraint>]
|
|
24
|
-
def self.checklist(spec, tree, nodes)
|
|
25
|
-
return [] unless applicable?(spec)
|
|
26
|
-
nodes.map do |node|
|
|
27
|
-
new(spec, tree, node)
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
#
|
|
32
|
-
def self.applicable?(spec)
|
|
33
|
-
spec['type']
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# Validate type.
|
|
37
|
-
#
|
|
38
|
-
def validate(spec)
|
|
39
|
-
type_match(node, spec['type'])
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
private
|
|
43
|
-
|
|
44
|
-
# Get the nodes base type see if matches the given type.
|
|
45
|
-
# The {TYPE_MATCH} chart is used to map a node base types
|
|
46
|
-
# to a given type.
|
|
47
|
-
#
|
|
48
|
-
# @return [Boolean] node's type matches given type
|
|
49
|
-
def type_match(node, type)
|
|
50
|
-
node_type, node_subtype = base_type_id(node).split('#')
|
|
51
|
-
want_type, want_subtype = type.split('#')
|
|
52
|
-
|
|
53
|
-
return false if want_subtype && want_subtype != node_subtype
|
|
54
|
-
|
|
55
|
-
pick_type = TYPE_MATCH[want_type] || [want_type]
|
|
56
|
-
pick_type.any?{ |t| t == node_type }
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
# Get the base of the node's type tag, i.e. the part after the last
|
|
60
|
-
# non-alphanumeric characeter plus `#`.
|
|
61
|
-
#
|
|
62
|
-
# @return [String] base type
|
|
63
|
-
def base_type_id(node)
|
|
64
|
-
fixed_type_id(node).split(/[^#A-Za-z0-9_-]/).last
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# Return the `type_id` of a node. If the type_id is `nil` then
|
|
68
|
-
# returns the `kind`.
|
|
69
|
-
#
|
|
70
|
-
# @return [String] type_id or kind of node
|
|
71
|
-
def fixed_type_id(node)
|
|
72
|
-
type_id = node.type_id
|
|
73
|
-
if type_id
|
|
74
|
-
type_id
|
|
75
|
-
else
|
|
76
|
-
node.kind.to_s
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
#
|
|
81
|
-
TYPE_MATCH = {
|
|
82
|
-
'date' => ['timestamp'],
|
|
83
|
-
'bool' => ['bool'],
|
|
84
|
-
'number' => ['int', 'float']
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
end
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
module YES
|
|
2
|
-
|
|
3
|
-
module Constraints
|
|
4
|
-
|
|
5
|
-
# Validate if a node's _value_ conforms to a constraint, where a
|
|
6
|
-
# value is either an sequence element or a mapping value.
|
|
7
|
-
#
|
|
8
|
-
# //authors:
|
|
9
|
-
# type: seq
|
|
10
|
-
# value:
|
|
11
|
-
# type: str
|
|
12
|
-
#
|
|
13
|
-
# A valid code value could then have no more than three characters.
|
|
14
|
-
class Value < NodeConstraint
|
|
15
|
-
|
|
16
|
-
# For value constraint, the work is all handled by the
|
|
17
|
-
# checklist method.
|
|
18
|
-
#
|
|
19
|
-
# @return [Array<Constraint>]
|
|
20
|
-
def self.checklist(spec, tree, nodes)
|
|
21
|
-
return [] unless applicable?(spec)
|
|
22
|
-
|
|
23
|
-
vspec = spec['value']
|
|
24
|
-
list = []
|
|
25
|
-
|
|
26
|
-
nodes.each do |node|
|
|
27
|
-
case node.kind
|
|
28
|
-
when :seq
|
|
29
|
-
YES.constraints.each do |c|
|
|
30
|
-
list.concat(c.checklist(vspec, tree, node.children))
|
|
31
|
-
end
|
|
32
|
-
when :map
|
|
33
|
-
YES.constraints.each do |c|
|
|
34
|
-
list.concat(c.checklist(vspec, tree, node.value.values))
|
|
35
|
-
end
|
|
36
|
-
else
|
|
37
|
-
# TODO: might value for scalars have a useful meaning?
|
|
38
|
-
raise "value constraint does not apply to scalars"
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
list
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
def self.applicable?(spec)
|
|
48
|
-
spec['value']
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
#
|
|
52
|
-
# no-op
|
|
53
|
-
#
|
|
54
|
-
# @return [Boolean] validity
|
|
55
|
-
def validate(spec)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
end
|
data/lib/yes/genclass.rb
DELETED
data/lib/yes/lint.rb
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
module YES
|
|
2
|
-
|
|
3
|
-
# YAML Easy Schema - Constrain Validator ("Lint")
|
|
4
|
-
#
|
|
5
|
-
# Issues
|
|
6
|
-
#
|
|
7
|
-
# * Matching fully-quaified tags.
|
|
8
|
-
# * Handling namespaces.
|
|
9
|
-
# * Handling YAML version directive.
|
|
10
|
-
#
|
|
11
|
-
class Lint
|
|
12
|
-
|
|
13
|
-
# The schema document.
|
|
14
|
-
attr :schema
|
|
15
|
-
|
|
16
|
-
# The tree, which is populate when #validate is called.
|
|
17
|
-
#attr :tree
|
|
18
|
-
|
|
19
|
-
# The constraint checklist.
|
|
20
|
-
attr :checklist
|
|
21
|
-
|
|
22
|
-
#
|
|
23
|
-
def initialize(schema)
|
|
24
|
-
@schema = YAML.load(schema)
|
|
25
|
-
@checklist = []
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
#
|
|
29
|
-
# @param [String] yaml
|
|
30
|
-
# A YAML document.
|
|
31
|
-
#
|
|
32
|
-
# @return [Array]
|
|
33
|
-
# List of constraints that were invalid.
|
|
34
|
-
#
|
|
35
|
-
def validate(yaml)
|
|
36
|
-
@checklist = []
|
|
37
|
-
|
|
38
|
-
tree = YAML.parse(yaml)
|
|
39
|
-
|
|
40
|
-
@schema.each do |ypath, spec|
|
|
41
|
-
validate_ypath(ypath, spec, tree)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
@checklist.reject{ |v| v.valid? }
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
#
|
|
48
|
-
def validate_ypath(ypath, spec, tree)
|
|
49
|
-
validate_spec(ypath, spec, tree)
|
|
50
|
-
|
|
51
|
-
## handle sub-paths
|
|
52
|
-
if spec['map']
|
|
53
|
-
spec['map'].each do |sub_path, sub_spec|
|
|
54
|
-
sub_ypath = ypath + '/' + sub_path
|
|
55
|
-
validate_ypath(sub_ypath, sub_spec, tree)
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
# Process all validations.
|
|
61
|
-
#
|
|
62
|
-
# FIXME: Add logic handling.
|
|
63
|
-
def validate_spec(ypath, spec, tree)
|
|
64
|
-
nodes = select_nodes(ypath, tree)
|
|
65
|
-
|
|
66
|
-
YES.constraints.each do |c|
|
|
67
|
-
@checklist.concat(c.checklist(spec, tree, nodes))
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# TODO: Maybe this should be a class method, too ?
|
|
72
|
-
def select_nodes(ypath, tree)
|
|
73
|
-
case ypath
|
|
74
|
-
when Hash
|
|
75
|
-
if path = ypath['path'] || ypath['ypath']
|
|
76
|
-
nodes = tree.select(path)
|
|
77
|
-
else
|
|
78
|
-
nodes = tree.select('*') # all nodes
|
|
79
|
-
end
|
|
80
|
-
YES.constraints.each do |c|
|
|
81
|
-
next unless Constraints::NodeConstraint === c
|
|
82
|
-
checklist = c.checklist(spec, tree, nodes)
|
|
83
|
-
selection = checklist.select{ |v| v.valid? }
|
|
84
|
-
nodes.concat(selection.map{ |s| s.node })
|
|
85
|
-
end
|
|
86
|
-
nodes
|
|
87
|
-
else
|
|
88
|
-
tree.select(ypath)
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
## Validate if a node is the only one of it's value in a sequence
|
|
93
|
-
## or mapping.
|
|
94
|
-
#def validate_unique(spec, nodes)
|
|
95
|
-
# return unless unique = spec['unique']
|
|
96
|
-
# # TODO: how to do?
|
|
97
|
-
#end
|
|
98
|
-
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
end
|