diff --git a/VERSION b/VERSION index 1d0ba9e..267577d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.4.0 +0.4.1 diff --git a/lib/shacl/algebra/node_shape.rb b/lib/shacl/algebra/node_shape.rb index a144993..89c5d5f 100644 --- a/lib/shacl/algebra/node_shape.rb +++ b/lib/shacl/algebra/node_shape.rb @@ -44,7 +44,7 @@ def conforms(node, depth: 0, **options) resultSeverity: options[:severity], component: RDF::Vocab::SHACL.ClosedConstraintComponent, **options) - end.compact + end.flatten.compact elsif @options[:ignoredProperties] raise SHACL::Error, "shape has ignoredProperties without being closed" end diff --git a/spec/shapes_spec.rb b/spec/shapes_spec.rb index c358798..f719e31 100644 --- a/spec/shapes_spec.rb +++ b/spec/shapes_spec.rb @@ -43,6 +43,86 @@ sxp: [:ValidationReport, true, []].to_sxp } } + }, + "nested node shape with closed properties": { + shape: %( + @prefix sh: . + @prefix rdfs: . + @prefix rdf: . + @prefix ex: . + + ex:WithLabelShape a sh:NodeShape ; + sh:closed true ; + sh:property [ + sh:path rdfs:label ; + sh:minCount 1 ; + sh:maxCount 1 ; + ] . + + ex:WithCommentShape a sh:NodeShape ; + sh:closed true ; + sh:property [ + sh:path rdfs:comment ; + sh:minCount 1 ; + sh:maxCount 1 ; + ] . + + ex:ResourceShape a sh:NodeShape ; + sh:targetClass ex:Resource ; + sh:or ( ex:WithLabelShape ex:WithCommentShape ) . + + ), + sxp: %{(shapes + ( + (NodeShape + (id ) + (type shacl:NodeShape) + (closed true) + (PropertyShape (id _:b0) (path rdfs:label) (minCount 1) (maxCount 1))) + (NodeShape + (id ) + (type shacl:NodeShape) + (closed true) + (PropertyShape (id _:b1) (path rdfs:comment) (minCount 1) (maxCount 1))) + (NodeShape + (id ) + (type shacl:NodeShape) + (targetClass ) + (or + (NodeShape + (id ) + (type shacl:NodeShape) + (closed true) + (PropertyShape (id _:b0) (path rdfs:label) (minCount 1) (maxCount 1))) + (NodeShape + (id ) + (type shacl:NodeShape) + (closed true) + (PropertyShape (id _:b1) (path rdfs:comment) (minCount 1) (maxCount 1))) + )) ))}, + data: { + "node which is neither of given shapes": { + input: %( + @prefix ex: . + @prefix rdfs: . + + ex:Resource1 a ex:Resource ; + rdfs:label "A Resource with a label" ; + ex:extraProperty "This should not be here" .), + valid: false, + sxp: %{ + (ValidationReport #f + ( + (ValidationResult + (value ) + (focus ) + (shape ) + (resultSeverity shacl:Violation) + (component shacl:OrConstraintComponent) + (message "node does not conform to any shape")) )) + } + } + } } }.each do |name, params| context name do