shex 0.6.2 → 0.7.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.
- checksums.yaml +4 -4
- data/README.md +108 -97
- data/VERSION +1 -1
- data/etc/doap.ttl +1 -1
- data/lib/shex/algebra/and.rb +3 -12
- data/lib/shex/algebra/each_of.rb +2 -12
- data/lib/shex/algebra/import.rb +6 -0
- data/lib/shex/algebra/not.rb +3 -10
- data/lib/shex/algebra/one_of.rb +2 -12
- data/lib/shex/algebra/operator.rb +28 -15
- data/lib/shex/algebra/or.rb +3 -12
- data/lib/shex/algebra/schema.rb +2 -9
- data/lib/shex/algebra/shape.rb +4 -2
- data/lib/shex/algebra/shape_expression.rb +29 -0
- data/lib/shex/algebra/start.rb +2 -10
- data/lib/shex/algebra/stem.rb +5 -1
- data/lib/shex/algebra/stem_range.rb +3 -1
- data/lib/shex/algebra/triple_constraint.rb +1 -1
- data/lib/shex/algebra/triple_expression.rb +18 -0
- data/lib/shex/algebra.rb +0 -1
- data/lib/shex/meta.rb +325 -9859
- data/lib/shex/parser.rb +559 -474
- data/lib/shex/terminals.rb +5 -25
- data/lib/shex.rb +4 -1
- metadata +57 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f23772b66ae1d2d65f82803ebc661051084b62bab305781945c3d36a1c9ff1c1
|
4
|
+
data.tar.gz: c5cba5902f5c6b2dd0bdf446ec9625dc9baa94682f5375fb3c3b89d1bd76cc91
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a9ad30899338103d06b8b2d89070990c81215e3bfe0ab0d649bcbb3290e5981fe7aadf15e6456358786fc4f5f68c8a28aafd44d6e440f42130f1778622ebd0dc
|
7
|
+
data.tar.gz: 7107749beac51786c8778a1f2ea8a733caf49d8b01d323d0437eecc5d17e873bc1ad083fbc146133cde250dd8705a25105c5f7522afc0eb2773f50ef996b86f5
|
data/README.md
CHANGED
@@ -18,34 +18,38 @@ This is a pure-Ruby library for working with the [Shape Expressions Language][Sh
|
|
18
18
|
|
19
19
|
The ShEx gem implements a [ShEx][ShExSpec] Shape Expression engine version 2.0.
|
20
20
|
|
21
|
-
* `ShEx::Parser` parses ShExC and ShExJ formatted documents generating executable operators which can be serialized as [S-Expressions]
|
21
|
+
* `ShEx::Parser` parses ShExC and ShExJ formatted documents generating executable operators which can be serialized as [S-Expressions][].
|
22
22
|
* `ShEx::Algebra` executes operators against Any `RDF::Graph`, including compliant [RDF.rb][].
|
23
23
|
* [Implementation Report](file.earl.html)
|
24
24
|
|
25
25
|
## Examples
|
26
26
|
### Validating a node using ShExC
|
27
27
|
|
28
|
-
require 'rubygems'
|
29
28
|
require 'rdf/turtle'
|
30
29
|
require 'shex'
|
31
30
|
|
32
|
-
shexc
|
31
|
+
shexc = %(
|
33
32
|
PREFIX doap: <http://usefulinc.com/ns/doap#>
|
34
33
|
PREFIX dc: <http://purl.org/dc/terms/>
|
35
|
-
<
|
36
|
-
|
37
|
-
|
38
|
-
doap:
|
39
|
-
doap:
|
40
|
-
|
34
|
+
PREFIX ex: <http://example.com/>
|
35
|
+
|
36
|
+
ex:TestShape EXTRA a {
|
37
|
+
a [doap:Project];
|
38
|
+
( doap:name Literal;
|
39
|
+
doap:description Literal
|
40
|
+
| dc:title Literal;
|
41
|
+
dc:description Literal)+;
|
42
|
+
doap:category IRI*;
|
43
|
+
doap:developer IRI+;
|
44
|
+
doap:implements [<http://shex.io/shex-semantics/>]
|
41
45
|
}
|
42
46
|
)
|
43
47
|
graph = RDF::Graph.load("etc/doap.ttl")
|
44
48
|
schema = ShEx.parse(shexc)
|
45
49
|
map = {
|
46
|
-
"https://rubygems.org/gems/shex" => "TestShape"
|
50
|
+
RDF::URI("https://rubygems.org/gems/shex") => RDF::URI("http://example.com/TestShape")
|
47
51
|
}
|
48
|
-
schema.satisfies?(
|
52
|
+
schema.satisfies?(graph, map)
|
49
53
|
# => true
|
50
54
|
### Validating a node using ShExJ
|
51
55
|
|
@@ -53,92 +57,99 @@ The ShEx gem implements a [ShEx][ShExSpec] Shape Expression engine version 2.0.
|
|
53
57
|
require 'rdf/turtle'
|
54
58
|
require 'shex'
|
55
59
|
|
56
|
-
shexj
|
60
|
+
shexj = %({
|
61
|
+
"@context": "http://www.w3.org/ns/shex.jsonld",
|
57
62
|
"type": "Schema",
|
58
|
-
"
|
59
|
-
"
|
60
|
-
"
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
"
|
65
|
-
|
66
|
-
|
67
|
-
"
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
"type": "EachOf",
|
82
|
-
"expressions": [
|
83
|
-
{
|
84
|
-
"type": "TripleConstraint",
|
85
|
-
"predicate": "http://usefulinc.com/ns/doap#name",
|
86
|
-
"valueExpr": {"type": "NodeConstraint", "nodeKind": "literal"}
|
87
|
-
},
|
88
|
-
{
|
89
|
-
"type": "TripleConstraint",
|
90
|
-
"predicate": "http://usefulinc.com/ns/doap#description",
|
91
|
-
"valueExpr": {"type": "NodeConstraint", "nodeKind": "literal"}
|
92
|
-
}
|
93
|
-
]
|
94
|
-
},
|
95
|
-
{
|
96
|
-
"type": "EachOf",
|
97
|
-
"expressions": [
|
98
|
-
{
|
99
|
-
"type": "TripleConstraint",
|
100
|
-
"predicate": "http://purl.org/dc/terms/title",
|
101
|
-
"valueExpr": {"type": "NodeConstraint", "nodeKind": "literal"}
|
102
|
-
},
|
103
|
-
{
|
104
|
-
"type": "TripleConstraint",
|
105
|
-
"predicate": "http://purl.org/dc/terms/description",
|
106
|
-
"valueExpr": {"type": "NodeConstraint", "nodeKind": "literal"}
|
107
|
-
}
|
108
|
-
]
|
63
|
+
"shapes": [{
|
64
|
+
"id": "http://example.com/TestShape",
|
65
|
+
"type": "Shape",
|
66
|
+
"extra": ["http://www.w3.org/1999/02/22-rdf-syntax-ns#type"],
|
67
|
+
"expression": {
|
68
|
+
"type": "EachOf",
|
69
|
+
"expressions": [{
|
70
|
+
"type": "TripleConstraint",
|
71
|
+
"predicate": "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
|
72
|
+
"valueExpr": {
|
73
|
+
"type": "NodeConstraint",
|
74
|
+
"values": ["http://usefulinc.com/ns/doap#Project"]
|
75
|
+
}
|
76
|
+
}, {
|
77
|
+
"type": "OneOf",
|
78
|
+
"expressions": [{
|
79
|
+
"type": "EachOf",
|
80
|
+
"expressions": [{
|
81
|
+
"type": "TripleConstraint",
|
82
|
+
"predicate": "http://usefulinc.com/ns/doap#name",
|
83
|
+
"valueExpr": {
|
84
|
+
"type": "NodeConstraint",
|
85
|
+
"nodeKind": "literal"
|
109
86
|
}
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
87
|
+
}, {
|
88
|
+
"type": "TripleConstraint",
|
89
|
+
"predicate": "http://usefulinc.com/ns/doap#description",
|
90
|
+
"valueExpr": {
|
91
|
+
"type": "NodeConstraint",
|
92
|
+
"nodeKind": "literal"
|
93
|
+
}
|
94
|
+
}]
|
95
|
+
}, {
|
96
|
+
"type": "EachOf",
|
97
|
+
"expressions": [{
|
98
|
+
"type": "TripleConstraint",
|
99
|
+
"predicate": "http://purl.org/dc/terms/title",
|
100
|
+
"valueExpr": {
|
101
|
+
"type": "NodeConstraint",
|
102
|
+
"nodeKind": "literal"
|
103
|
+
}
|
104
|
+
}, {
|
105
|
+
"type": "TripleConstraint",
|
106
|
+
"predicate": "http://purl.org/dc/terms/description",
|
107
|
+
"valueExpr": {
|
108
|
+
"type": "NodeConstraint",
|
109
|
+
"nodeKind": "literal"
|
110
|
+
}
|
111
|
+
}]
|
112
|
+
}],
|
113
|
+
"min": 1,
|
114
|
+
"max": -1
|
115
|
+
}, {
|
116
|
+
"type": "TripleConstraint",
|
117
|
+
"predicate": "http://usefulinc.com/ns/doap#category",
|
118
|
+
"valueExpr": {
|
119
|
+
"type": "NodeConstraint",
|
120
|
+
"nodeKind": "iri"
|
118
121
|
},
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
122
|
+
"min": 0,
|
123
|
+
"max": -1
|
124
|
+
}, {
|
125
|
+
"type": "TripleConstraint",
|
126
|
+
"predicate": "http://usefulinc.com/ns/doap#developer",
|
127
|
+
"valueExpr": {
|
128
|
+
"type": "NodeConstraint",
|
129
|
+
"nodeKind": "iri"
|
124
130
|
},
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
131
|
+
"min": 1,
|
132
|
+
"max": -1
|
133
|
+
}, {
|
134
|
+
"type": "TripleConstraint",
|
135
|
+
"predicate": "http://usefulinc.com/ns/doap#implements",
|
136
|
+
"valueExpr": {
|
137
|
+
"type": "NodeConstraint",
|
138
|
+
"values": [
|
139
|
+
"http://shex.io/shex-semantics/"
|
140
|
+
]
|
132
141
|
}
|
133
|
-
|
134
|
-
|
142
|
+
}
|
143
|
+
]
|
135
144
|
}
|
136
145
|
}
|
137
|
-
})
|
146
|
+
]})
|
138
147
|
graph = RDF::Graph.load("etc/doap.ttl")
|
139
148
|
schema = ShEx.parse(shexj, format: :shexj)
|
140
|
-
map = {
|
141
|
-
|
149
|
+
map = {
|
150
|
+
RDF::URI("https://rubygems.org/gems/shex") => RDF::URI("http://example.com/TestShape")
|
151
|
+
}
|
152
|
+
schema.satisfies?(graph, map)
|
142
153
|
# => true
|
143
154
|
|
144
155
|
## Extensions
|
@@ -179,20 +190,18 @@ Example usage:
|
|
179
190
|
|
180
191
|
## Documentation
|
181
192
|
|
182
|
-
<https://
|
193
|
+
<https://ruby-rdf.github.io/shex>
|
183
194
|
|
184
195
|
|
185
196
|
## Implementation Notes
|
186
|
-
The ShExC parser uses the [EBNF][] gem to generate
|
187
|
-
|
188
|
-
The parser takes branch and follow tables generated from the [ShEx Grammar](file.shex.html) described in the [specification][ShExSpec]. Branch and Follow tables are specified in the generated {ShEx::Meta}.
|
197
|
+
The ShExC parser uses the [EBNF][] gem to generate a [PEG][] parser.
|
189
198
|
|
190
|
-
The
|
199
|
+
The parser uses the executable [S-Expressions][] generated from the EBNF ShExC grammar to create a set of executable {ShEx::Algebra} Operators which are directly executed to perform shape validation.
|
191
200
|
|
192
201
|
## Dependencies
|
193
202
|
|
194
|
-
* [Ruby](https://ruby-lang.org/) (>= 2.
|
195
|
-
* [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.
|
203
|
+
* [Ruby](https://ruby-lang.org/) (>= 2.6)
|
204
|
+
* [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.2)
|
196
205
|
* [SPARQL gem](https://rubygems.org/gems/sparql) (~> 3.1)
|
197
206
|
|
198
207
|
## Installation
|
@@ -215,7 +224,7 @@ follows:
|
|
215
224
|
|
216
225
|
## Resources
|
217
226
|
|
218
|
-
* <https://
|
227
|
+
* <https://ruby-rdf.github.io/shex>
|
219
228
|
* <https://github.com/ruby-rdf/shex>
|
220
229
|
* <https://rubygems.org/gems/shex>
|
221
230
|
|
@@ -255,8 +264,10 @@ see <https://unlicense.org/> or the accompanying {file:LICENSE} file.
|
|
255
264
|
|
256
265
|
[ShExSpec]: http://shex.io/shex-semantics-20170713/
|
257
266
|
[RDF]: https://www.w3.org/RDF/
|
258
|
-
[RDF.rb]: https://
|
267
|
+
[RDF.rb]: https://ruby-rdf.github.io/rdf
|
259
268
|
[EBNF]: https://rubygems.org/gems/ebnf
|
260
269
|
[YARD]: https://yardoc.org/
|
261
270
|
[YARD-GS]: https://rubydoc.info/docs/yard/file/docs/GettingStarted.md
|
262
271
|
[PDD]: https://unlicense.org/#unlicensing-contributions
|
272
|
+
[PEG]: https://en.wikipedia.org/wiki/Parsing_expression_grammar "Parsing Expression Grammar"
|
273
|
+
[S-Expression]: https://en.wikipedia.org/wiki/S-expression
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.7.1
|
data/etc/doap.ttl
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
|
11
11
|
<https://rubygems.org/gems/shex> a doap:Project, earl:TestSubject, earl:Software ;
|
12
12
|
doap:name "ShEx" ;
|
13
|
-
doap:homepage <https://ruby-rdf.github.
|
13
|
+
doap:homepage <https://ruby-rdf.github.io/shex> ;
|
14
14
|
doap:license <https://unlicense.org/1.0/> ;
|
15
15
|
doap:shortdesc "ShEx is a Shape Expression engine for Ruby RDF.rb."@en ;
|
16
16
|
doap:description "ShEx is an Shape Expression engine for the Ruby RDF.rb library suite."@en ;
|
data/lib/shex/algebra/and.rb
CHANGED
@@ -61,22 +61,13 @@ module ShEx::Algebra
|
|
61
61
|
end
|
62
62
|
|
63
63
|
##
|
64
|
-
# expressions must be ShapeExpressions
|
64
|
+
# expressions must be ShapeExpressions or references to ShapeExpressions
|
65
65
|
#
|
66
66
|
# @return [Operator] `self`
|
67
67
|
# @raise [ShEx::StructureError] if the value is invalid
|
68
68
|
def validate!
|
69
|
-
|
70
|
-
|
71
|
-
when ShapeExpression
|
72
|
-
when RDF::Resource
|
73
|
-
ref = schema.find(op)
|
74
|
-
ref.is_a?(ShapeExpression) ||
|
75
|
-
structure_error("#{json_type} must reference a ShapeExpression: #{ref}")
|
76
|
-
else
|
77
|
-
structure_error("#{json_type} must reference a ShapeExpression: #{ref}")
|
78
|
-
end
|
79
|
-
end
|
69
|
+
validate_expressions!
|
70
|
+
validate_self_references!
|
80
71
|
super
|
81
72
|
end
|
82
73
|
|
data/lib/shex/algebra/each_of.rb
CHANGED
@@ -73,22 +73,12 @@ module ShEx::Algebra
|
|
73
73
|
end
|
74
74
|
|
75
75
|
##
|
76
|
-
# expressions must be TripleExpressions
|
76
|
+
# expressions must be TripleExpressions or references to TripleExpressions
|
77
77
|
#
|
78
78
|
# @return [Operator] `self`
|
79
79
|
# @raise [ShEx::StructureError] if the value is invalid
|
80
80
|
def validate!
|
81
|
-
|
82
|
-
case op
|
83
|
-
when TripleExpression
|
84
|
-
when RDF::Resource
|
85
|
-
ref = schema.find(op)
|
86
|
-
ref.is_a?(TripleExpression) ||
|
87
|
-
structure_error("#{json_type} must reference a TripleExpression: #{ref}")
|
88
|
-
else
|
89
|
-
structure_error("#{json_type} must reference a TripleExpression: #{ref}")
|
90
|
-
end
|
91
|
-
end
|
81
|
+
validate_expressions!
|
92
82
|
super
|
93
83
|
end
|
94
84
|
end
|
data/lib/shex/algebra/not.rb
CHANGED
@@ -45,20 +45,13 @@ module ShEx::Algebra
|
|
45
45
|
end
|
46
46
|
|
47
47
|
##
|
48
|
-
#
|
48
|
+
# expressions must be ShapeExpressions or references to ShapeExpressions and must not reference itself recursively.
|
49
49
|
#
|
50
50
|
# @return [Operator] `self`
|
51
51
|
# @raise [ShEx::StructureError] if the value is invalid
|
52
52
|
def validate!
|
53
|
-
|
54
|
-
|
55
|
-
when RDF::Resource
|
56
|
-
ref = schema.find(expression)
|
57
|
-
ref.is_a?(ShapeExpression) ||
|
58
|
-
structure_error("#{json_type} must reference a ShapeExpression: #{ref}")
|
59
|
-
else
|
60
|
-
structure_error("#{json_type} must reference a ShapeExpression: #{ref}")
|
61
|
-
end
|
53
|
+
validate_expressions!
|
54
|
+
validate_self_references!
|
62
55
|
super
|
63
56
|
end
|
64
57
|
|
data/lib/shex/algebra/one_of.rb
CHANGED
@@ -65,22 +65,12 @@ module ShEx::Algebra
|
|
65
65
|
end
|
66
66
|
|
67
67
|
##
|
68
|
-
# expressions must be TripleExpressions
|
68
|
+
# expressions must be TripleExpressions or references to TripleExpressions
|
69
69
|
#
|
70
70
|
# @return [Operator] `self`
|
71
71
|
# @raise [ShEx::StructureError] if the value is invalid
|
72
72
|
def validate!
|
73
|
-
|
74
|
-
case op
|
75
|
-
when TripleExpression
|
76
|
-
when RDF::Resource
|
77
|
-
ref = schema.find(op)
|
78
|
-
ref.is_a?(TripleExpression) ||
|
79
|
-
structure_error("#{json_type} must reference a TripleExpression: #{ref}")
|
80
|
-
else
|
81
|
-
structure_error("#{json_type} must reference a TripleExpression: #{ref}")
|
82
|
-
end
|
83
|
-
end
|
73
|
+
validate_expressions!
|
84
74
|
super
|
85
75
|
end
|
86
76
|
end
|
@@ -35,8 +35,8 @@ module ShEx::Algebra
|
|
35
35
|
# @option options [RDF::Resource] :id
|
36
36
|
# Identifier of the operator
|
37
37
|
# @raise [TypeError] if any operand is invalid
|
38
|
-
def initialize(*operands)
|
39
|
-
@options =
|
38
|
+
def initialize(*operands, **options)
|
39
|
+
@options = options.dup
|
40
40
|
@operands = operands.map! do |operand|
|
41
41
|
case operand
|
42
42
|
when Array
|
@@ -221,12 +221,19 @@ module ShEx::Algebra
|
|
221
221
|
end
|
222
222
|
|
223
223
|
##
|
224
|
-
# The
|
225
|
-
# @return [
|
224
|
+
# The first expression from {#expressions}.
|
225
|
+
# @return [RDF::Resource, Operand]
|
226
226
|
def expression
|
227
227
|
expressions.first
|
228
228
|
end
|
229
229
|
|
230
|
+
##
|
231
|
+
# References are all operands which are RDF::Resource
|
232
|
+
# @return [RDF::Resource, Operand]
|
233
|
+
def references
|
234
|
+
@references = operands.select {|op| op.is_a?(RDF::Resource)}
|
235
|
+
end
|
236
|
+
|
230
237
|
##
|
231
238
|
# Returns the binary S-Expression (SXP) representation of this operator.
|
232
239
|
#
|
@@ -242,15 +249,10 @@ module ShEx::Algebra
|
|
242
249
|
# Returns an S-Expression (SXP) representation of this operator
|
243
250
|
#
|
244
251
|
# @return [String]
|
245
|
-
def to_sxp
|
246
|
-
begin
|
247
|
-
require 'sxp' # @see https://rubygems.org/gems/sxp
|
248
|
-
rescue LoadError
|
249
|
-
abort "SPARQL::Algebra::Operator#to_sxp requires the SXP gem (hint: `gem install sxp')."
|
250
|
-
end
|
252
|
+
def to_sxp(**options)
|
251
253
|
require 'sparql/algebra/sxp_extensions'
|
252
254
|
|
253
|
-
to_sxp_bin.to_sxp
|
255
|
+
to_sxp_bin.to_sxp(**options)
|
254
256
|
end
|
255
257
|
|
256
258
|
##
|
@@ -432,6 +434,8 @@ module ShEx::Algebra
|
|
432
434
|
case self
|
433
435
|
when And, Or
|
434
436
|
(obj['shapeExprs'] ||= []) << op.to_h
|
437
|
+
when Not
|
438
|
+
obj['shapeExpr'] = op.to_h
|
435
439
|
else
|
436
440
|
obj['valueExpr'] = op.to_h
|
437
441
|
end
|
@@ -593,22 +597,23 @@ module ShEx::Algebra
|
|
593
597
|
|
594
598
|
##
|
595
599
|
# Enumerate via depth-first recursive descent over operands, yielding each operator
|
600
|
+
# @param [Boolean] include_self
|
596
601
|
# @yield operator
|
597
602
|
# @yieldparam [Object] operator
|
598
603
|
# @return [Enumerator]
|
599
|
-
def each_descendant(&block)
|
604
|
+
def each_descendant(include_self = false, &block)
|
600
605
|
if block_given?
|
601
606
|
|
602
|
-
block.call(self)
|
607
|
+
block.call(self) if include_self
|
603
608
|
|
604
609
|
operands.each do |operand|
|
605
610
|
case operand
|
606
611
|
when Array
|
607
612
|
operand.each do |op|
|
608
|
-
op.each_descendant(&block) if op.respond_to?(:each_descendant)
|
613
|
+
op.each_descendant(true, &block) if op.respond_to?(:each_descendant)
|
609
614
|
end
|
610
615
|
else
|
611
|
-
operand.each_descendant(&block) if operand.respond_to?(:each_descendant)
|
616
|
+
operand.each_descendant(true, &block) if operand.respond_to?(:each_descendant)
|
612
617
|
end
|
613
618
|
end
|
614
619
|
end
|
@@ -631,6 +636,14 @@ module ShEx::Algebra
|
|
631
636
|
@options[:parent]= operator
|
632
637
|
end
|
633
638
|
|
639
|
+
##
|
640
|
+
# Find a ShapeExpression or TripleExpression by identifier
|
641
|
+
# @param [#to_s] id
|
642
|
+
# @return [TripleExpression, ShapeExpression]
|
643
|
+
def find(id)
|
644
|
+
each_descendant(false).detect {|op| op.id == id}
|
645
|
+
end
|
646
|
+
|
634
647
|
##
|
635
648
|
# Ancestors of this Operator
|
636
649
|
# @return [Array<Operator>]
|
data/lib/shex/algebra/or.rb
CHANGED
@@ -67,22 +67,13 @@ module ShEx::Algebra
|
|
67
67
|
end
|
68
68
|
|
69
69
|
##
|
70
|
-
# expressions must be ShapeExpressions
|
70
|
+
# expressions must be ShapeExpressions or references to ShapeExpressions
|
71
71
|
#
|
72
72
|
# @return [Operator] `self`
|
73
73
|
# @raise [ShEx::StructureError] if the value is invalid
|
74
74
|
def validate!
|
75
|
-
|
76
|
-
|
77
|
-
when ShapeExpression
|
78
|
-
when RDF::Resource
|
79
|
-
ref = schema.find(op)
|
80
|
-
ref.is_a?(ShapeExpression) ||
|
81
|
-
structure_error("#{json_type} must reference a ShapeExpression: #{ref}")
|
82
|
-
else
|
83
|
-
structure_error("#{json_type} must reference a ShapeExpression: #{ref}")
|
84
|
-
end
|
85
|
-
end
|
75
|
+
validate_expressions!
|
76
|
+
validate_self_references!
|
86
77
|
super
|
87
78
|
end
|
88
79
|
|
data/lib/shex/algebra/schema.rb
CHANGED
@@ -25,8 +25,9 @@ module ShEx::Algebra
|
|
25
25
|
end
|
26
26
|
|
27
27
|
# (see Operator#initialize)
|
28
|
-
def initialize(*operands)
|
28
|
+
def initialize(*operands, **options)
|
29
29
|
super
|
30
|
+
schema = self
|
30
31
|
each_descendant do |op|
|
31
32
|
# Set schema everywhere
|
32
33
|
op.schema = self
|
@@ -211,14 +212,6 @@ module ShEx::Algebra
|
|
211
212
|
@start ||= operands.detect {|op| op.is_a?(Start)}
|
212
213
|
end
|
213
214
|
|
214
|
-
##
|
215
|
-
# Find a ShapeExpression or TripleExpression by identifier
|
216
|
-
# @param [#to_s] id
|
217
|
-
# @return [TripleExpression, ShapeExpression]
|
218
|
-
def find(id)
|
219
|
-
each_descendant.detect {|op| op.id == id}
|
220
|
-
end
|
221
|
-
|
222
215
|
##
|
223
216
|
# Validate shapes, in addition to other operands
|
224
217
|
# @return [Operator] `self`
|
data/lib/shex/algebra/shape.rb
CHANGED
@@ -106,7 +106,7 @@ module ShEx::Algebra
|
|
106
106
|
end
|
107
107
|
|
108
108
|
##
|
109
|
-
# expression must be a TripleExpression
|
109
|
+
# expression must be a TripleExpression and must not reference itself recursively.
|
110
110
|
#
|
111
111
|
# @return [Operator] `self`
|
112
112
|
# @raise [ShEx::StructureError] if the value is invalid
|
@@ -118,8 +118,10 @@ module ShEx::Algebra
|
|
118
118
|
ref.is_a?(TripleExpression) ||
|
119
119
|
structure_error("#{json_type} must reference a TripleExpression: #{ref}")
|
120
120
|
else
|
121
|
-
structure_error("#{json_type} must
|
121
|
+
structure_error("#{json_type} must be a TripleExpression or reference: #{expression.to_sxp}")
|
122
122
|
end
|
123
|
+
# FIXME: this runs afoul of otherwise legitamate self-references, through a TripleExpression.
|
124
|
+
#!validate_self_references!
|
123
125
|
super
|
124
126
|
end
|
125
127
|
|
@@ -15,5 +15,34 @@ module ShEx::Algebra
|
|
15
15
|
def satisfies?(focus, depth: 0, **options)
|
16
16
|
raise NotImplementedError, "#satisfies? Not implemented in #{self.class}"
|
17
17
|
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# expressions must be ShapeExpressions or references.
|
21
|
+
#
|
22
|
+
# @raise [ShEx::StructureError] if the value is invalid
|
23
|
+
def validate_expressions!
|
24
|
+
expressions.each do |op|
|
25
|
+
case op
|
26
|
+
when ShapeExpression
|
27
|
+
when RDF::Resource
|
28
|
+
ref = schema.find(op)
|
29
|
+
ref.is_a?(ShapeExpression) ||
|
30
|
+
structure_error("#{json_type} must reference a ShapeExpression: #{ref}")
|
31
|
+
else
|
32
|
+
structure_error("#{json_type} must be a ShapeExpression or reference: #{op.to_sxp}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# An Operator with a label must contain a reference to itself.
|
39
|
+
#
|
40
|
+
# @raise [ShEx::StructureError] if the shape is invalid
|
41
|
+
def validate_self_references!
|
42
|
+
return # FIXME: needs to stop at a TripleConstraint
|
43
|
+
each_descendant do |op|
|
44
|
+
structure_error("#{json_type} must not reference itself (#{id}): #{op.to_sxp}") if op.references.include?(id)
|
45
|
+
end
|
46
|
+
end
|
18
47
|
end
|
19
48
|
end
|
data/lib/shex/algebra/start.rb
CHANGED
@@ -30,20 +30,12 @@ module ShEx::Algebra
|
|
30
30
|
end
|
31
31
|
|
32
32
|
##
|
33
|
-
#
|
33
|
+
# expressions must be ShapeExpressions or references to ShapeExpressions
|
34
34
|
#
|
35
35
|
# @return [Operator] `self`
|
36
36
|
# @raise [ShEx::StructureError] if the value is invalid
|
37
37
|
def validate!
|
38
|
-
|
39
|
-
when ShapeExpression
|
40
|
-
when RDF::Resource
|
41
|
-
ref = schema.find(expression)
|
42
|
-
ref.is_a?(ShapeExpression) ||
|
43
|
-
structure_error("#{json_type} must reference a ShapeExpression: #{ref}")
|
44
|
-
else
|
45
|
-
structure_error("#{json_type} must reference a ShapeExpression: #{ref}")
|
46
|
-
end
|
38
|
+
validate_expressions!
|
47
39
|
super
|
48
40
|
end
|
49
41
|
end
|
data/lib/shex/algebra/stem.rb
CHANGED
@@ -66,8 +66,12 @@ module ShEx::Algebra
|
|
66
66
|
NAME = :languageStem
|
67
67
|
|
68
68
|
# (see Stem#match?)
|
69
|
+
# If the operand is empty, than any language will do,
|
70
|
+
# otherwise, it matches the substring up to that first '-', if any.
|
69
71
|
def match?(value, depth: 0)
|
70
|
-
if value.literal? &&
|
72
|
+
if value.literal? &&
|
73
|
+
value.language? &&
|
74
|
+
(operands.first.to_s.empty? || value.language.to_s.match?(%r(^#{operands.first}((-.*)?)$)))
|
71
75
|
status "matched #{value}", depth: depth
|
72
76
|
true
|
73
77
|
else
|