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