rdf-n3 3.0.1 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +198 -76
- data/UNLICENSE +1 -1
- data/VERSION +1 -1
- data/lib/rdf/n3/algebra/builtin.rb +79 -0
- data/lib/rdf/n3/algebra/formula.rb +446 -0
- data/lib/rdf/n3/algebra/list/append.rb +42 -0
- data/lib/rdf/n3/algebra/list/first.rb +24 -0
- data/lib/rdf/n3/algebra/list/in.rb +48 -0
- data/lib/rdf/n3/algebra/list/iterate.rb +96 -0
- data/lib/rdf/n3/algebra/list/last.rb +24 -0
- data/lib/rdf/n3/algebra/list/length.rb +24 -0
- data/lib/rdf/n3/algebra/list/member.rb +44 -0
- data/lib/rdf/n3/algebra/list_operator.rb +96 -0
- data/lib/rdf/n3/algebra/log/conclusion.rb +65 -0
- data/lib/rdf/n3/algebra/log/conjunction.rb +36 -0
- data/lib/rdf/n3/algebra/log/content.rb +34 -0
- data/lib/rdf/n3/algebra/log/dtlit.rb +41 -0
- data/lib/rdf/n3/algebra/log/equal_to.rb +34 -0
- data/lib/rdf/n3/algebra/log/implies.rb +102 -0
- data/lib/rdf/n3/algebra/log/includes.rb +70 -0
- data/lib/rdf/n3/algebra/log/langlit.rb +41 -0
- data/lib/rdf/n3/algebra/log/n3_string.rb +34 -0
- data/lib/rdf/n3/algebra/log/not_equal_to.rb +23 -0
- data/lib/rdf/n3/algebra/log/not_includes.rb +27 -0
- data/lib/rdf/n3/algebra/log/output_string.rb +40 -0
- data/lib/rdf/n3/algebra/log/parsed_as_n3.rb +36 -0
- data/lib/rdf/n3/algebra/log/semantics.rb +40 -0
- data/lib/rdf/n3/algebra/math/absolute_value.rb +36 -0
- data/lib/rdf/n3/algebra/math/acos.rb +26 -0
- data/lib/rdf/n3/algebra/math/acosh.rb +26 -0
- data/lib/rdf/n3/algebra/math/asin.rb +26 -0
- data/lib/rdf/n3/algebra/math/asinh.rb +26 -0
- data/lib/rdf/n3/algebra/math/atan.rb +26 -0
- data/lib/rdf/n3/algebra/math/atanh.rb +26 -0
- data/lib/rdf/n3/algebra/math/ceiling.rb +28 -0
- data/lib/rdf/n3/algebra/math/cos.rb +40 -0
- data/lib/rdf/n3/algebra/math/cosh.rb +38 -0
- data/lib/rdf/n3/algebra/math/difference.rb +40 -0
- data/lib/rdf/n3/algebra/math/equal_to.rb +54 -0
- data/lib/rdf/n3/algebra/math/exponentiation.rb +35 -0
- data/lib/rdf/n3/algebra/math/floor.rb +28 -0
- data/lib/rdf/n3/algebra/math/greater_than.rb +41 -0
- data/lib/rdf/n3/algebra/math/less_than.rb +41 -0
- data/lib/rdf/n3/algebra/math/negation.rb +38 -0
- data/lib/rdf/n3/algebra/math/not_equal_to.rb +25 -0
- data/lib/rdf/n3/algebra/math/not_greater_than.rb +25 -0
- data/lib/rdf/n3/algebra/math/not_less_than.rb +25 -0
- data/lib/rdf/n3/algebra/math/product.rb +20 -0
- data/lib/rdf/n3/algebra/math/quotient.rb +36 -0
- data/lib/rdf/n3/algebra/math/remainder.rb +35 -0
- data/lib/rdf/n3/algebra/math/rounded.rb +26 -0
- data/lib/rdf/n3/algebra/math/sin.rb +40 -0
- data/lib/rdf/n3/algebra/math/sinh.rb +38 -0
- data/lib/rdf/n3/algebra/math/sum.rb +40 -0
- data/lib/rdf/n3/algebra/math/tan.rb +40 -0
- data/lib/rdf/n3/algebra/math/tanh.rb +38 -0
- data/lib/rdf/n3/algebra/not_implemented.rb +13 -0
- data/lib/rdf/n3/algebra/resource_operator.rb +122 -0
- data/lib/rdf/n3/algebra/str/concatenation.rb +27 -0
- data/lib/rdf/n3/algebra/str/contains.rb +33 -0
- data/lib/rdf/n3/algebra/str/contains_ignoring_case.rb +33 -0
- data/lib/rdf/n3/algebra/str/ends_with.rb +33 -0
- data/lib/rdf/n3/algebra/str/equal_ignoring_case.rb +34 -0
- data/lib/rdf/n3/algebra/str/format.rb +17 -0
- data/lib/rdf/n3/algebra/str/greater_than.rb +38 -0
- data/lib/rdf/n3/algebra/str/less_than.rb +33 -0
- data/lib/rdf/n3/algebra/str/matches.rb +37 -0
- data/lib/rdf/n3/algebra/str/not_equal_ignoring_case.rb +17 -0
- data/lib/rdf/n3/algebra/str/not_greater_than.rb +17 -0
- data/lib/rdf/n3/algebra/str/not_less_than.rb +17 -0
- data/lib/rdf/n3/algebra/str/not_matches.rb +18 -0
- data/lib/rdf/n3/algebra/str/replace.rb +35 -0
- data/lib/rdf/n3/algebra/str/scrape.rb +35 -0
- data/lib/rdf/n3/algebra/str/starts_with.rb +33 -0
- data/lib/rdf/n3/algebra/time/day.rb +35 -0
- data/lib/rdf/n3/algebra/time/day_of_week.rb +27 -0
- data/lib/rdf/n3/algebra/time/gm_time.rb +29 -0
- data/lib/rdf/n3/algebra/time/hour.rb +35 -0
- data/lib/rdf/n3/algebra/time/in_seconds.rb +59 -0
- data/lib/rdf/n3/algebra/time/local_time.rb +29 -0
- data/lib/rdf/n3/algebra/time/minute.rb +35 -0
- data/lib/rdf/n3/algebra/time/month.rb +35 -0
- data/lib/rdf/n3/algebra/time/second.rb +35 -0
- data/lib/rdf/n3/algebra/time/timezone.rb +36 -0
- data/lib/rdf/n3/algebra/time/year.rb +29 -0
- data/lib/rdf/n3/algebra.rb +210 -0
- data/lib/rdf/n3/extensions.rb +221 -0
- data/lib/rdf/n3/format.rb +66 -1
- data/lib/rdf/n3/list.rb +630 -0
- data/lib/rdf/n3/reader.rb +774 -497
- data/lib/rdf/n3/reasoner.rb +282 -0
- data/lib/rdf/n3/refinements.rb +178 -0
- data/lib/rdf/n3/repository.rb +332 -0
- data/lib/rdf/n3/terminals.rb +78 -0
- data/lib/rdf/n3/vocab.rb +36 -3
- data/lib/rdf/n3/writer.rb +461 -250
- data/lib/rdf/n3.rb +11 -8
- metadata +177 -49
- data/AUTHORS +0 -1
- data/History.markdown +0 -99
- data/lib/rdf/n3/patches/array_hacks.rb +0 -53
- data/lib/rdf/n3/reader/meta.rb +0 -641
- data/lib/rdf/n3/reader/parser.rb +0 -237
@@ -0,0 +1,282 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module RDF::N3
|
3
|
+
##
|
4
|
+
# A Notation-3/Turtle reasoner in Ruby
|
5
|
+
#
|
6
|
+
# Takes either a parsed formula or an `RDF::Queryable` and updates it by reasoning over formula defined within the queryable.
|
7
|
+
#
|
8
|
+
# @author [Gregg Kellogg](http://greggkellogg.net/)
|
9
|
+
class Reasoner
|
10
|
+
include RDF::Enumerable
|
11
|
+
include RDF::Mutable
|
12
|
+
include RDF::Util::Logger
|
13
|
+
|
14
|
+
# The top-level parsed formula, including builtins and variables.
|
15
|
+
# @return [RDF::N3::Algebra::Formula]
|
16
|
+
attr_reader :formula
|
17
|
+
|
18
|
+
# Opens a Notation-3 file, and parses it to initialize the reasoner
|
19
|
+
#
|
20
|
+
# @param [String, #to_s] file
|
21
|
+
# @yield [reasoner] `self`
|
22
|
+
# @yieldparam [RDF::N3::Reasoner] reasoner
|
23
|
+
# @yieldreturn [void] ignored
|
24
|
+
# @return [RDF::N3::Reasoner]
|
25
|
+
def self.open(file)
|
26
|
+
RDF::N3::Reader.open(file, **options) do |reader|
|
27
|
+
RDF::N3::Reasoner.new(reader, **options, &block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# Initializes a new reasoner. If input is an IO or string, it is taken as n3 source and parsed first. Otherwise, it is a parsed formula.
|
33
|
+
#
|
34
|
+
# It returns the evaluated formula, or yields triples.
|
35
|
+
#
|
36
|
+
# @example Initializing from a reader
|
37
|
+
# reader = RDF::N3::Reader.new(":a :b :c .")
|
38
|
+
# reasoner = RDF::N3::Reasoner.new(reader)
|
39
|
+
# reasoner.each_triple {}
|
40
|
+
#
|
41
|
+
# @example Initializing as a mutable
|
42
|
+
# reasoner = RDF::N3::Reasoner.new do |r|
|
43
|
+
# r << RDF::N3::Reader.new(":a :b :c .")
|
44
|
+
# end
|
45
|
+
# reasoner.each_triple {}
|
46
|
+
#
|
47
|
+
# @example Initializing with multiple inputs
|
48
|
+
# reasoner = RDF::N3::Reasoner.new
|
49
|
+
# RDF::NTriples::Reader.open("example.nt") {|r| reasoner << r}
|
50
|
+
# RDF::N3::Reader.open("rules.n3") {|r| reasoner << r}
|
51
|
+
# reasoner.each_triple {}
|
52
|
+
#
|
53
|
+
# @param [RDF::Mutable] input (nil)
|
54
|
+
# Input should be parsed N3 using native lists (see `:list_terms` option to {RDF::N3::Reader#initialize})
|
55
|
+
# @param [Hash{Symbol => Object}] options
|
56
|
+
# @option options [#to_s] :base_uri (nil)
|
57
|
+
# the base URI to use when resolving relative URIs (for acessing intermediate parser productions)
|
58
|
+
# @yield [reasoner] `self`
|
59
|
+
# @yieldparam [RDF::N3::Reasoner] reasoner
|
60
|
+
# @yieldreturn [void] ignored
|
61
|
+
# @return [RDF::N3::Reasoner]
|
62
|
+
def initialize(input, **options, &block)
|
63
|
+
@options = options.merge(strings: {}) # for --strings and log:outputString
|
64
|
+
@mutable = case input
|
65
|
+
when RDF::Mutable then input
|
66
|
+
when RDF::Enumerable then RDF::N3::Repository.new {|r| r << input}
|
67
|
+
else RDF::N3::Repository.new
|
68
|
+
end
|
69
|
+
|
70
|
+
@formula = input if input.is_a?(RDF::N3::Algebra::Formula)
|
71
|
+
|
72
|
+
log_debug("reasoner: expression") {SXP::Generator.string(formula.to_sxp_bin)}
|
73
|
+
|
74
|
+
if block_given?
|
75
|
+
case block.arity
|
76
|
+
when 0 then instance_eval(&block)
|
77
|
+
else block.call(self)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# Returns a copy of this reasoner
|
84
|
+
def dup
|
85
|
+
repo = RDF::N3::Repository.new {|r| r << @mutable}
|
86
|
+
self.class.new(repo) do |reasoner|
|
87
|
+
reasoner.instance_variable_set(:@options, @options.dup)
|
88
|
+
reasoner.instance_variable_set(:@formula, @formula.dup) if @formula
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
##
|
93
|
+
# Inserts an RDF statement the datastore, resets `formula`.
|
94
|
+
#
|
95
|
+
# @param [RDF::Statement] statement
|
96
|
+
# @return [void]
|
97
|
+
def insert_statement(statement)
|
98
|
+
@formula = nil
|
99
|
+
@mutable.insert_statement(statement)
|
100
|
+
end
|
101
|
+
|
102
|
+
##
|
103
|
+
# Updates the datastore by reasoning over the formula, optionally yielding each conclusion; uses triples from the graph associated with this formula as the dataset over which to reason.
|
104
|
+
#
|
105
|
+
# @param [Hash{Symbol => Object}] options
|
106
|
+
# @option options [Boolean] :apply
|
107
|
+
# @option options [Boolean] :rules
|
108
|
+
# @option options [Boolean] :think
|
109
|
+
# @yield [statement]
|
110
|
+
# @yieldparam [RDF::Statement] statement
|
111
|
+
# @return [RDF::N3::Reasoner] `self`
|
112
|
+
def execute(**options, &block)
|
113
|
+
@options[:logger] = options[:logger] if options.has_key?(:logger)
|
114
|
+
|
115
|
+
# The knowledge base is the non-variable portions of formula
|
116
|
+
knowledge_base = RDF::N3::Repository.new {|r| r << formula}
|
117
|
+
log_debug("reasoner: knowledge_base") {SXP::Generator.string(knowledge_base.statements.to_sxp_bin)}
|
118
|
+
|
119
|
+
# If thinking, continuously execute until results stop growing
|
120
|
+
count = -1
|
121
|
+
log_info("reasoner: start") { "count: #{count}"}
|
122
|
+
solutions = RDF::Query::Solutions(RDF::Query::Solution.new)
|
123
|
+
while knowledge_base.count > count
|
124
|
+
log_info("reasoner: do") { "count: #{count}"}
|
125
|
+
count = knowledge_base.count
|
126
|
+
log_depth {formula.execute(knowledge_base, solutions: solutions, **options)}
|
127
|
+
knowledge_base << formula
|
128
|
+
solutions = RDF::Query::Solutions(RDF::Query::Solution.new) if solutions.empty?
|
129
|
+
log_debug("reasoner: solutions") {SXP::Generator.string solutions.to_sxp_bin}
|
130
|
+
log_debug("reasoner: datastore") {SXP::Generator.string knowledge_base.statements.to_sxp_bin}
|
131
|
+
log_info("reasoner: inferred") {SXP::Generator.string knowledge_base.statements.select(&:inferred?).to_sxp_bin}
|
132
|
+
log_info("reasoner: formula") do
|
133
|
+
SXP::Generator.string RDF::N3::Algebra::Formula.from_enumerable(knowledge_base).to_sxp_bin
|
134
|
+
end
|
135
|
+
@formula = nil # cause formula to be re-calculated from knowledge-base
|
136
|
+
unless options[:think]
|
137
|
+
count = knowledge_base.count
|
138
|
+
break
|
139
|
+
end
|
140
|
+
end
|
141
|
+
log_info("reasoner: end") { "count: #{count}"}
|
142
|
+
|
143
|
+
# Add updates back to mutable, containg builtins and variables.
|
144
|
+
@mutable << knowledge_base
|
145
|
+
|
146
|
+
each(&block) if block_given?
|
147
|
+
self
|
148
|
+
end
|
149
|
+
alias_method :reason!, :execute
|
150
|
+
|
151
|
+
##
|
152
|
+
# Reason with results in a duplicate datastore
|
153
|
+
#
|
154
|
+
# @see execute
|
155
|
+
def reason(**options, &block)
|
156
|
+
self.dup.reason!(**options, &block)
|
157
|
+
end
|
158
|
+
|
159
|
+
##
|
160
|
+
# Yields each statement in the datastore
|
161
|
+
#
|
162
|
+
# @yieldparam [RDF::Statement] statement
|
163
|
+
# @yieldreturn [void] ignored
|
164
|
+
# @return [void]
|
165
|
+
def each(&block)
|
166
|
+
@mutable.each(&block)
|
167
|
+
end
|
168
|
+
|
169
|
+
##
|
170
|
+
# Yields data, excluding formulae or variables and statements referencing formulae or variables
|
171
|
+
#
|
172
|
+
# @overload data
|
173
|
+
# @yield [statement]
|
174
|
+
# each statement
|
175
|
+
# @yieldparam [RDF::Statement] statement
|
176
|
+
# @yieldreturn [void] ignored
|
177
|
+
# @return [void]
|
178
|
+
#
|
179
|
+
# @overload data
|
180
|
+
# @return [Enumerator<RDF::Statement>]
|
181
|
+
# @return [RDF::Enumerator]
|
182
|
+
# @yield [statement]
|
183
|
+
# @yieldparam [RDF::Statement] statement
|
184
|
+
def data(&block)
|
185
|
+
if block_given?
|
186
|
+
project_graph(nil) do |statement|
|
187
|
+
block.call(statement) unless statement.variable? ||
|
188
|
+
has_graph?(statement.subject) ||
|
189
|
+
has_graph?(statement.object)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
enum_data
|
193
|
+
end
|
194
|
+
alias_method :each_datum, :data
|
195
|
+
|
196
|
+
##
|
197
|
+
# Returns an enumerator for {#data}.
|
198
|
+
# FIXME: enum_for doesn't seem to be working properly
|
199
|
+
# in JRuby 1.7, so specs are marked pending
|
200
|
+
#
|
201
|
+
# @return [Enumerator<RDF::Statement>]
|
202
|
+
# @see #each_statement
|
203
|
+
def enum_data
|
204
|
+
# Ensure that statements are queryable, countable and enumerable
|
205
|
+
this = self
|
206
|
+
RDF::Queryable::Enumerator.new do |yielder|
|
207
|
+
this.send(:each_datum) {|y| yielder << y}
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
##
|
212
|
+
# Yields conclusions, excluding formulae and those statements in the original dataset, or returns an enumerator over the conclusions
|
213
|
+
#
|
214
|
+
# @overload conclusions
|
215
|
+
# @yield [statement]
|
216
|
+
# each statement
|
217
|
+
# @yieldparam [RDF::Statement] statement
|
218
|
+
# @yieldreturn [void] ignored
|
219
|
+
# @return [void]
|
220
|
+
#
|
221
|
+
# @overload conclusions
|
222
|
+
# @return [Enumerator<RDF::Statement>]
|
223
|
+
# @return [RDF::Enumerator]
|
224
|
+
# @yield [statement]
|
225
|
+
# @yieldparam [RDF::Statement] statement
|
226
|
+
def conclusions(&block)
|
227
|
+
if block_given?
|
228
|
+
# Invoke {#each} in the containing class:
|
229
|
+
each_statement {|s| block.call(s) if s.inferred?}
|
230
|
+
end
|
231
|
+
enum_conclusions
|
232
|
+
end
|
233
|
+
alias_method :each_conclusion, :conclusions
|
234
|
+
|
235
|
+
##
|
236
|
+
# Returns an enumerator for {#conclusions}.
|
237
|
+
# FIXME: enum_for doesn't seem to be working properly
|
238
|
+
# in JRuby 1.7, so specs are marked pending
|
239
|
+
#
|
240
|
+
# @return [Enumerator<RDF::Statement>]
|
241
|
+
# @see #each_statement
|
242
|
+
def enum_conclusions
|
243
|
+
# Ensure that statements are queryable, countable and enumerable
|
244
|
+
this = self
|
245
|
+
RDF::Queryable::Enumerator.new do |yielder|
|
246
|
+
this.send(:each_conclusion) {|y| yielder << y}
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
##
|
251
|
+
# Returns the concatenated strings from log:outputString
|
252
|
+
#
|
253
|
+
# @return [String]
|
254
|
+
def strings
|
255
|
+
@options[:strings].
|
256
|
+
sort_by {|k, v| k}.
|
257
|
+
map {|(k,v)| v.join("")}.
|
258
|
+
join("")
|
259
|
+
end
|
260
|
+
|
261
|
+
##
|
262
|
+
# Returns the top-level formula for this file.
|
263
|
+
#
|
264
|
+
# Transforms an RDF dataset into a recursive formula structure.
|
265
|
+
#
|
266
|
+
# @return [RDF::N3::Algebra::Formula]
|
267
|
+
def formula
|
268
|
+
@formula ||= RDF::N3::Algebra::Formula.from_enumerable(@mutable, **@options)
|
269
|
+
end
|
270
|
+
|
271
|
+
##
|
272
|
+
# Returns the SPARQL S-Expression (SSE) representation of the parsed formula.
|
273
|
+
# Formulae are represented as subjects and objects in the containing graph, along with their universals and existentials
|
274
|
+
#
|
275
|
+
# @return [Array] `self`
|
276
|
+
# @see http://openjena.org/wiki/SSE
|
277
|
+
def to_sxp_bin
|
278
|
+
formula.to_sxp_bin
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
@@ -0,0 +1,178 @@
|
|
1
|
+
# Refinements on core RDF class behavior for RDF::N3.
|
2
|
+
module RDF::N3::Refinements
|
3
|
+
# @!parse
|
4
|
+
# # Refinements on RDF::Term
|
5
|
+
# module RDF::Term
|
6
|
+
# ##
|
7
|
+
# # As a term is constant, this returns itself.
|
8
|
+
# #
|
9
|
+
# # @param [Hash{Symbol => RDF::Term}] bindings
|
10
|
+
# # a query solution containing zero or more variable bindings
|
11
|
+
# # @param [Hash{Symbol => Object}] options ({})
|
12
|
+
# # options passed from query
|
13
|
+
# # @return [RDF::Term]
|
14
|
+
# # @see SPARQL::Algebra::Expression.evaluate
|
15
|
+
# def evaluate(bindings, formulae: nil, **options); end
|
16
|
+
# end
|
17
|
+
refine ::RDF::Term do
|
18
|
+
def evaluate(bindings, formulae:, **options)
|
19
|
+
self
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# @!parse
|
24
|
+
# # Refinements on RDF::Node
|
25
|
+
# module RDF::Term
|
26
|
+
# ##
|
27
|
+
# # Blank node may refer to a formula.
|
28
|
+
# #
|
29
|
+
# # @param [Hash{Symbol => RDF::Term}] bindings
|
30
|
+
# # a query solution containing zero or more variable bindings
|
31
|
+
# # @param [Hash{Symbol => Object}] options ({})
|
32
|
+
# # options passed from query
|
33
|
+
# # @return [RDF::Node, RDF::N3::Algebra::Formula]
|
34
|
+
# # @see SPARQL::Algebra::Expression.evaluate
|
35
|
+
# def evaluate(bindings, formulae:, **options); end
|
36
|
+
# end
|
37
|
+
refine ::RDF::Node do
|
38
|
+
##
|
39
|
+
# @return [RDF::Node, RDF::N3::Algebra::Formula]
|
40
|
+
def evaluate(bindings, formulae:, **options)
|
41
|
+
node? ? formulae.fetch(self, self) : self
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# @!parse
|
46
|
+
# # Refinements on RDF::Statement
|
47
|
+
# class ::RDF::Statement
|
48
|
+
# # Refines `valid?` to allow literal subjects and BNode predicates.
|
49
|
+
# # @return [Boolean]
|
50
|
+
# def valid?; end
|
51
|
+
#
|
52
|
+
# # Refines `invalid?` to allow literal subjects and BNode predicates.
|
53
|
+
# # @return [Boolean]
|
54
|
+
# def invalid?; end
|
55
|
+
#
|
56
|
+
# # Refines `validate!` to allow literal subjects and BNode predicates.
|
57
|
+
# # @return [RDF::Value] `self`
|
58
|
+
# # @raise [ArgumentError] if the value is invalid
|
59
|
+
# def validate!; end
|
60
|
+
#
|
61
|
+
# ##
|
62
|
+
# # As a statement is constant, this returns itself.
|
63
|
+
# #
|
64
|
+
# # @param [Hash{Symbol => RDF::Term}] bindings
|
65
|
+
# # a query solution containing zero or more variable bindings
|
66
|
+
# # @param [Hash{Symbol => Object}] options ({})
|
67
|
+
# # options passed from query
|
68
|
+
# # @return [RDF::Statement]
|
69
|
+
# # @see SPARQL::Algebra::Expression.evaluate
|
70
|
+
# def evaluate(bindings, formulae:, **options); end
|
71
|
+
# end
|
72
|
+
refine ::RDF::Statement do
|
73
|
+
##
|
74
|
+
# Override `valid?` terms as subjects and resources as predicates.
|
75
|
+
#
|
76
|
+
# @return [Boolean]
|
77
|
+
def valid?
|
78
|
+
has_subject? && subject.term? && subject.valid? &&
|
79
|
+
has_predicate? && predicate.term? && predicate.valid? &&
|
80
|
+
has_object? && object.term? && object.valid? &&
|
81
|
+
(has_graph? ? (graph_name.resource? && graph_name.valid?) : true)
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
# @return [Boolean]
|
86
|
+
def invalid?
|
87
|
+
!valid?
|
88
|
+
end
|
89
|
+
|
90
|
+
##
|
91
|
+
# Default validate! implementation, overridden in concrete classes
|
92
|
+
# @return [RDF::Value] `self`
|
93
|
+
# @raise [ArgumentError] if the value is invalid
|
94
|
+
def validate!
|
95
|
+
raise ArgumentError, "#{self.inspect} is not valid" if invalid?
|
96
|
+
self
|
97
|
+
end
|
98
|
+
alias_method :validate, :validate!
|
99
|
+
|
100
|
+
##
|
101
|
+
# @return [RDF::Statement]
|
102
|
+
def evaluate(bindings, formulae:, **options)
|
103
|
+
self
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# @!parse
|
108
|
+
# # Refinements on RDF::Query::Pattern
|
109
|
+
# class ::RDF::Query::Pattern
|
110
|
+
# # Refines `#valid?` to allow literal subjects and BNode predicates.
|
111
|
+
# # @return [Boolean]
|
112
|
+
# def valid?; end
|
113
|
+
#
|
114
|
+
# ##
|
115
|
+
# # Evaluates the pattern using the given variable `bindings` by cloning the pattern replacing variables with their bindings recursively. If the resulting pattern is constant, it is cast as a statement.
|
116
|
+
# #
|
117
|
+
# # @param [Hash{Symbol => RDF::Term}] bindings
|
118
|
+
# # a query solution containing zero or more variable bindings
|
119
|
+
# # @param [Hash{Symbol => Object}] options ({})
|
120
|
+
# # options passed from query
|
121
|
+
# # @return [RDF::Statement, RDF::N3::Algebra::Formula]
|
122
|
+
# # @see SPARQL::Algebra::Expression.evaluate
|
123
|
+
# def evaluate(bindings, formulae:, **options); end
|
124
|
+
# end
|
125
|
+
refine ::RDF::Query::Pattern do
|
126
|
+
##
|
127
|
+
# Is this pattern composed only of valid components?
|
128
|
+
#
|
129
|
+
# @return [Boolean] `true` or `false`
|
130
|
+
def valid?
|
131
|
+
(has_subject? ? (subject.term? || subject.variable?) && subject.valid? : true) &&
|
132
|
+
(has_predicate? ? (predicate.term? || predicate.variable?) && predicate.valid? : true) &&
|
133
|
+
(has_object? ? (object.term? || object.variable?) && object.valid? : true) &&
|
134
|
+
(has_graph? ? (graph_name.resource? || graph_name.variable?) && graph_name.valid? : true)
|
135
|
+
rescue NoMethodError
|
136
|
+
false
|
137
|
+
end
|
138
|
+
|
139
|
+
# @return [RDF::Statement, RDF::N3::Algebra::Formula]
|
140
|
+
def evaluate(bindings, formulae:, **options)
|
141
|
+
elements = self.to_quad.map do |term|
|
142
|
+
term.evaluate(bindings, formulae: formulae, **options)
|
143
|
+
end.compact.map do |term|
|
144
|
+
term.node? ? formulae.fetch(term, term) : term
|
145
|
+
end
|
146
|
+
|
147
|
+
self.class.from(elements)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# @!parse
|
152
|
+
# # Refinements on RDF::Query::Variable
|
153
|
+
# class RDF::Query::Variable
|
154
|
+
# ##
|
155
|
+
# # If variable is bound, replace with the bound value, otherwise, returns itself
|
156
|
+
# #
|
157
|
+
# # @param [Hash{Symbol => RDF::Term}] bindings
|
158
|
+
# # a query solution containing zero or more variable bindings
|
159
|
+
# # @param [Hash{Symbol => Object}] options ({})
|
160
|
+
# # options passed from query
|
161
|
+
# # @return [RDF::Term]
|
162
|
+
# # @see SPARQL::Algebra::Expression.evaluate
|
163
|
+
# def evaluate(bindings, formulae:, **options); end
|
164
|
+
# end
|
165
|
+
refine ::RDF::Query::Variable do
|
166
|
+
##
|
167
|
+
# @return [RDF::Term]
|
168
|
+
def evaluate(bindings, formulae:, **options)
|
169
|
+
value = bindings.has_key?(name) ? bindings[name] : self
|
170
|
+
value.node? ? formulae.fetch(value, value) : value
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
refine ::RDF::Graph do
|
175
|
+
# Allow a graph to be treated as a term in a statement.
|
176
|
+
include ::RDF::Term
|
177
|
+
end
|
178
|
+
end
|