rdf-virtuoso 0.0.11

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.
@@ -0,0 +1,19 @@
1
+ require 'active_rdf/association_reflection'
2
+
3
+ module ActiveRDF
4
+ module Reflections
5
+ # Returns a hash containing all AssociationReflection objects for the current class
6
+ # Example:
7
+ #
8
+ # Invoice.reflections
9
+ # Account.reflections
10
+ #
11
+ def reflections
12
+ read_inheritable_attribute(:reflections) || write_inheritable_attribute(:reflections, {})
13
+ end
14
+
15
+ def reflect_on_association(association)
16
+ reflections[association].is_a?(AssociationReflection) ? reflections[association] : nil
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,10 @@
1
+ module ActiveRDF
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 10
6
+ PRE = nil
7
+
8
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
9
+ end
10
+ end
@@ -0,0 +1,8 @@
1
+ module RDF
2
+ module Virtuoso
3
+ autoload :Repository, 'rdf/virtuoso/repository'
4
+ autoload :Query, 'rdf/virtuoso/query'
5
+ autoload :Prefixes, 'rdf/virtuoso/prefixes'
6
+ autoload :Parser, 'rdf/virtuoso/parser'
7
+ end
8
+ end
@@ -0,0 +1,42 @@
1
+ module RDF
2
+ module Virtuoso
3
+ module Parser
4
+ class JSON
5
+
6
+ def self.call(response)
7
+ parse_json_bindings(response)
8
+ end
9
+
10
+ def self.parse_json_bindings(response)
11
+ case
12
+ when response['boolean']
13
+ response['boolean']
14
+ when response['results']
15
+ solutions = response['results']['bindings'].map do |row|
16
+ row = row.inject({}) do |cols, (name, value)|
17
+ cols.merge(name.to_sym => parse_json_value(value))
18
+ end
19
+ RDF::Query::Solution.new(row)
20
+ end
21
+ RDF::Query::Solutions.new(solutions)
22
+ end
23
+ end
24
+
25
+ def self.parse_json_value(value, nodes = {})
26
+ case value['type'].to_sym
27
+ when :bnode
28
+ nodes[id = value['value']] ||= RDF::Node.new(id)
29
+ when :uri
30
+ RDF::URI.new(value['value'])
31
+ when :literal
32
+ RDF::Literal.new(value['value'], :language => value['xml:lang'])
33
+ when :'typed-literal'
34
+ RDF::Literal.new(value['value'], :datatype => value['datatype'])
35
+ else nil
36
+ end
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,54 @@
1
+ module RDF::Virtuoso
2
+ require 'uri'
3
+
4
+ class UnProcessable; end
5
+ class Prefixes
6
+
7
+ PREFIXES = {
8
+ dc: 'http://purl.org/dc/terms/',
9
+ bibo: 'http://purl.org/ontology/bibo/',
10
+ fabio: 'http://purl.org/spar/fabio/',
11
+ rev: 'http://purl.org/stuff/rev#',
12
+ foaf: 'http://xmlns.com/foaf/0.1/',
13
+ lang: 'http://lexvo.org/id/iso639-3/'
14
+ }
15
+
16
+ class << self
17
+ def parse(uri_or_array)
18
+ prefixes = case uri_or_array
19
+ when String then [uri_or_array]
20
+ when Array then uri_or_array
21
+ else return UnProcessable.new
22
+ end
23
+ result = Set.new
24
+ prefixes.each do |prefix|
25
+ uri = URI(prefix)
26
+ str = ""
27
+ str << uri.host.split('.')[-2]
28
+ /^(?<iri>.*[\/|#]).+$/ =~ uri.to_s
29
+ str << ": <%s>" % iri
30
+ result << str
31
+ end
32
+ result.to_a
33
+ end
34
+ end
35
+
36
+ def initialize(prefixes={})
37
+ @prefixes = prefixes
38
+ end
39
+
40
+ def to_a
41
+ ary = []
42
+ @prefixes.each_pair do |key, value|
43
+ ary << "#{key}: <#{value}>"
44
+ end
45
+ ary
46
+ end
47
+
48
+ def to_s
49
+ @prefixes.inspect
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,632 @@
1
+ module RDF::Virtuoso
2
+
3
+ ##
4
+ # A SPARQL query builder.
5
+ #
6
+ # @example Iterating over all found solutions
7
+ # query.each_solution { |solution| puts solution.inspect }
8
+ #
9
+ class Query < RDF::Query
10
+ ##
11
+ # @return [Symbol]
12
+ # @see http://www.w3.org/TR/rdf-sparql-query/#QueryForms
13
+ attr_reader :form
14
+
15
+ ##
16
+ # @return [Hash{Symbol => Object}]
17
+ attr_reader :options
18
+
19
+ ##
20
+ # @return [Array<[key, RDF::Value]>]
21
+ attr_reader :values
22
+
23
+
24
+ attr_reader :data_values
25
+
26
+ ##
27
+ # Creates a boolean `ASK` query.
28
+ #
29
+ # @param [Hash{Symbol => Object}] options
30
+ # @return [Query]
31
+ # @see http://www.w3.org/TR/rdf-sparql-query/#ask
32
+ def self.ask(options = {})
33
+ self.new(:ask, options)
34
+ end
35
+
36
+ ##
37
+ # Creates a tuple `SELECT` query.
38
+ #
39
+ # @param [Array<Symbol>] variables
40
+ # @param [Hash{Symbol => Object}] options
41
+ # @return [Query]
42
+ # @see http://www.w3.org/TR/rdf-sparql-query/#select
43
+ def self.select(*variables)
44
+ options = variables.last.is_a?(Hash) ? variables.pop : {}
45
+ self.new(:select, options).select(*variables)
46
+ end
47
+
48
+ ##
49
+ # Creates a `DESCRIBE` query.
50
+ #
51
+ # @param [Array<Symbol, RDF::URI>] variables
52
+ # @param [Hash{Symbol => Object}] options
53
+ # @return [Query]
54
+ # @see http://www.w3.org/TR/rdf-sparql-query/#describe
55
+ def self.describe(*variables)
56
+ options = variables.last.is_a?(Hash) ? variables.pop : {}
57
+ self.new(:describe, options).describe(*variables)
58
+ end
59
+
60
+ ##
61
+ # Creates a graph `CONSTRUCT` query.
62
+ #
63
+ # @param [Array<RDF::Query::Pattern, Array>] patterns
64
+ # @param [Hash{Symbol => Object}] options
65
+ # @return [Query]
66
+ # @see http://www.w3.org/TR/rdf-sparql-query/#construct
67
+ def self.construct(*patterns)
68
+ options = patterns.last.is_a?(Hash) ? patterns.pop : {}
69
+ self.new(:construct, options).construct(*patterns) # FIXME
70
+ end
71
+
72
+ ##
73
+ # Creates an `UPDATE` query.
74
+ #
75
+ # @param [Array<RDF::Query::Pattern, Array>] patterns
76
+ # @param [Hash{Symbol => Object}] options
77
+ # @return [Query]
78
+ # @see http://www.w3.org/Submission/SPARQL-Update/
79
+ def self.insert_data(*patterns)
80
+ # options = variables.last.is_a?(Hash) ? variables.pop : {}
81
+ options = patterns.last.is_a?(Hash) ? patterns.pop : {}
82
+ self.new(:insert_data, options).insert_data(*patterns)
83
+ end
84
+
85
+ def self.insert(*patterns)
86
+ # options = variables.last.is_a?(Hash) ? variables.pop : {}
87
+ options = patterns.last.is_a?(Hash) ? patterns.pop : {}
88
+ self.new(:insert, options).insert(*patterns)
89
+ end
90
+
91
+ def self.delete_data(*patterns)
92
+ options = patterns.last.is_a?(Hash) ? patterns.pop : {}
93
+ self.new(:delete_data, options).delete_data(*patterns)
94
+ end
95
+
96
+ def self.delete(*patterns)
97
+ options = patterns.last.is_a?(Hash) ? patterns.pop : {}
98
+ self.new(:delete, options).delete(*patterns)
99
+ end
100
+
101
+ def self.create(*variables)
102
+ options = variables.last.is_a?(Hash) ? variables.pop : {}
103
+ self.new(:create, options).create(variables.first)
104
+ end
105
+
106
+ def self.drop(*variables)
107
+ options = variables.last.is_a?(Hash) ? variables.pop : {}
108
+ self.new(:drop, options).drop(variables.first)
109
+ end
110
+
111
+ def self.clear(*variables)
112
+ options = variables.last.is_a?(Hash) ? variables.pop : {}
113
+ self.new(:clear, options).clear(variables.first)
114
+ end
115
+
116
+ ##
117
+ # @param [Symbol, #to_s] form
118
+ # @param [Hash{Symbol => Object}] options
119
+ # @yield [query]
120
+ # @yieldparam [Query]
121
+ def initialize(form = :ask, options = {}, &block)
122
+ @form = form.respond_to?(:to_sym) ? form.to_sym : form.to_s.to_sym
123
+ super([], options, &block)
124
+ end
125
+
126
+ ##
127
+ # @return [Query]
128
+ # @see http://www.w3.org/TR/rdf-sparql-query/#ask
129
+ def ask
130
+ @form = :ask
131
+ self
132
+ end
133
+
134
+ ##
135
+ # @param [Array<Symbol>] variables
136
+ # @return [Query]
137
+ # @see http://www.w3.org/TR/rdf-sparql-query/#select
138
+ def select(*variables)
139
+ @values = variables.map { |var| [var, RDF::Query::Variable.new(var)] }
140
+ self
141
+ end
142
+
143
+ ##
144
+ # @param [Array<Symbol>] variables
145
+ # @return [Query]
146
+ # @see http://www.w3.org/TR/rdf-sparql-query/#describe
147
+ def describe(*variables)
148
+ @values = variables.map { |var|
149
+ [var, var.is_a?(RDF::URI) ? var : RDF::Query::Variable.new(var)]
150
+ }
151
+ self
152
+ end
153
+
154
+ ##
155
+ # @param [Array<RDF::Query::Pattern, Array>] patterns
156
+ # @return [Query]
157
+ # @see http://www.w3.org/TR/rdf-sparql-query/#construct
158
+ def construct(*patterns)
159
+ new_patterns = []
160
+ patterns.each do |pattern|
161
+ new_patterns << pattern.map do |value|
162
+ if value.is_a?(Symbol)
163
+ value = RDF::Query::Variable.new(value)
164
+ elsif value.is_a?(RDF::URI)
165
+ value = value
166
+ else
167
+ value = RDF::Literal.new(value)
168
+ end
169
+ end
170
+ end
171
+ @data_values = build_patterns(new_patterns)
172
+ self
173
+ end
174
+
175
+
176
+ ##
177
+ # @param [Array<RDF::Query::Pattern, Array>] patterns
178
+ # @return [Query]
179
+ # @see http://www.w3.org/Submission/SPARQL-Update/
180
+ def insert_data(*patterns)
181
+ new_patterns = []
182
+ patterns.each do |values|
183
+ new_patterns << values.map { |var| [var, var.is_a?(RDF::URI) ? var : var] }
184
+ end
185
+ @data_values = new_patterns #build_patterns(new_patterns)
186
+ self
187
+ end
188
+
189
+ def insert(*patterns)
190
+ new_patterns = []
191
+ patterns.each do |pattern|
192
+ new_patterns << pattern.map do |value|
193
+ if value.is_a?(Symbol)
194
+ value = RDF::Query::Variable.new(value)
195
+ elsif value.is_a?(RDF::URI)
196
+ value = value
197
+ else
198
+ value = RDF::Literal.new(value)
199
+ end
200
+ end
201
+ end
202
+ @data_values = build_patterns(new_patterns)
203
+ self
204
+ end
205
+
206
+ def delete_data(*patterns)
207
+ new_patterns = []
208
+ patterns.each do |values|
209
+ new_patterns << values.map { |var| [var, var.is_a?(RDF::URI) ? var : var] }
210
+ end
211
+ @data_values = new_patterns #build_patterns(new_patterns)
212
+ self
213
+ end
214
+
215
+ def delete(*patterns)
216
+ new_patterns = []
217
+ patterns.each do |pattern|
218
+ new_patterns << pattern.map do |value|
219
+ if value.is_a?(Symbol)
220
+ value = RDF::Query::Variable.new(value)
221
+ elsif value.is_a?(RDF::URI)
222
+ value = value
223
+ else
224
+ value = RDF::Literal.new(value)
225
+ end
226
+ end
227
+ end
228
+ @data_values = build_patterns(new_patterns)
229
+ self
230
+ end
231
+
232
+ # def delete(*variables)
233
+ # @values = variables.map { |var|
234
+ # [var, var.is_a?(RDF::URI) ? var : RDF::Query::Variable.new(var)]
235
+ # }
236
+ # self
237
+ # end
238
+
239
+ def create(uri)
240
+ options[:graph] = uri
241
+ self
242
+ end
243
+
244
+ def drop(uri)
245
+ options[:graph] = uri
246
+ self
247
+ end
248
+
249
+ def clear(uri)
250
+ options[:graph] = uri
251
+ self
252
+ end
253
+
254
+ # @param RDF::URI uri
255
+ # @return [Query]
256
+ # @see http://www.w3.org/TR/rdf-sparql-query/#specDataset
257
+ def from(uri)
258
+ options[:from] = uri
259
+ self
260
+ end
261
+
262
+ # @param RDF::URI uri
263
+ # @return [Query]
264
+ def graph(uri)
265
+ options[:graph] = uri
266
+ self
267
+ end
268
+
269
+ ##
270
+ # @param [Array<RDF::Query::Pattern, Array>] patterns
271
+ # @return [Query]
272
+ # @see http://www.w3.org/TR/rdf-sparql-query/#GraphPattern
273
+ def where(*patterns)
274
+ @patterns += build_patterns(patterns)
275
+ self
276
+ end
277
+
278
+ alias_method :whether, :where
279
+
280
+ ##
281
+ # @param [Array<Symbol, String>] variables
282
+ # @return [Query]
283
+ # @see http://www.w3.org/TR/rdf-sparql-query/#modOrderBy
284
+ def order(*variables)
285
+ options[:order_by] = variables
286
+ self
287
+ end
288
+
289
+ alias_method :order_by, :order
290
+
291
+ ##
292
+ # @return [Query]
293
+ # @see http://www.w3.org/TR/rdf-sparql-query/#modDistinct
294
+ def distinct(state = true)
295
+ options[:distinct] = state
296
+ self
297
+ end
298
+
299
+ ##
300
+ # @return [Query]
301
+ # @see http://www.w3.org/TR/rdf-sparql-query/#modReduced
302
+ def reduced(state = true)
303
+ options[:reduced] = state
304
+ self
305
+ end
306
+
307
+ ## SPARQL 1.1 Aggregates
308
+ # @return [Query]
309
+ # @see http://www.w3.org/TR/sparql11-query/#defn_aggCount
310
+ # def count(*variables)
311
+ # options[:count] = variables
312
+ # self
313
+ # end
314
+ AGG_METHODS = %w(count min max sum avg sample group_concat group_digest)
315
+
316
+ AGG_METHODS.each do |m|
317
+ define_method m do |*variables|
318
+ options[m.to_sym] = variables
319
+ self
320
+ end
321
+ end
322
+
323
+ ##
324
+ # @param [Integer, #to_i] start
325
+ # @return [Query]
326
+ # @see http://www.w3.org/TR/rdf-sparql-query/#modOffset
327
+ def offset(start)
328
+ slice(start, nil)
329
+ end
330
+
331
+ ##
332
+ # @param [Integer, #to_i] length
333
+ # @return [Query]
334
+ # @see http://www.w3.org/TR/rdf-sparql-query/#modResultLimit
335
+ def limit(length)
336
+ slice(nil, length)
337
+ end
338
+
339
+ ##
340
+ # @param [Integer, #to_i] start
341
+ # @param [Integer, #to_i] length
342
+ # @return [Query]
343
+ def slice(start, length)
344
+ options[:offset] = start.to_i if start
345
+ options[:limit] = length.to_i if length
346
+ self
347
+ end
348
+
349
+ ##
350
+ # @return [Query]
351
+ # @see http://www.w3.org/TR/rdf-sparql-query/#prefNames
352
+ def prefix(string)
353
+ (options[:prefixes] ||= []) << string
354
+ self
355
+ end
356
+
357
+ ##
358
+ # @return [Query]
359
+ # @see http://www.w3.org/TR/rdf-sparql-query/#prefNames
360
+ def prefixes(prefixes = nil)
361
+ options[:prefixes] ||= []
362
+ options[:prefixes] += prefixes.to_a
363
+ self
364
+ end
365
+
366
+ ##
367
+ # @return [Query]
368
+ # @see http://www.w3.org/TR/rdf-sparql-query/#optionals
369
+ def optional(*patterns)
370
+ (options[:optionals] ||= []) << build_patterns(patterns)
371
+ self
372
+ end
373
+
374
+ ##
375
+ # @return [Query]
376
+ # @see http://www.w3.org/TR/rdf-sparql-query/#minus
377
+ def minus(*patterns)
378
+ (options[:minuses] ||= []) << build_patterns(patterns)
379
+ self
380
+ end
381
+
382
+ def union(*patterns)
383
+ (options[:unions] ||= []) << build_patterns(patterns)
384
+ self
385
+ end
386
+
387
+ ##
388
+ # @private
389
+ def build_patterns(patterns)
390
+ patterns.map do |pattern|
391
+ case pattern
392
+ when RDF::Query::Pattern then pattern
393
+ else RDF::Query::Pattern.new(*pattern.to_a)
394
+ end
395
+ end
396
+ end
397
+
398
+ ##
399
+ # @private
400
+ def filter(string)
401
+ (options[:filters] ||= []) << string
402
+ self
403
+ end
404
+
405
+ def filters(filters = nil)
406
+ options[:filters] ||= []
407
+ options[:filters] += filters.to_a
408
+ self
409
+ end
410
+
411
+ ##
412
+ # @return [Boolean]
413
+ def true?
414
+ case result
415
+ when TrueClass, FalseClass then result
416
+ when Enumerable then !result.empty?
417
+ else false
418
+ end
419
+ end
420
+
421
+ ##
422
+ # @return [Boolean]
423
+ def false?
424
+ !true?
425
+ end
426
+
427
+ ##
428
+ # @return [Enumerable<RDF::Query::Solution>]
429
+ def solutions
430
+ result
431
+ end
432
+
433
+ ##
434
+ # @yield [statement]
435
+ # @yieldparam [RDF::Statement]
436
+ # @return [Enumerator]
437
+ def each_statement(&block)
438
+ result.each_statement(&block)
439
+ end
440
+
441
+ ##
442
+ # @return [Object]
443
+ def result
444
+ @result ||= execute
445
+ end
446
+
447
+ ##
448
+ # @return [Object]
449
+ def execute
450
+ #query
451
+ #raise NotImplementedError
452
+ end
453
+
454
+ ##
455
+ # Returns the string representation of this query.
456
+ #
457
+ # @return [String]
458
+ def to_s
459
+ buffer = [form.to_s.gsub('_', ' ').upcase]
460
+ case form
461
+ when :select, :describe
462
+ buffer << 'DISTINCT' if options[:distinct]
463
+ buffer << 'REDUCED' if options[:reduced]
464
+ # Aggregates in select/describe
465
+ aggregates = [:count, :min, :max, :avg, :sum, :sample, :group_concat, :group_digest]
466
+ if (options.keys & aggregates).any?
467
+ (options.keys & aggregates).each do |agg|
468
+ case agg
469
+ when :sample
470
+ buffer << '(sql:' + agg.to_s.upcase
471
+ buffer << options[agg].map { |var| var.is_a?(String) ? var : "(?#{var})" }
472
+ when :group_concat, :group_digest
473
+ buffer << '(sql:' + agg.to_s.upcase
474
+ buffer << options[agg].map { |var| var.is_a?(Symbol) ? "(?#{var}" : "'#{var}'"}.join(', ')
475
+ buffer << ')'
476
+ else
477
+ buffer << '(' + agg.to_s.gsub('_', ' ').upcase
478
+ buffer << options[agg].map { |var| var.is_a?(String) ? var : "(?#{var})" }
479
+ end
480
+
481
+ buffer << 'AS ?' + agg.to_s + ')'
482
+ end
483
+ else
484
+ buffer << (values.empty? ? '*' : values.map { |v| serialize_value(v[1]) }.join(' '))
485
+ end
486
+ when :construct
487
+ buffer << '{'
488
+ buffer += serialize_patterns(@data_values)
489
+ buffer << '}'
490
+
491
+ # for virtuoso inserts
492
+ when :insert_data
493
+ buffer << "INTO GRAPH #{serialize_value(options[:graph])}" if options[:graph]
494
+ buffer << '{'
495
+ @data_values.each do |triple|
496
+ if triple.first.first.is_a?(RDF::Statement)
497
+ buffer << triple.map { |v| serialize_value(v[1])}
498
+ else
499
+ buffer << triple.map { |v| serialize_value(v[1])}.join(' ') + " ."
500
+ end
501
+ end
502
+ buffer << '}'
503
+
504
+ when :insert
505
+ buffer << "INTO GRAPH #{serialize_value(options[:graph])}" if options[:graph]
506
+ # buffer += serialize_patterns(options[:template])
507
+ # (@data_values.map { |v| puts v[1].inspect; puts 'xxx ' } )
508
+ buffer << '{'
509
+ buffer += serialize_patterns(@data_values)
510
+ buffer << '}'
511
+
512
+ when :delete_data
513
+ buffer << "FROM #{serialize_value(options[:graph])}" #if options[:graph]
514
+ buffer << '{'
515
+ @data_values.each do |triple|
516
+ if triple.first.first.is_a?(RDF::Statement)
517
+ buffer << triple.map { |v| serialize_value(v[1])}
518
+ else
519
+ buffer << triple.map { |v| serialize_value(v[1])}.join(' ') + " ."
520
+ end
521
+ end
522
+ buffer << '}'
523
+
524
+ when :delete
525
+ buffer << "FROM #{serialize_value(options[:graph])}" if options[:graph]
526
+ buffer << '{'
527
+ buffer += serialize_patterns(@data_values)
528
+ buffer << '}'
529
+
530
+ when :create, :drop
531
+ buffer << 'SILENT' if options[:silent]
532
+ buffer << "GRAPH #{serialize_value(options[:graph])}"
533
+
534
+ when :clear
535
+ buffer << "GRAPH #{serialize_value(options[:graph])}"
536
+
537
+ end
538
+
539
+ buffer << "FROM #{serialize_value(options[:from])}" if options[:from]
540
+
541
+ unless patterns.empty? && ([:describe, :insert_data, :delete_data, :create, :clear, :drop].include?(form))
542
+ buffer << 'WHERE {'
543
+
544
+ buffer << '{' if options[:unions]
545
+
546
+ buffer += serialize_patterns(patterns)
547
+ if options[:optionals]
548
+ options[:optionals].each do |patterns|
549
+ buffer << 'OPTIONAL {'
550
+ buffer += serialize_patterns(patterns)
551
+ buffer << '}'
552
+ end
553
+ end
554
+
555
+ if options[:minuses]
556
+ options[:minuses].each do |patterns|
557
+ buffer << 'MINUS {'
558
+ buffer += serialize_patterns(patterns)
559
+ buffer << '}'
560
+ end
561
+ end
562
+
563
+ if options[:filters]
564
+ buffer += options[:filters].map { |filter| "FILTER(#{filter})" }
565
+ end
566
+ buffer << '}'
567
+
568
+ if options[:unions]
569
+ options[:unions].each do |patterns|
570
+ buffer << 'UNION {'
571
+ buffer += serialize_patterns(patterns)
572
+ buffer << '}'
573
+ end
574
+ buffer << '}'
575
+ end
576
+
577
+ end
578
+
579
+ if options[:order_by]
580
+ buffer << 'ORDER BY'
581
+ buffer += options[:order_by].map { |var| var.is_a?(String) ? var : "?#{var}" }
582
+ end
583
+
584
+ buffer << "OFFSET #{options[:offset]}" if options[:offset]
585
+ buffer << "LIMIT #{options[:limit]}" if options[:limit]
586
+ options[:prefixes].reverse.each {|e| buffer.unshift("PREFIX #{e}") } if options[:prefixes]
587
+
588
+ buffer.join(' ')
589
+ end
590
+
591
+ ##
592
+ # @private
593
+ def serialize_patterns(patterns)
594
+ patterns.map do |p|
595
+ p.to_triple.map { |v| serialize_value(v) }.join(' ') << " ."
596
+ end
597
+ end
598
+
599
+ ##
600
+ # Outputs a developer-friendly representation of this query to `stderr`.
601
+ #
602
+ # @return [void]
603
+ def inspect!
604
+ warn(inspect)
605
+ self
606
+ end
607
+
608
+ ##
609
+ # Returns a developer-friendly representation of this query.
610
+ #
611
+ # @return [String]
612
+ def inspect
613
+ sprintf("#<%s:%#0x(%s)>", self.class.name, __id__, to_s)
614
+ end
615
+
616
+ ##
617
+ # Serializes an RDF::Value into a format appropriate for select, construct, and where clauses
618
+ #
619
+ # @param [RDF::Value]
620
+ # @return [String]
621
+ # @private
622
+ def serialize_value(value)
623
+ # SPARQL queries are UTF-8, but support ASCII-style Unicode escapes, so
624
+ # the N-Triples serializer is fine unless it's a variable:
625
+ case
626
+ when value.is_a?(String) then value.inspect
627
+ when value.variable? then value.to_s
628
+ else RDF::NTriples.serialize(value)
629
+ end
630
+ end
631
+ end
632
+ end