shacl 0.2.1 → 0.4.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 +4 -4
- data/README.md +11 -6
- data/VERSION +1 -1
- data/lib/rdf/vocab/shacl.rb +1096 -1096
- data/lib/shacl/algebra/and.rb +3 -2
- data/lib/shacl/algebra/constraint_component.rb +67 -0
- data/lib/shacl/algebra/node_shape.rb +10 -16
- data/lib/shacl/algebra/not.rb +3 -2
- data/lib/shacl/algebra/operator.rb +312 -44
- data/lib/shacl/algebra/or.rb +3 -2
- data/lib/shacl/algebra/pattern.rb +43 -0
- data/lib/shacl/algebra/property_shape.rb +11 -16
- data/lib/shacl/algebra/{qualified_value_shape.rb → qualified_value.rb} +14 -8
- data/lib/shacl/algebra/shape.rb +12 -41
- data/lib/shacl/algebra/sparql_constraint.rb +160 -0
- data/lib/shacl/algebra/xone.rb +3 -2
- data/lib/shacl/algebra.rb +30 -13
- data/lib/shacl/context.rb +5 -0
- data/lib/shacl/shapes.rb +99 -14
- data/lib/shacl/validation_result.rb +22 -19
- data/lib/shacl.rb +10 -5
- metadata +36 -19
data/lib/shacl/shapes.rb
CHANGED
@@ -9,6 +9,12 @@ module SHACL
|
|
9
9
|
class Shapes < Array
|
10
10
|
include RDF::Util::Logger
|
11
11
|
|
12
|
+
# The original shapes graph
|
13
|
+
#
|
14
|
+
# @return [RDF::Graph]
|
15
|
+
attr_reader :shapes_graph
|
16
|
+
|
17
|
+
|
12
18
|
# The graphs which have been loaded as shapes
|
13
19
|
#
|
14
20
|
# @return [Array<RDF::URI>]
|
@@ -28,6 +34,7 @@ module SHACL
|
|
28
34
|
#
|
29
35
|
# @param [RDF::Graph] graph
|
30
36
|
# @param [Array<RDF::URI>] loaded_graphs = []
|
37
|
+
# The graphs which have been loaded as shapes
|
31
38
|
# @param [Hash{Symbol => Object}] options
|
32
39
|
# @return [Shapes]
|
33
40
|
# @raise [SHACL::Error]
|
@@ -38,20 +45,43 @@ module SHACL
|
|
38
45
|
while (imports = graph.query({predicate: RDF::OWL.imports}).map(&:object)).count > import_count
|
39
46
|
# Load each imported graph
|
40
47
|
imports.each do |ref|
|
41
|
-
graph
|
42
|
-
|
48
|
+
# Don't try import if the import subject is already in the graph
|
49
|
+
unless graph.subject?(ref)
|
50
|
+
begin
|
51
|
+
options[:logger].info('Shapes') {"load import #{ref}"} if options[:logger].respond_to?(:info)
|
52
|
+
graph.load(ref)
|
53
|
+
loaded_graphs << ref
|
54
|
+
rescue IOError => e
|
55
|
+
# Skip import
|
56
|
+
options[:logger].warn('Shapes') {"load import #{ref}"} if options[:logger].respond_to?(:warn)
|
57
|
+
end
|
58
|
+
end
|
43
59
|
import_count += 1
|
44
60
|
end
|
45
61
|
end
|
46
62
|
|
47
63
|
# Serialize the graph as framed JSON-LD and initialize patterns, recursively.
|
48
|
-
|
49
|
-
|
50
|
-
|
64
|
+
expanded = JSON::LD::API.fromRdf(graph, useNativeTypes: true)
|
65
|
+
|
66
|
+
# Node and Property constraints
|
67
|
+
shape_json = JSON::LD::API.frame(expanded, SHAPES_FRAME,
|
68
|
+
omitGraph: false,
|
69
|
+
embed: '@always',
|
70
|
+
expanded: true)['@graph']
|
71
|
+
|
72
|
+
# Any defined Constraint Components
|
73
|
+
components = JSON::LD::API.frame(expanded, COMPONENTS_FRAME,
|
74
|
+
omitGraph: false,
|
75
|
+
embed: '@always',
|
76
|
+
expanded: true)['@graph']
|
77
|
+
|
78
|
+
# Extract any constraint components and merge to top-level
|
79
|
+
shape_json = components + shape_json
|
51
80
|
|
52
81
|
# Create an array of the framed shapes
|
53
82
|
shapes = self.new(shape_json.map {|o| Algebra.from_json(o, **options)})
|
54
83
|
shapes.instance_variable_set(:@shape_json, shape_json)
|
84
|
+
shapes.instance_variable_set(:@shapes_graph, graph)
|
55
85
|
shapes
|
56
86
|
end
|
57
87
|
|
@@ -65,11 +95,11 @@ module SHACL
|
|
65
95
|
# @raise [SHACL::Error]
|
66
96
|
def self.from_queryable(queryable, **options)
|
67
97
|
# Query queryable to find one ore more shapes graphs
|
68
|
-
|
69
|
-
graph = RDF::Graph.new do |g|
|
70
|
-
|
98
|
+
graph_names = queryable.query({predicate: RDF::Vocab::SHACL.shapesGraph}).objects
|
99
|
+
graph = RDF::Graph.new(graph_name: graph_names.first, data: RDF::Repository.new) do |g|
|
100
|
+
graph_names.each {|iri| g.load(iri, graph_name: graph_names.first)}
|
71
101
|
end
|
72
|
-
from_graph(graph, loaded_graphs:
|
102
|
+
from_graph(graph, loaded_graphs: graph_names, **options)
|
73
103
|
end
|
74
104
|
|
75
105
|
##
|
@@ -80,12 +110,18 @@ module SHACL
|
|
80
110
|
# @param [Hash{Symbol => Object}] options
|
81
111
|
# @option options [RDF::Term] :focus
|
82
112
|
# An explicit focus node, overriding any defined on the top-level shaps.
|
113
|
+
# @option options [Logger, #write, #<<] :logger
|
114
|
+
# Record error/info/debug output
|
83
115
|
# @return [SHACL::ValidationReport]
|
84
116
|
def execute(graph, depth: 0, **options)
|
85
117
|
self.each do |shape|
|
86
118
|
shape.graph = graph
|
119
|
+
shape.shapes_graph = shapes_graph
|
87
120
|
shape.each_descendant do |op|
|
88
|
-
op.
|
121
|
+
op.instance_variable_set(:@logger, options[:logger]) if
|
122
|
+
options[:logger] && op.respond_to?(:execute)
|
123
|
+
op.graph = graph if op.respond_to?(:graph=)
|
124
|
+
op.shapes_graph = shapes_graph if op.respond_to?(:shapes_graph=)
|
89
125
|
end
|
90
126
|
end
|
91
127
|
|
@@ -115,11 +151,12 @@ module SHACL
|
|
115
151
|
"id": "@id",
|
116
152
|
"type": {"@id": "@type", "@container": "@set"},
|
117
153
|
"@vocab": "http://www.w3.org/ns/shacl#",
|
154
|
+
"owl": "http://www.w3.org/2002/07/owl#",
|
118
155
|
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
|
119
156
|
"shacl": "http://www.w3.org/ns/shacl#",
|
120
157
|
"sh": "http://www.w3.org/ns/shacl#",
|
121
158
|
"xsd": "http://www.w3.org/2001/XMLSchema#",
|
122
|
-
"and": {"@type": "@id"
|
159
|
+
"and": {"@type": "@id"},
|
123
160
|
"annotationProperty": {"@type": "@id"},
|
124
161
|
"class": {"@type": "@id"},
|
125
162
|
"comment": "http://www.w3.org/2000/01/rdf-schema#comment",
|
@@ -130,35 +167,83 @@ module SHACL
|
|
130
167
|
"entailment": {"@type": "@id"},
|
131
168
|
"equals": {"@type": "@id"},
|
132
169
|
"ignoredProperties": {"@type": "@id", "@container": "@list"},
|
170
|
+
"imports": {"@id": "owl:imports", "@type": "@id"},
|
133
171
|
"in": {"@type": "@none", "@container": "@list"},
|
134
172
|
"inversePath": {"@type": "@id"},
|
135
173
|
"label": "http://www.w3.org/2000/01/rdf-schema#label",
|
136
174
|
"languageIn": {"@container": "@list"},
|
137
175
|
"lessThan": {"@type": "@id"},
|
138
176
|
"lessThanOrEquals": {"@type": "@id"},
|
177
|
+
"namespace": {"@type": "xsd:anyURI"},
|
139
178
|
"nodeKind": {"@type": "@vocab"},
|
140
|
-
"or": {"@type": "@id"
|
179
|
+
"or": {"@type": "@id"},
|
141
180
|
"path": {"@type": "@none"},
|
181
|
+
"prefixes": {"@type": "@id"},
|
142
182
|
"property": {"@type": "@id"},
|
143
183
|
"severity": {"@type": "@vocab"},
|
184
|
+
"sparql": {"@type": "@id"},
|
144
185
|
"targetClass": {"@type": "@id"},
|
145
186
|
"targetNode": {"@type": "@none"},
|
146
|
-
"xone": {"@type": "@id"
|
187
|
+
"xone": {"@type": "@id"}
|
147
188
|
},
|
148
189
|
"and": {},
|
149
190
|
"class": {},
|
150
191
|
"datatype": {},
|
151
|
-
"in": {},
|
192
|
+
"in": {"@embed": "@never"},
|
152
193
|
"node": {},
|
153
194
|
"nodeKind": {},
|
154
195
|
"not": {},
|
155
196
|
"or": {},
|
156
197
|
"property": {},
|
198
|
+
"sparql": {},
|
157
199
|
"targetClass": {},
|
158
200
|
"targetNode": {},
|
159
201
|
"targetObjectsOf": {},
|
160
202
|
"xone": {},
|
161
203
|
"targetSubjectsOf": {}
|
162
204
|
})).freeze
|
205
|
+
|
206
|
+
COMPONENTS_FRAME = JSON.parse(%({
|
207
|
+
"@context": {
|
208
|
+
"id": "@id",
|
209
|
+
"type": {"@id": "@type", "@container": "@set"},
|
210
|
+
"@vocab": "http://www.w3.org/ns/shacl#",
|
211
|
+
"owl": "http://www.w3.org/2002/07/owl#",
|
212
|
+
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
|
213
|
+
"shacl": "http://www.w3.org/ns/shacl#",
|
214
|
+
"sh": "http://www.w3.org/ns/shacl#",
|
215
|
+
"xsd": "http://www.w3.org/2001/XMLSchema#",
|
216
|
+
"and": {"@type": "@id"},
|
217
|
+
"annotationProperty": {"@type": "@id"},
|
218
|
+
"class": {"@type": "@id"},
|
219
|
+
"comment": "http://www.w3.org/2000/01/rdf-schema#comment",
|
220
|
+
"condition": {"@type": "@id"},
|
221
|
+
"datatype": {"@type": "@vocab"},
|
222
|
+
"declare": {"@type": "@id"},
|
223
|
+
"disjoint": {"@type": "@id"},
|
224
|
+
"entailment": {"@type": "@id"},
|
225
|
+
"equals": {"@type": "@id"},
|
226
|
+
"ignoredProperties": {"@type": "@id", "@container": "@list"},
|
227
|
+
"imports": {"@id": "owl:imports", "@type": "@id"},
|
228
|
+
"in": {"@type": "@none", "@container": "@list"},
|
229
|
+
"inversePath": {"@type": "@id"},
|
230
|
+
"label": "http://www.w3.org/2000/01/rdf-schema#label",
|
231
|
+
"languageIn": {"@container": "@list"},
|
232
|
+
"lessThan": {"@type": "@id"},
|
233
|
+
"lessThanOrEquals": {"@type": "@id"},
|
234
|
+
"namespace": {"@type": "xsd:anyURI"},
|
235
|
+
"nodeKind": {"@type": "@vocab"},
|
236
|
+
"or": {"@type": "@id"},
|
237
|
+
"path": {"@type": "@id"},
|
238
|
+
"prefixes": {"@type": "@id"},
|
239
|
+
"property": {"@type": "@id"},
|
240
|
+
"severity": {"@type": "@vocab"},
|
241
|
+
"sparql": {"@type": "@id"},
|
242
|
+
"targetClass": {"@type": "@id"},
|
243
|
+
"targetNode": {"@type": "@none"},
|
244
|
+
"xone": {"@type": "@id"}
|
245
|
+
},
|
246
|
+
"@type": "ConstraintComponent"
|
247
|
+
})).freeze
|
163
248
|
end
|
164
249
|
end
|
@@ -115,26 +115,29 @@ module SHACL
|
|
115
115
|
block.call(RDF::Statement(subject, RDF::Vocab::SHACL.resultMessage, RDF::Literal(message))) if message
|
116
116
|
end
|
117
117
|
|
118
|
-
#
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
118
|
+
# Class Methods
|
119
|
+
class << self
|
120
|
+
# Transform a JSON representation of a result, into a native representation
|
121
|
+
# @param [Hash] input
|
122
|
+
# @return [ValidationResult]
|
123
|
+
def from_json(input, **options)
|
124
|
+
input = JSON.parse(input) if input.is_a?(String)
|
125
|
+
input = JSON::LD::API.compact(input,
|
126
|
+
"http://github.com/ruby-rdf/shacl/",
|
127
|
+
expandContext: "http://github.com/ruby-rdf/shacl/")
|
128
|
+
raise ArgumentError, "Expect report to be a hash" unless input.is_a?(Hash)
|
129
|
+
result = self.new
|
128
130
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
131
|
+
result.focus = Algebra::Operator.to_rdf(:focus, input['focusNode'], base: nil, vocab: false) if input['focusNode']
|
132
|
+
result.path = Algebra::Operator.parse_path(input['resultPath'], **options) if input['resultPath']
|
133
|
+
result.resultSeverity = Algebra::Operator.iri(input['resultSeverity'], **options) if input['resultSeverity']
|
134
|
+
result.component = Algebra::Operator.iri(input['sourceConstraintComponent'], **options) if input['sourceConstraintComponent']
|
135
|
+
result.shape = Algebra::Operator.iri(input['sourceShape'], **options) if input['sourceShape']
|
136
|
+
result.value = Algebra::Operator.to_rdf(:value, input['value'], **options) if input['value']
|
137
|
+
result.details = Algebra::Operator.to_rdf(:details, input['details'], **options) if input['details']
|
138
|
+
result.message = Algebra::Operator.to_rdf(:message, input['message'], **options) if input['message']
|
139
|
+
result
|
140
|
+
end
|
138
141
|
end
|
139
142
|
|
140
143
|
# To results are eql? if their overlapping properties are equal
|
data/lib/shacl.rb
CHANGED
@@ -21,8 +21,8 @@ module SHACL
|
|
21
21
|
# @option (see Shapes#from_graph)
|
22
22
|
# @return (see Shapes#from_graph)
|
23
23
|
# @raise (see Shapes#from_graph)
|
24
|
-
def self.get_shapes(
|
25
|
-
Shapes.from_graph(
|
24
|
+
def self.get_shapes(shapes_graph, **options)
|
25
|
+
Shapes.from_graph(shapes_graph, **options)
|
26
26
|
end
|
27
27
|
|
28
28
|
##
|
@@ -33,8 +33,13 @@ module SHACL
|
|
33
33
|
# @return (see Shapes#from_graph)
|
34
34
|
# @raise (see Shapes#from_graph)
|
35
35
|
def self.open(input, **options)
|
36
|
-
graph
|
37
|
-
|
36
|
+
# Create graph backed by repo to allow a graph_name
|
37
|
+
graph = RDF::Graph.load(input,
|
38
|
+
graph_name: RDF::URI(input),
|
39
|
+
data: RDF::Repository.new)
|
40
|
+
self.get_shapes(graph,
|
41
|
+
loaded_graphs: [RDF::URI(input, canonicalize: true)],
|
42
|
+
**options)
|
38
43
|
end
|
39
44
|
|
40
45
|
##
|
@@ -77,7 +82,7 @@ module SHACL
|
|
77
82
|
attr_reader :code
|
78
83
|
|
79
84
|
##
|
80
|
-
# Initializes a new
|
85
|
+
# Initializes a new error instance.
|
81
86
|
#
|
82
87
|
# @param [String, #to_s] message
|
83
88
|
# @param [Hash{Symbol => Object}] options
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shacl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gregg Kellogg
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-08-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rdf
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '3.
|
19
|
+
version: '3.3'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '3.
|
26
|
+
version: '3.3'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: json-ld
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '3.
|
33
|
+
version: '3.3'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '3.
|
40
|
+
version: '3.3'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: sxp
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,70 +58,84 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '3.
|
61
|
+
version: '3.3'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '3.
|
68
|
+
version: '3.3'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rdf-spec
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '3.
|
75
|
+
version: '3.3'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '3.
|
82
|
+
version: '3.3'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rdf-turtle
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '3.
|
89
|
+
version: '3.3'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '3.
|
96
|
+
version: '3.3'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rdf-vocab
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.3'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.3'
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
112
|
name: rdf-xsd
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
100
114
|
requirements:
|
101
115
|
- - "~>"
|
102
116
|
- !ruby/object:Gem::Version
|
103
|
-
version: '3.
|
117
|
+
version: '3.3'
|
104
118
|
type: :development
|
105
119
|
prerelease: false
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
107
121
|
requirements:
|
108
122
|
- - "~>"
|
109
123
|
- !ruby/object:Gem::Version
|
110
|
-
version: '3.
|
124
|
+
version: '3.3'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: rspec
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
114
128
|
requirements:
|
115
129
|
- - "~>"
|
116
130
|
- !ruby/object:Gem::Version
|
117
|
-
version: '3.
|
131
|
+
version: '3.12'
|
118
132
|
type: :development
|
119
133
|
prerelease: false
|
120
134
|
version_requirements: !ruby/object:Gem::Requirement
|
121
135
|
requirements:
|
122
136
|
- - "~>"
|
123
137
|
- !ruby/object:Gem::Version
|
124
|
-
version: '3.
|
138
|
+
version: '3.12'
|
125
139
|
- !ruby/object:Gem::Dependency
|
126
140
|
name: rspec-its
|
127
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -164,13 +178,16 @@ files:
|
|
164
178
|
- lib/shacl.rb
|
165
179
|
- lib/shacl/algebra.rb
|
166
180
|
- lib/shacl/algebra/and.rb
|
181
|
+
- lib/shacl/algebra/constraint_component.rb
|
167
182
|
- lib/shacl/algebra/node_shape.rb
|
168
183
|
- lib/shacl/algebra/not.rb
|
169
184
|
- lib/shacl/algebra/operator.rb
|
170
185
|
- lib/shacl/algebra/or.rb
|
186
|
+
- lib/shacl/algebra/pattern.rb
|
171
187
|
- lib/shacl/algebra/property_shape.rb
|
172
|
-
- lib/shacl/algebra/
|
188
|
+
- lib/shacl/algebra/qualified_value.rb
|
173
189
|
- lib/shacl/algebra/shape.rb
|
190
|
+
- lib/shacl/algebra/sparql_constraint.rb
|
174
191
|
- lib/shacl/algebra/xone.rb
|
175
192
|
- lib/shacl/context.rb
|
176
193
|
- lib/shacl/format.rb
|
@@ -196,14 +213,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
196
213
|
requirements:
|
197
214
|
- - ">="
|
198
215
|
- !ruby/object:Gem::Version
|
199
|
-
version: '
|
216
|
+
version: '3.0'
|
200
217
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
201
218
|
requirements:
|
202
219
|
- - ">="
|
203
220
|
- !ruby/object:Gem::Version
|
204
221
|
version: '0'
|
205
222
|
requirements: []
|
206
|
-
rubygems_version: 3.
|
223
|
+
rubygems_version: 3.2.33
|
207
224
|
signing_key:
|
208
225
|
specification_version: 4
|
209
226
|
summary: Implementation of Shapes Constraint Language (SHACL) for RDF.rb
|