shex 0.6.0 → 0.6.4
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/AUTHORS +1 -1
- data/LICENSE +1 -1
- data/README.md +133 -118
- data/VERSION +1 -1
- data/etc/doap.ttl +17 -19
- 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 +32 -20
- data/lib/shex/algebra/or.rb +3 -12
- data/lib/shex/algebra/schema.rb +4 -11
- data/lib/shex/algebra/semact.rb +8 -8
- data/lib/shex/algebra/shape.rb +6 -4
- 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 +1 -2
- data/lib/shex/extensions/test.rb +18 -16
- data/lib/shex/format.rb +2 -4
- data/lib/shex/meta.rb +325 -9859
- data/lib/shex/parser.rb +563 -478
- data/lib/shex/terminals.rb +5 -25
- data/lib/shex.rb +7 -4
- metadata +48 -13
@@ -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
|
#
|
@@ -243,11 +250,6 @@ module ShEx::Algebra
|
|
243
250
|
#
|
244
251
|
# @return [String]
|
245
252
|
def to_sxp
|
246
|
-
begin
|
247
|
-
require 'sxp' # @see http://rubygems.org/gems/sxp
|
248
|
-
rescue LoadError
|
249
|
-
abort "SPARQL::Algebra::Operator#to_sxp requires the SXP gem (hint: `gem install sxp')."
|
250
|
-
end
|
251
253
|
require 'sparql/algebra/sxp_extensions'
|
252
254
|
|
253
255
|
to_sxp_bin.to_sxp
|
@@ -335,7 +337,7 @@ module ShEx::Algebra
|
|
335
337
|
end
|
336
338
|
end
|
337
339
|
|
338
|
-
new(*operands, options.merge(id: id))
|
340
|
+
new(*operands, **options.merge(id: id))
|
339
341
|
end
|
340
342
|
|
341
343
|
def json_type
|
@@ -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,23 +597,23 @@ module ShEx::Algebra
|
|
593
597
|
|
594
598
|
##
|
595
599
|
# Enumerate via depth-first recursive descent over operands, yielding each operator
|
596
|
-
# @param [
|
600
|
+
# @param [Boolean] include_self
|
597
601
|
# @yield operator
|
598
602
|
# @yieldparam [Object] operator
|
599
603
|
# @return [Enumerator]
|
600
|
-
def each_descendant(&block)
|
604
|
+
def each_descendant(include_self = false, &block)
|
601
605
|
if block_given?
|
602
606
|
|
603
|
-
block.call(self)
|
607
|
+
block.call(self) if include_self
|
604
608
|
|
605
609
|
operands.each do |operand|
|
606
610
|
case operand
|
607
611
|
when Array
|
608
612
|
operand.each do |op|
|
609
|
-
op.each_descendant(&block) if op.respond_to?(:each_descendant)
|
613
|
+
op.each_descendant(true, &block) if op.respond_to?(:each_descendant)
|
610
614
|
end
|
611
615
|
else
|
612
|
-
operand.each_descendant(&block) if operand.respond_to?(:each_descendant)
|
616
|
+
operand.each_descendant(true, &block) if operand.respond_to?(:each_descendant)
|
613
617
|
end
|
614
618
|
end
|
615
619
|
end
|
@@ -632,6 +636,14 @@ module ShEx::Algebra
|
|
632
636
|
@options[:parent]= operator
|
633
637
|
end
|
634
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
|
+
|
635
647
|
##
|
636
648
|
# Ancestors of this Operator
|
637
649
|
# @return [Array<Operator>]
|
@@ -661,12 +673,12 @@ module ShEx::Algebra
|
|
661
673
|
self
|
662
674
|
end
|
663
675
|
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
end
|
676
|
+
def dup
|
677
|
+
operands = @operands.map {|o| o.dup rescue o}
|
678
|
+
self.class.new(*operands, id: @id)
|
679
|
+
end
|
669
680
|
|
681
|
+
protected
|
670
682
|
##
|
671
683
|
# A unary operator.
|
672
684
|
#
|
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
|
@@ -39,7 +40,7 @@ module ShEx::Algebra
|
|
39
40
|
# @param [RDF::Queryable] graph
|
40
41
|
# @param [Hash{RDF::Term => <RDF::Resource>}, Array<Array(RDF::Term, RDF::Resource)>] map
|
41
42
|
# A set of (`term`, `resource`) pairs where `term` is a node within `graph`, and `resource` identifies a shape
|
42
|
-
# @param [Array<RDF::Term>]
|
43
|
+
# @param [Array<RDF::Term>] focus ([])
|
43
44
|
# One or more nodes within `graph` for which to run the start expression.
|
44
45
|
# @param [Array<Schema, String>] shapeExterns ([])
|
45
46
|
# One or more schemas, or paths to ShEx schema resources used for finding external shapes.
|
@@ -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`
|
@@ -250,7 +243,7 @@ module ShEx::Algebra
|
|
250
243
|
attr_accessor :expression
|
251
244
|
|
252
245
|
# Holds the result of processing a shape
|
253
|
-
# @param [RDF::Resource]
|
246
|
+
# @param [RDF::Resource] shape
|
254
247
|
# @return [ShapeResult]
|
255
248
|
def initialize(shape)
|
256
249
|
@shape = shape
|
data/lib/shex/algebra/semact.rb
CHANGED
@@ -18,13 +18,14 @@ module ShEx::Algebra
|
|
18
18
|
##
|
19
19
|
# Called on entry
|
20
20
|
#
|
21
|
-
# @
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
21
|
+
# @overload enter(code, arcs_in, arcs_out, logging)
|
22
|
+
# @param [String] code
|
23
|
+
# @param [Array<RDF::Statement>] arcs_in available statements to be matched having `focus` as an object
|
24
|
+
# @param [Array<RDF::Statement>] arcs_out available statements to be matched having `focus` as a subject
|
25
|
+
# @param [Integer] depth for logging
|
26
|
+
# @param [Hash{Symbol => Object}] options
|
27
|
+
# Other, operand-specific options
|
28
|
+
# @return [Boolean] Returning `false` results in {ShEx::NotSatisfied} exception
|
28
29
|
def enter(**options)
|
29
30
|
if implementation = schema.extensions[operands.first.to_s]
|
30
31
|
implementation.enter(code: operands[0], expression: parent, **options)
|
@@ -67,7 +68,6 @@ module ShEx::Algebra
|
|
67
68
|
# @param [String] code
|
68
69
|
# @param [Array<RDF::Statement>] matched statements matched by this expression
|
69
70
|
# @param [Array<RDF::Statement>] unmatched statements considered, but not matched by this expression
|
70
|
-
# @param [ShEx::Algebra::TripleExpression] expression containing this semantic act
|
71
71
|
# @param [Integer] depth for logging
|
72
72
|
# @param [Hash{Symbol => Object}] options
|
73
73
|
# Other, operand-specific options
|
data/lib/shex/algebra/shape.rb
CHANGED
@@ -36,8 +36,8 @@ module ShEx::Algebra
|
|
36
36
|
# neigh(G, n) is the neighbourhood of the node n in the graph G.
|
37
37
|
#
|
38
38
|
# neigh(G, n) = arcsOut(G, n) ∪ arcsIn(G, n)
|
39
|
-
arcs_in = schema.graph.query(object: focus).to_a.sort_by(&:to_sxp)
|
40
|
-
arcs_out = schema.graph.query(subject: focus).to_a.sort_by(&:to_sxp)
|
39
|
+
arcs_in = schema.graph.query({object: focus}).to_a.sort_by(&:to_sxp)
|
40
|
+
arcs_out = schema.graph.query({subject: focus}).to_a.sort_by(&:to_sxp)
|
41
41
|
neigh = (arcs_in + arcs_out).uniq
|
42
42
|
|
43
43
|
# `matched` is the subset of statements which match `expression`.
|
@@ -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
|
@@ -102,7 +102,9 @@ module ShEx::Algebra
|
|
102
102
|
def match?(value, depth: 0)
|
103
103
|
initial_match = case operands.first
|
104
104
|
when :wildcard then true
|
105
|
-
when RDF::Literal
|
105
|
+
when RDF::Literal
|
106
|
+
value.language? &&
|
107
|
+
(operands.first.to_s.empty? || value.language.to_s.match?(%r(^#{operands.first}((-.*)?)$)))
|
106
108
|
else false
|
107
109
|
end
|
108
110
|
|
@@ -97,7 +97,7 @@ module ShEx::Algebra
|
|
97
97
|
ref.is_a?(ShapeExpression) ||
|
98
98
|
structure_error("#{json_type} must reference a ShapeExpression: #{ref}")
|
99
99
|
else
|
100
|
-
structure_error("#{json_type} must
|
100
|
+
structure_error("#{json_type} must be a ShapeExpression or reference: #{expresson.to_sxp}")
|
101
101
|
end
|
102
102
|
super
|
103
103
|
end
|
@@ -16,6 +16,24 @@ module ShEx::Algebra
|
|
16
16
|
raise NotImplementedError, "#matches Not implemented in #{self.class}"
|
17
17
|
end
|
18
18
|
|
19
|
+
##
|
20
|
+
# expressions must be TripleExpressions or references to TripleExpressions
|
21
|
+
#
|
22
|
+
# @raise [ShEx::StructureError] if the value is invalid
|
23
|
+
def validate_expressions!
|
24
|
+
expressions.each do |op|
|
25
|
+
case op
|
26
|
+
when TripleExpression
|
27
|
+
when RDF::Resource
|
28
|
+
ref = schema.find(op)
|
29
|
+
ref.is_a?(TripleExpression) ||
|
30
|
+
structure_error("#{json_type} must reference a TripleExpression: #{ref}")
|
31
|
+
else
|
32
|
+
structure_error("#{json_type} must be a TripleExpression or reference: #{op.to_sxp}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
19
37
|
##
|
20
38
|
# Included TripleConstraints
|
21
39
|
# @return [Array<TripleConstraints>]
|
data/lib/shex/algebra.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
$:.unshift(File.expand_path("../..", __FILE__))
|
2
2
|
require 'sparql/algebra'
|
3
|
-
require 'sxp'
|
4
3
|
|
5
4
|
module ShEx
|
6
5
|
# Based on the SPARQL Algebra, operators for executing a patch
|
7
6
|
#
|
8
|
-
# @author [Gregg Kellogg](
|
7
|
+
# @author [Gregg Kellogg](https://greggkellogg.net/)
|
9
8
|
module Algebra
|
10
9
|
autoload :And, 'shex/algebra/and'
|
11
10
|
autoload :Annotation, 'shex/algebra/annotation'
|
data/lib/shex/extensions/test.rb
CHANGED
@@ -6,21 +6,23 @@
|
|
6
6
|
# @see http://shex.io/extensions/Test/
|
7
7
|
require 'shex'
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
md
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
9
|
+
module ShEx
|
10
|
+
Test = Class.new(ShEx::Extension("http://shex.io/extensions/Test/")) do
|
11
|
+
# (see ShEx::Extension#visit)
|
12
|
+
def visit(code: nil, matched: nil, depth: 0, **options)
|
13
|
+
str = if md = /^ *(fail|print) *\( *(?:(\"(?:[^\\"]|\\")*\")|([spo])) *\) *$/.match(code.to_s)
|
14
|
+
md[2] || case md[3]
|
15
|
+
when 's' then matched.subject
|
16
|
+
when 'p' then matched.predicate
|
17
|
+
when 'o' then matched.object
|
18
|
+
else matched.to_sxp
|
19
|
+
end.to_s
|
20
|
+
else
|
21
|
+
matched ? matched.to_sxp : 'no statement'
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
-
|
24
|
+
$stdout.puts str
|
25
|
+
return !md || md[1] == 'print'
|
26
|
+
end
|
25
27
|
end
|
26
|
-
end
|
28
|
+
end
|
data/lib/shex/format.rb
CHANGED
@@ -4,14 +4,12 @@ module ShEx
|
|
4
4
|
##
|
5
5
|
# ShEx format specification. Note that this format does not define any readers or writers.
|
6
6
|
#
|
7
|
-
# @example Obtaining an
|
8
|
-
# RDF::Format.for(:shex) #=>
|
7
|
+
# @example Obtaining an ShEx format class
|
8
|
+
# RDF::Format.for(:shex) #=> ShEx::Format
|
9
9
|
# RDF::Format.for("etc/foaf.shex")
|
10
10
|
# RDF::Format.for(file_name: "etc/foaf.shex")
|
11
11
|
# RDF::Format.for(file_extension: "shex")
|
12
12
|
# RDF::Format.for(content_type: "application/shex")
|
13
|
-
#
|
14
|
-
# @see http://www.w3.org/TR/ldpatch/
|
15
13
|
class Format < RDF::Format
|
16
14
|
content_type 'application/shex', extension: :shex
|
17
15
|
content_encoding 'utf-8'
|