yes 0.0.1
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.
- data/.ruby +41 -0
- data/.yardopts +8 -0
- data/HISTORY.rdoc +31 -0
- data/LICENSE.rdoc +35 -0
- data/QED.rdoc +1036 -0
- data/README.rdoc +144 -0
- data/THANKS.rdoc +10 -0
- data/bin/yes-lint +4 -0
- data/data/yes/yes.yes +21 -0
- data/lib/yes.rb +38 -0
- data/lib/yes/cli.rb +20 -0
- data/lib/yes/constraints/abstract_constraint.rb +121 -0
- data/lib/yes/constraints/choice.rb +39 -0
- data/lib/yes/constraints/count.rb +38 -0
- data/lib/yes/constraints/exclusive.rb +48 -0
- data/lib/yes/constraints/fnmatch.rb +42 -0
- data/lib/yes/constraints/inclusive.rb +50 -0
- data/lib/yes/constraints/key.rb +55 -0
- data/lib/yes/constraints/kind.rb +34 -0
- data/lib/yes/constraints/length.rb +46 -0
- data/lib/yes/constraints/node_constraint.rb +55 -0
- data/lib/yes/constraints/range.rb +43 -0
- data/lib/yes/constraints/regexp.rb +52 -0
- data/lib/yes/constraints/required.rb +45 -0
- data/lib/yes/constraints/requires.rb +57 -0
- data/lib/yes/constraints/tag.rb +55 -0
- data/lib/yes/constraints/tree_constraint.rb +14 -0
- data/lib/yes/constraints/type.rb +91 -0
- data/lib/yes/constraints/value.rb +62 -0
- data/lib/yes/genclass.rb +2 -0
- data/lib/yes/lint.rb +101 -0
- data/lib/yes/logical_and.rb +13 -0
- metadata +110 -0
@@ -0,0 +1,55 @@
|
|
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
|
@@ -0,0 +1,14 @@
|
|
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
|
@@ -0,0 +1,91 @@
|
|
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
|
@@ -0,0 +1,62 @@
|
|
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
ADDED
data/lib/yes/lint.rb
ADDED
@@ -0,0 +1,101 @@
|
|
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
|
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: "yes"
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Thomas Sawyer
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-07-13 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: qed
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
type: :development
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: detroit
|
28
|
+
prerelease: false
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: "0"
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id002
|
37
|
+
description: YAML Easy Schemas it a straight-foward but powerful YPath-based schema format and validation program for YAML documents.
|
38
|
+
email: transfire@gmail.com
|
39
|
+
executables:
|
40
|
+
- yes-lint
|
41
|
+
extensions: []
|
42
|
+
|
43
|
+
extra_rdoc_files:
|
44
|
+
- README.rdoc
|
45
|
+
files:
|
46
|
+
- .ruby
|
47
|
+
- .yardopts
|
48
|
+
- bin/yes-lint
|
49
|
+
- data/yes/yes.yes
|
50
|
+
- lib/yes/cli.rb
|
51
|
+
- lib/yes/constraints/abstract_constraint.rb
|
52
|
+
- lib/yes/constraints/choice.rb
|
53
|
+
- lib/yes/constraints/count.rb
|
54
|
+
- lib/yes/constraints/exclusive.rb
|
55
|
+
- lib/yes/constraints/fnmatch.rb
|
56
|
+
- lib/yes/constraints/inclusive.rb
|
57
|
+
- lib/yes/constraints/key.rb
|
58
|
+
- lib/yes/constraints/kind.rb
|
59
|
+
- lib/yes/constraints/length.rb
|
60
|
+
- lib/yes/constraints/node_constraint.rb
|
61
|
+
- lib/yes/constraints/range.rb
|
62
|
+
- lib/yes/constraints/regexp.rb
|
63
|
+
- lib/yes/constraints/required.rb
|
64
|
+
- lib/yes/constraints/requires.rb
|
65
|
+
- lib/yes/constraints/tag.rb
|
66
|
+
- lib/yes/constraints/tree_constraint.rb
|
67
|
+
- lib/yes/constraints/type.rb
|
68
|
+
- lib/yes/constraints/value.rb
|
69
|
+
- lib/yes/genclass.rb
|
70
|
+
- lib/yes/lint.rb
|
71
|
+
- lib/yes/logical_and.rb
|
72
|
+
- lib/yes.rb
|
73
|
+
- HISTORY.rdoc
|
74
|
+
- README.rdoc
|
75
|
+
- QED.rdoc
|
76
|
+
- LICENSE.rdoc
|
77
|
+
- THANKS.rdoc
|
78
|
+
homepage: http://rubyworks.github.com/yes
|
79
|
+
licenses:
|
80
|
+
- BSD-2-Clause
|
81
|
+
- BSD-2-Clause
|
82
|
+
post_install_message:
|
83
|
+
rdoc_options:
|
84
|
+
- --title
|
85
|
+
- YES API
|
86
|
+
- --main
|
87
|
+
- README.rdoc
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: "0"
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: "0"
|
102
|
+
requirements: []
|
103
|
+
|
104
|
+
rubyforge_project: "yes"
|
105
|
+
rubygems_version: 1.8.2
|
106
|
+
signing_key:
|
107
|
+
specification_version: 3
|
108
|
+
summary: YAML Easy Schema
|
109
|
+
test_files: []
|
110
|
+
|