lib/shex/algebra/shape_ref.rb in shex-0.2.0 vs lib/shex/algebra/shape_ref.rb in shex-0.3.0

- old
+ new

@@ -8,38 +8,64 @@ structure_error("Shape reference must be an IRI or BNode: #{arg}", exception: ArgumentError) unless arg.is_a?(RDF::Resource) super end ## + # Creates an operator instance from a parsed ShExJ representation + # @param (see Operator#from_shexj) + # @return [Operator] + def self.from_shexj(operator, options = {}) + raise ArgumentError unless operator.is_a?(Hash) && operator['type'] == "ShapeRef" + raise ArgumentError, "missing reference in #{operator.inspect}" unless operator.has_key?('reference') + super + end + + ## # Satisfies referenced shape. # @param (see Satisfiable#satisfies?) # @return (see Satisfiable#satisfies?) # @raise (see Satisfiable#satisfies?) # @see [https://shexspec.github.io/spec/#shape-expression-semantics] - def satisfies?(focus) - status "ref #{operands.first.to_s}" - matched_shape = referenced_shape.satisfies?(focus) - satisfy satisfied: matched_shape + def satisfies?(focus, depth: 0) + status "ref #{operands.first.to_s}", depth: depth + schema.enter_shape(operands.first, focus) do |shape| + if shape + matched_shape = shape.satisfies?(focus, depth: depth + 1) + satisfy focus: focus, satisfied: matched_shape, depth: depth + else + status "Satisfy as #{operands.first} was re-entered for #{focus}", depth: depth + satisfy focus: focus, satisfied: referenced_shape, depth: depth + end + end rescue ShEx::NotSatisfied => e - not_satisfied e.message, unsatisfied: e.expression - raise + not_satisfied e.message, focus: focus, unsatisfied: e.expression, depth: depth end ## # Returns the referenced shape # # @return [Shape] def referenced_shape - schema.shapes[operands.first.to_s] + @referenced_shape ||= schema.shapes.detect {|s| s.label == operands.first} end ## - # A ShapeRef is valid if it's ancestor schema has any shape with a lable + # A ShapeRef is valid if it's ancestor schema has any shape with a label # the same as it's reference. + # A ref cannot reference itself (via whatever path) without going through a TripleConstraint. + # Even when going through TripleConstraints, there can't be a negative reference. def validate! structure_error("Missing referenced shape: #{operands.first}") if referenced_shape.nil? - # FIXME - #raise ShEx::ParseError, "Self referencing shape: #{operands.first}" if referenced_shape == first_ancestor(Shape) + raise ShEx::StructureError, "Self referencing shape: #{operands.first}" if referenced_shape == first_ancestor(Satisfiable) super + end + + ## + # Returns the binary S-Expression (SXP) representation of this operator. + # + # @return [Array] + # @see https://en.wikipedia.org/wiki/S-expression + def to_sxp_bin + ([:shapeRef, ([:label, @label] if @label)].compact + operands).to_sxp_bin end end end