Class: ShEx::Algebra::Schema
- Defined in:
- lib/shex/algebra/schema.rb
Constant Summary collapse
- NAME =
:schema
Constants inherited from Operator
Instance Attribute Summary collapse
-
#extensions ⇒ Hash{String => ShEx::Extension}
readonly
Map of Semantic Action instances.
-
#graph ⇒ RDF::Queryable
Graph to validate.
-
#map ⇒ Hash{RDF::Resource => RDF::Resource}
readonly
Map of nodes to shapes.
Attributes inherited from Operator
#id, #logger, #operands, #options, #schema
Class Method Summary collapse
-
.from_shexj(operator, **options) ⇒ Operator
Creates an operator instance from a parsed ShExJ representation.
Instance Method Summary collapse
-
#enter_shape(id, node) {|shape,| ... } ⇒ ShapeExpression
Indicate that a shape has been entered with a specific focus node.
-
#execute(graph, map, focus: [], shapeExterns: [], depth: 0, **options) ⇒ Hash{RDF::Term => Array<ShapeResult>}
Match on schema.
-
#external_schemas ⇒ Array<Schema>
Externally loaded schemas, lazily evaluated.
-
#initialize(*operands, **options) ⇒ Object
constructor
Initializes a new operator instance.
-
#satisfies?(graph, map, **options) ⇒ Boolean
Match on schema.
-
#shapes ⇒ Array<Operator>
Shapes as a hash.
-
#start ⇒ Object
Start action, if any.
-
#validate! ⇒ Operator
Validate shapes, in addition to other operands.
Methods inherited from Operator
#base_uri, #closed?, #dup, #each_descendant, #eql?, #expression, #expressions, #find, #focus, #focus=, #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
Constructor Details
#initialize(*operands) ⇒ Object #initialize(*operands, **options) ⇒ Object
Initializes a new operator instance.
28 29 30 31 32 33 34 35 |
# File 'lib/shex/algebra/schema.rb', line 28 def initialize(*operands, **) super schema = self each_descendant do |op| # Set schema everywhere op.schema = self end end |
Instance Attribute Details
#extensions ⇒ Hash{String => ShEx::Extension} (readonly)
Map of Semantic Action instances
16 17 18 |
# File 'lib/shex/algebra/schema.rb', line 16 def extensions @extensions end |
#graph ⇒ RDF::Queryable
Graph to validate
8 9 10 |
# File 'lib/shex/algebra/schema.rb', line 8 def graph @graph end |
#map ⇒ Hash{RDF::Resource => RDF::Resource} (readonly)
Map of nodes to shapes
12 13 14 |
# File 'lib/shex/algebra/schema.rb', line 12 def map @map end |
Class Method Details
.from_shexj(operator, **options) ⇒ Operator
Creates an operator instance from a parsed ShExJ representation
22 23 24 25 |
# File 'lib/shex/algebra/schema.rb', line 22 def self.from_shexj(operator, **) raise ArgumentError unless operator.is_a?(Hash) && operator['type'] == "Schema" super end |
Instance Method Details
#enter_shape(id, node) {|shape,| ... } ⇒ ShapeExpression
Indicate that a shape has been entered with a specific focus node. Any future attempt to enter the same shape with the same node raises an exception.
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/shex/algebra/schema.rb', line 177 def enter_shape(id, node, &block) shape = shapes.detect {|s| s.id == id} structure_error("No shape found for #{id}") unless shape @shapes_entered[id] ||= {} if @shapes_entered[id][node] block.call(false) else @shapes_entered[id][node] = self begin block.call(shape) ensure @shapes_entered[id].delete(node) end end end |
#execute(graph, map, focus: [], shapeExterns: [], depth: 0, **options) ⇒ Hash{RDF::Term => Array<ShapeResult>}
Match on schema. Finds appropriate shape for node, and matches that shape.
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 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/shex/algebra/schema.rb', line 51 def execute(graph, map, focus: [], shapeExterns: [], depth: 0, **) @graph, @shapes_entered, results = graph, {}, {} @external_schemas = shapeExterns @extensions = {} focus = Array(focus).map {|f| value(f, **)} logger = [:logger] || @options[:logger] each_descendant do |op| # Set logging everywhere op.logger = logger end # Initialize Extensions each_descendant do |op| next unless op.is_a?(SemAct) name = op.operands.first.to_s if ext_class = ShEx::Extension.find(name) @extensions[name] ||= ext_class.new(schema: self, depth: depth, **) end end # If `n` is a Blank Node, we won't find it through normal matching, find an equivalent node in the graph having the same id @map = case map when Hash map.inject({}) do |memo, (node, shapes)| gnode = graph.enum_term.detect {|t| t.node? && t.id == node.id} if node.is_a?(RDF::Node) node = gnode if gnode memo.merge(node => Array(shapes)) end when Array map.inject({}) do |memo, (node, shape)| gnode = graph.enum_term.detect {|t| t.node? && t.id == node.id} if node.is_a?(RDF::Node) node = gnode if gnode (memo[node] ||= []).concat(Array(shape)) memo end when nil then {} else structure_error "Unrecognized shape map: #{map.inspect}" end # First, evaluate semantic acts semantic_actions.all? do |op| op.satisfies?([], depth: depth + 1) end # Next run any start expression if !focus.empty? if start focus.each do |node| node = graph.enum_term.detect {|t| t.node? && t.id == node.id} if node.is_a?(RDF::Node) sr = ShapeResult.new(RDF::URI("http://www.w3.org/ns/shex#Start")) (results[node] ||= []) << sr begin sr.expression = start.satisfies?(node, depth: depth + 1) sr.result = true rescue ShEx::NotSatisfied => e sr.expression = e.expression sr.result = false end end else structure_error "Focus nodes with no start" end end # Match against all shapes associated with the ids for focus @map.each do |node, shapes| results[node] ||= [] shapes.each do |id| enter_shape(id, node) do |shape| sr = ShapeResult.new(id) results[node] << sr begin sr.expression = shape.satisfies?(node, depth: depth + 1) sr.result = true rescue ShEx::NotSatisfied => e sr.expression = e.expression sr.result = false end end end end if results.values.flatten.all? {|sr| sr.result} status "schema satisfied", depth: depth results else raise ShEx::NotSatisfied.new("Graph does not conform to schema", expression: results) end ensure # Close Semantic Action extensions @extensions.values.each {|ext| ext.close(schema: self, depth: depth, **)} end |
#external_schemas ⇒ Array<Schema>
Externally loaded schemas, lazily evaluated
196 197 198 199 200 201 202 203 204 205 206 207 |
# File 'lib/shex/algebra/schema.rb', line 196 def external_schemas @external_schemas = Array(@external_schemas).map do |extern| schema = case extern when Schema then extern else status "Load extern #{extern}" ShEx.open(extern, logger: [:logger]) end schema.graph = graph schema end end |
#satisfies?(graph, map, **options) ⇒ Boolean
Match on schema. Finds appropriate shape for node, and matches that shape.
153 154 155 156 157 |
# File 'lib/shex/algebra/schema.rb', line 153 def satisfies?(graph, map, **) execute(graph, map, **) rescue ShEx::NotSatisfied false end |
#shapes ⇒ Array<Operator>
Shapes as a hash
162 163 164 165 166 167 |
# File 'lib/shex/algebra/schema.rb', line 162 def shapes @shapes ||= begin shapes = Array(operands.detect {|op| op.is_a?(Array) && op.first == :shapes}) Array(shapes[1..-1]) end end |
#start ⇒ Object
Start action, if any
211 212 213 |
# File 'lib/shex/algebra/schema.rb', line 211 def start @start ||= operands.detect {|op| op.is_a?(Start)} end |
#validate! ⇒ Operator
Validate shapes, in addition to other operands
219 220 221 222 223 224 225 226 227 228 |
# File 'lib/shex/algebra/schema.rb', line 219 def validate! shapes.each do |op| op.validate! if op.respond_to?(:validate!) if op.is_a?(RDF::Resource) ref = find(op) structure_error("Missing reference: #{op}") if ref.nil? end end super end |