Class: ShEx::Algebra::Shape

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

Constant Summary collapse

NAME =
:shape

Constants inherited from Operator

Operator::ARITY

Instance Attribute Summary collapse

Attributes inherited from Operator

#id, #logger, #operands, #options, #schema

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Operator

#base_uri, #closed?, #each_descendant, #eql?, #expression, #expressions, #focus, #focus=, #initialize, #inspect, #iri, iri, #json_type, #matched, #matched=, #message, #message=, #not_matched, #not_satisfied, #operand, #parent, #parent=, #satisfied, #satisfied=, #satisfy, #semact?, #semantic_actions, #serialize_value, #status, #structure_error, #to_h, #to_json, #to_sxp, #to_sxp_bin, #triple_expression?, #unmatched, #unmatched=, #unsatisfied, #unsatisfied=, value, #value

Constructor Details

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

Instance Attribute Details

#matchablesArray<RDF::Statement>

Let ‘matchables` be the triples in `outs` whose predicate appears in a TripleConstraint in `expression`. If `expression` is absent, `matchables = Ø` (the empty set).

Returns:

  • (Array<RDF::Statement>)


15
16
17
# File 'lib/shex/algebra/shape.rb', line 15

def matchables
  @matchables
end

#outsArray<RDF::Statement>

Let ‘outs` be the `arcsOut` in `remainder`: `outs = remainder ∩ arcsOut(G, n)`.

Returns:

  • (Array<RDF::Statement>)


10
11
12
# File 'lib/shex/algebra/shape.rb', line 10

def outs
  @outs
end

#unmatchablesArray<RDF::Statement>

Let ‘unmatchables` be the triples in `outs` which are not in `matchables`. `matchables ∪ unmatchables = outs.`

Returns:

  • (Array<RDF::Statement>)


20
21
22
# File 'lib/shex/algebra/shape.rb', line 20

def unmatchables
  @unmatchables
end

Class Method Details

.from_shexj(operator, options = {}) ⇒ Operator

Creates an operator instance from a parsed ShExJ representation

Returns:

Raises:

  • (ArgumentError)


26
27
28
29
# File 'lib/shex/algebra/shape.rb', line 26

def self.from_shexj(operator, options = {})
  raise ArgumentError unless operator.is_a?(Hash) && operator['type'] == "Shape"
  super
end

Instance Method Details

#satisfies?(focus, depth: 0) ⇒ Boolean, ShapeExpression

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:

  • focus (RDF::Resource)
  • depth (Integer) (defaults to: 0)

    for logging

  • options (Hash{Symbol => Object})

    Other, operand-specific options

Returns:

  • (Boolean)
  • (ShapeExpression)

    with ‘matched` and `satisfied` accessors for matched triples and sub-expressions

Raises:

  • (ShEx::NotMatched)

    with ‘expression` accessor to access `matched` and `unmatched` statements along with `satisfied` and `unsatisfied` operations.



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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/shex/algebra/shape.rb', line 35

def satisfies?(focus, depth: 0)
  # 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: focus).to_a.sort_by(&:to_sxp)
  arcs_out = schema.graph.query(subject: focus).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}", depth: depth)
  matched_expression = case expression
  when RDF::Resource
    ref.matches(arcs_in, arcs_out, depth: depth + 1)
  when TripleExpression
    expression.matches(arcs_in, arcs_out, depth: depth + 1)
  end
  matched = Array(matched_expression && matched_expression.matched)

  # `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 == focus}

  # 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)}

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

  # No matchable can be matched by any TripleConstraint in expression
  unmatched = matchables.select do |statement|
    expression.triple_constraints.any? do |expr|
      begin
        statement.predicate == expr.predicate && expr.matches([], [statement], depth: depth + 1)
      rescue ShEx::NotMatched
        false # Expected not to match
      end
    end if expression
  end
  unless unmatched.empty?
    not_satisfied "Statements remain matching TripleConstraints",
                  matched: matched,
                  unmatched: unmatched,
                  satisfied: expression,
                  depth: depth
  end

  # There is no triple in matchables whose predicate does not appear in extra.
  unmatched = matchables.reject {|st| extra.include?(st.predicate)}
  unless unmatched.empty?
    not_satisfied "Statements remains with predicate #{unmatched.map(&:predicate).compact.join(',')} not in extra",
                  matched: matched,
                  unmatched: unmatched,
                  satisfied: expression,
                  depth: depth
  end

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

  # Presumably, to be satisfied, there must be some triples in matches
  semantic_actions.each do |op|
    op.satisfies?(matched, matched: matched, depth: depth + 1)
  end unless matched.empty?

  # FIXME: also record matchables, outs and others?
  satisfy focus: focus, matched: matched, depth: depth
rescue ShEx::NotMatched => e
  not_satisfied e.message, focus: focus, unsatisfied: e.expression, depth: depth
end

#validate!Operator

expression must be a TripleExpression

Returns:

Raises:



113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/shex/algebra/shape.rb', line 113

def validate!
  case expression
  when nil, TripleExpression
  when RDF::Resource
    ref = schema.find(expression)
    ref.is_a?(TripleExpression) ||
    structure_error("#{json_type} must reference a TripleExpression: #{ref}")
  else
    structure_error("#{json_type} must reference a TripleExpression: #{ref}")
  end
  super
end