Class: ShEx::Algebra::Shape

Inherits:
Operator show all
Includes:
ShapeExpression
Defined in:
vendor/bundler/ruby/3.3.0/bundler/gems/shex-f64040a493d0/lib/shex/algebra/shape.rb

Constant Summary collapse

NAME =
:shape

Constants inherited from Operator

Operator::ARITY

Constants included from SPARQL::Algebra::Expression

SPARQL::Algebra::Expression::PATTERN_PARENTS

Constants included from RDF::Util::Logger

RDF::Util::Logger::IOWrapper

Instance Attribute Summary collapse

Attributes inherited from Operator

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

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ShapeExpression

#validate_expressions!, #validate_self_references!

Methods inherited from Operator

#base_uri, #closed?, #dup, #each_descendant, #eql?, #expression, #expressions, #find, #focus, #focus=, #initialize, #inspect, #iri, iri, #json_type, #matched, #matched=, #message, #message=, #not_matched, #not_satisfied, #operand, #parent, #parent=, #references, #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

Methods included from SPARQL::Algebra::Expression

cast, #constant?, #evaluate, extension, extension?, extensions, for, #invalid?, new, #node?, open, #optimize, #optimize!, parse, register_extension, #to_sxp_bin, #valid?, #variable?

Methods included from RDF::Util::Logger

#log_debug, #log_depth, #log_error, #log_fatal, #log_info, #log_recover, #log_recovering?, #log_statistics, #log_warn, #logger

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:



15
16
17
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/shex-f64040a493d0/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:



10
11
12
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/shex-f64040a493d0/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:



20
21
22
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/shex-f64040a493d0/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 'vendor/bundler/ruby/3.3.0/bundler/gems/shex-f64040a493d0/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:

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 'vendor/bundler/ruby/3.3.0/bundler/gems/shex-f64040a493d0/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 and must not reference itself recursively.

Returns:

Raises:



113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/shex-f64040a493d0/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 be a TripleExpression or reference: #{expression.to_sxp}")
  end
  # FIXME: this runs afoul of otherwise legitamate self-references, through a TripleExpression.
  #!validate_self_references!
  super
end