Class: ShEx::Algebra::Shape

Inherits:
Operator show all
Includes:
Satisfiable
Defined in:
lib/shex/algebra/shape.rb

Constant Summary collapse

NAME =
:shape

Constants inherited from Operator

Operator::ARITY

Instance Attribute Summary

Attributes inherited from Operator

#operands, #options, #schema

Instance Method Summary collapse

Methods included from Satisfiable

#not_satisfies?, #satisfiable?

Methods inherited from Operator

#closed?, #each_descendant, #eql?, #first_ancestor, #initialize, #inspect, #not_matched, #not_satisfied, #operand, #parent, #parent=, #satisfiable?, #semact?, #semantic_actions, #status, #structure_error, #to_sxp, #to_sxp_bin, #triple_expression?, #validate!

Constructor Details

This class inherits a constructor from ShEx::Algebra::Operator

Instance Method Details

#satisfies?(n) ⇒ Boolean

The ‘satisfies` semantics for a `Shape` depend on a matches function defined below. For a node `n`, shape `S`, graph `G`, and shapeMap `m`, `satisfies(n, S, G, m)`.

Parameters:

  • n (RDF::Resource)

Returns:

  • (Boolean)

    ‘true` if satisfied

Raises:



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/shex/algebra/shape.rb', line 12

def satisfies?(n)
  expression = operands.detect {|op| op.is_a?(TripleExpression)}

  # neigh(G, n) is the neighbourhood of the node n in the graph G.
  #
  #    neigh(G, n) = arcsOut(G, n) ∪ arcsIn(G, n)
  arcs_in = schema.graph.query(object: n).to_a.sort_by(&:to_sxp)
  arcs_out = schema.graph.query(subject: n).to_a.sort_by(&:to_sxp)
  neigh = (arcs_in + arcs_out).uniq

  # `matched` is the subset of statements which match `expression`.
  status("arcsIn: #{arcs_in.count}, arcsOut: #{arcs_out.count}")
  matched = expression ? expression.matches(neigh) : []

  # `remainder` is the set of unmatched statements
  remainder = neigh - matched

  # Let `outs` be the `arcsOut` in `remainder`: `outs = remainder ∩ arcsOut(G, n)`.
  outs = remainder.select {|s| s.subject == n}

  # Let `matchables` be the triples in `outs` whose predicate appears in a `TripleConstraint` in `expression`. If `expression` is absent, `matchables = Ø` (the empty set).
  predicates = expression ? expression.triple_constraints.map(&:predicate).uniq : []
  matchables = outs.select {|s| predicates.include?(s.predicate)}

  # No matchable can be matched by any TripleConstraint in expression
  matchables.each do |statement|
    expression.triple_constraints.each do |expr|
      begin
        status "check matchable #{statement.to_sxp} against #{expr.to_sxp}"
        if statement.predicate == expr.predicate && expr.matches([statement])
          not_satisfied "Unmatched statement: #{statement.to_sxp} matched #{expr.to_sxp}"
        end
      rescue NotMatched
        logger.recovering = false
        # Expected not to match
      end
    end
  end if expression

  # There is no triple in `matchables` which matches a `TripleConstraint` in `expression`.
  # FIXME: Really run against every TripleConstraint?

  # Let `unmatchables` be the triples in `outs` which are not in `matchables`.
  unmatchables = outs - matchables

  # There is no triple in matchables whose predicate does not appear in extra.
  matchables.each do |statement|
    not_satisfied "Statement remains with predicate #{statement.predicate} not in extra" unless extra.include?(statement.predicate)
  end

  # closed is false or unmatchables is empty.
  not_satisfied "Unmatchables remain on a closed shape" unless !closed? || unmatchables.empty?

  # Presumably, to be satisfied, there must be some triples in matches

  semantic_actions.all? do |op|
    # FIXME: what triples to run against satisfies?
    op.satisfies?(matched)
  end unless matched.empty?

  true
rescue NotMatched => e
  logger.recovering = false
  not_satisfied e.message
end

#triple_expressionsArray<TripleExpressions>

Included TripleExpressions

Returns:

  • (Array<TripleExpressions>)


81
82
83
# File 'lib/shex/algebra/shape.rb', line 81

def triple_expressions
  operands.select {|op| op.is_a?(TripleExpression)}
end