class SHACL::Algebra::PropertyShape

Constants

NAME

Public Instance Methods

builtin_lessThan(property, node, path, value_nodes, **options) click to toggle source

Specifies the condition that each value node is smaller than all the objects of the triples that have the focus node as subject and the value of sh:lessThan as predicate.

@example

ex:LessThanExampleShape
        a sh:NodeShape ;
        sh:property [
                sh:path ex:startDate ;
                sh:lessThan ex:endDate ;
        ] .

@param [RDF::URI] property the property of the focus node whose values must be equal to some value node. @param [RDF::Term] node the focus node @param [RDF::URI, SPARQL::Algebra::Expression] path (nil) the property path from the focus node to the value nodes. @param [Array<RDF::Term>] value_nodes @return [Array<SHACL::ValidationResult>]

# File lib/shacl/algebra/property_shape.rb, line 102
def builtin_lessThan(property, node, path, value_nodes, **options)
  terms = graph.query({subject: node, predicate: property}).objects
  compare(:<, terms, node, path, value_nodes,
          RDF::Vocab::SHACL.LessThanConstraintComponent, **options)
end
builtin_lessThanOrEquals(property, node, path, value_nodes, **options) click to toggle source

Specifies the condition that each value node is smaller than or equal to all the objects of the triples that have the focus node as subject and the value of sh:lessThanOrEquals as predicate.

@param [RDF::URI] property the property of the focus node whose values must be equal to some value node. @param [RDF::Term] node the focus node @param [RDF::URI, SPARQL::Algebra::Expression] path (nil) the property path from the focus node to the value nodes. @param [Array<RDF::Term>] value_nodes @return [Array<SHACL::ValidationResult>]

# File lib/shacl/algebra/property_shape.rb, line 115
def builtin_lessThanOrEquals(property, node, path, value_nodes, **options)
  terms = graph.query({subject: node, predicate: property}).objects
  compare(:<=, terms, node, path, value_nodes,
          RDF::Vocab::SHACL.LessThanOrEqualsConstraintComponent, **options)
end
builtin_maxCount(count, node, path, value_nodes, **options) click to toggle source

Specifies the maximum number of value nodes.

@param [Integer] count @param [RDF::Term] node the focus node @param [RDF::URI, SPARQL::Algebra::Expression] path (nil) the property path from the focus node to the value nodes. @param [Array<RDF::Term>] value_nodes @return [Array<SHACL::ValidationResult>]

# File lib/shacl/algebra/property_shape.rb, line 132
def builtin_maxCount(count, node, path, value_nodes, **options)
  satisfy(focus: node, path: path,
    message: "#{value_nodes.count} <= maxCount #{count}",
    resultSeverity: (options.fetch(:severity) unless value_nodes.count <= count.to_i),
    component: RDF::Vocab::SHACL.MaxCountConstraintComponent,
    **options)
end
builtin_minCount(count, node, path, value_nodes, **options) click to toggle source

Specifies the minimum number of value nodes.

@example

ex:MinCountExampleShape
        a sh:PropertyShape ;
        sh:targetNode ex:Alice, ex:Bob ;
        sh:path ex:name ;
        sh:minCount 1 .

@param [Integer] count @param [RDF::Term] node the focus node @param [RDF::URI, SPARQL::Algebra::Expression] path (nil) the property path from the focus node to the value nodes. @param [Array<RDF::Term>] value_nodes @return [Array<SHACL::ValidationResult>]

# File lib/shacl/algebra/property_shape.rb, line 154
def builtin_minCount(count, node, path, value_nodes, **options)
  satisfy(focus: node, path: path,
    message: "#{value_nodes.count} >= minCount #{count}",
    resultSeverity: (options.fetch(:severity) unless value_nodes.count >= count.to_i),
    component: RDF::Vocab::SHACL.MinCountConstraintComponent,
    **options)
end
builtin_uniqueLang(uniq, node, path, value_nodes, **options) click to toggle source

The property `sh:uniqueLang` can be set to `true` to specify that no pair of value nodes may use the same language tag.

@param [Boolean] uniq @param [RDF::Term] node the focus node @param [RDF::URI, SPARQL::Algebra::Expression] path (nil) the property path from the focus node to the value nodes. @param [Array<RDF::Term>] value_nodes @return [Array<SHACL::ValidationResult>]

# File lib/shacl/algebra/property_shape.rb, line 169
def builtin_uniqueLang(uniq, node, path, value_nodes, **options)
  if !value_nodes.all?(&:literal?)
    not_satisfied(focus: node, path: path,
      message: "not all values are literals",
      resultSeverity: options.fetch(:severity),
      component: RDF::Vocab::SHACL.UniqueLangConstraintComponent,
      **options)
  elsif value_nodes.map(&:language).compact.length != value_nodes.map(&:language).compact.uniq.length
    not_satisfied(focus: node, path: path,
      message: "not all values have unique language tags",
      resultSeverity: options.fetch(:severity),
      component: RDF::Vocab::SHACL.UniqueLangConstraintComponent,
      **options)
  else
    satisfy(focus: node, path: path,
      message: "all literals have unique language tags",
      component: RDF::Vocab::SHACL.UniqueLangConstraintComponent,
      **options)
  end
end
conforms(node, depth: 0, **options) click to toggle source

Validates the specified `property` within `graph`, a list of {ValidationResult}.

A property conforms the nodes found by evaluating it's `path` all conform.

@param [RDF::Term] node @param [Hash{Symbol => Object}] options @return [Array<SHACL::ValidationResult>]

Returns a validation result for each value node.
# File lib/shacl/algebra/property_shape.rb, line 16
def conforms(node, depth: 0, **options)
  return [] if deactivated?
  options = id ? options.merge(shape: id) : options
  options = options.merge(severity: RDF::Vocab::SHACL.Violation)

  # Add some instance options to the argument
  options = %i{
    flags
    qualifiedMinCount
    qualifiedMaxCount
    qualifiedValueShapesDisjoint
    severity
  }.inject(options) do |memo, sym|
    @options[sym] ? memo.merge(sym => @options[sym]) : memo
  end

  path = @options[:path]
  log_debug(NAME, depth: depth) {SXP::Generator.string({id: id, node: node, path: path}.to_sxp_bin)}
  log_error(NAME, "no path", depth: depth) unless path

  # Turn the `path` attribute into a SPARQL Property Path and evaluate to find related nodes.
  value_nodes = if path.is_a?(RDF::URI)
    graph.query({subject: node, predicate: path}).objects
  elsif path.evaluatable?
    path.execute(graph,
      subject: node,
      object: RDF::Query::Variable.new(:object)).map do
        |soln| soln[:object]
    end.compact.uniq
  else
    log_error(NAME, "Can't handle path", depth: depth) {path.to_sxp}
    []
  end

  # Evaluate against builtins
  builtin_results = @options.map do |k, v|
    self.send("builtin_#{k}".to_sym, v, node, path, value_nodes, depth: depth + 1, **options) if self.respond_to?("builtin_#{k}".to_sym)
  end.flatten.compact

  # Evaluate against operands
  op_results = operands.map do |op|
    if op.is_a?(QualifiedValueShape)
      # All value nodes are passed
      op.conforms(node, value_nodes: value_nodes, path: path, depth: depth + 1, **options)
    else
      value_nodes.map do |n|
       res = op.conforms(n, path: path, depth: depth + 1, **options)
       if op.is_a?(NodeShape) && !res.all?(&:conform?)
         # Special case for embedded NodeShape
         not_satisfied(focus: node, path: path,
           value: n,
           message: "node does not conform to #{op.id}",
           resultSeverity: options.fetch(:severity),
           component: RDF::Vocab::SHACL.NodeConstraintComponent,
           **options)
       else
         res
       end
     end
    end
  end.flatten.compact

  builtin_results + op_results
end
path() click to toggle source

The path defined on this property shape @return [RDF::URI, ]

# File lib/shacl/algebra/property_shape.rb, line 83
def path
  @options[:path]
end