sparql-client 3.2.0 → 3.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 91430f8e6c63118569f32b193b274fe8f19ca59728af08591177bdd5795ff05e
4
- data.tar.gz: 3e0da28e7522a09004e2ac4bcd1b42e17cc943f02fd242d3a9e399597baa33e1
3
+ metadata.gz: 2c9eca6a3f6e57b16150e55c6a595c616c4b8b58778772e619168e5dd19c05a5
4
+ data.tar.gz: 5c383ab056d6f28951a366a5cb546f3aa900e7c81170b2f42a04ce72167deea8
5
5
  SHA512:
6
- metadata.gz: 21e38994cd92126304d4a481a3ee471018c9dd99206d537340b2c91eb49bd853bd76fa3bf558e795ed18110b6d639f97cb5288d2b520f5196739d7bb9cc0f095
7
- data.tar.gz: 75a14ccdce74d985fb83f541853e4e8d95edfeb9c8d59a5f5fbc988cf378c985623df574585480e30945791327ce9f99ab5da2178b5c886c8cc91152d7174442
6
+ metadata.gz: 12f686f4d066f3539de0fd3924895bbd854d2998f4b666d60e58df2efac33343c214588ff19b5ed759d8f2c481f8c3ff5a02f9f432fe55977a56e4080029d8c1
7
+ data.tar.gz: 4168b202c647758fffb13ad0a6445b46d797a34482764cdc5efb3a9e36a258c0157e03f958eaf5a96530453210afbbcc986aa0b3374a849dde73a9f090d15b6d
data/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  This is a [Ruby][] implementation of a [SPARQL][] client for [RDF.rb][].
4
4
 
5
- * <https://ruby-rdf.github.com/sparql-client/>
5
+ * <https://ruby-rdf.github.io/sparql-client/>
6
6
 
7
- [![Gem Version](https://badge.fury.io/rb/sparql-client.png)](https://badge.fury.io/rb/sparql-client)
7
+ [![Gem Version](https://badge.fury.io/rb/sparql-client.svg)](https://badge.fury.io/rb/sparql-client)
8
8
  [![Build Status](https://github.com/ruby-rdf/sparql-client/workflows/CI/badge.svg?branch=develop)](https://github.com/ruby-rdf/sparql-client/actions?query=workflow%3ACI)
9
9
  [![Coverage Status](https://coveralls.io/repos/ruby-rdf/sparql-client/badge.svg?branch=master&service=github)](https://coveralls.io/github/ruby-rdf/sparql-client?branch=master)
10
10
  [![Gitter chat](https://badges.gitter.im/ruby-rdf/rdf.png)](https://gitter.im/ruby-rdf/rdf)
@@ -44,7 +44,7 @@ sparql = SPARQL::Client.new("http://dbpedia.org/sparql", headers: {'User-Agent'
44
44
 
45
45
  ```ruby
46
46
  require 'sparql/client'
47
- sparql = SPARQL::Client.new("http://dbpedia.org/sparql", { graph: "http://dbpedia.org" })
47
+ sparql = SPARQL::Client.new("http://dbpedia.org/sparql", graph: "http://dbpedia.org")
48
48
  ```
49
49
 
50
50
 
@@ -117,10 +117,10 @@ sparql.delete_data(data)
117
117
 
118
118
  ## Documentation
119
119
 
120
- * [SPARQL::Client](https://www.rubydoc.info/github/ruby-rdf/sparql-client/SPARQL/Client)
121
- * [SPARQL::Client::Query](https://www.rubydoc.info/github/ruby-rdf/sparql-client/SPARQL/Client/Query)
122
- * [SPARQL::Client::Repository](https://www.rubydoc.info/github/ruby-rdf/sparql-client/SPARQL/Client/Repository)
123
- * [SPARQL::Client::Update](https://www.rubydoc.info/github/ruby-rdf/sparql-client/SPARQL/Client/Update)
120
+ * [SPARQL::Client](https://ruby-rdf.github.io/sparql-client/SPARQL/Client)
121
+ * [SPARQL::Client::Query](https://ruby-rdf.github.io/sparql-client/SPARQL/Client/Query)
122
+ * [SPARQL::Client::Repository](https://ruby-rdf.github.io/sparql-client/SPARQL/Client/Repository)
123
+ * [SPARQL::Client::Update](https://ruby-rdf.github.io/sparql-client/SPARQL/Client/Update)
124
124
 
125
125
  ## Dependencies
126
126
 
@@ -191,7 +191,7 @@ This repository uses [Git Flow](https://github.com/nvie/gitflow) to mange develo
191
191
 
192
192
  ## Resources
193
193
 
194
- * <https://ruby-rdf.github.com/sparql-client/>
194
+ * <https://ruby-rdf.github.io/sparql-client/>
195
195
  * <https://github.com/ruby-rdf/sparql-client>
196
196
  * <https://rubygems.org/gems/sparql-client>
197
197
  * <https://raa.ruby-lang.org/project/sparql-client/>
@@ -207,7 +207,7 @@ see <https://unlicense.org/> or the accompanying {file:UNLICENSE} file.
207
207
  [SPARQL]: https://en.wikipedia.org/wiki/SPARQL
208
208
  [SPARQL JSON]: https://www.w3.org/TR/rdf-sparql-json-res/
209
209
  [RDF.rb]: https://rubygems.org/gems/rdf
210
- [RDF::Repository]: https://rubydoc.info/github/ruby-rdf/rdf/RDF/Repository
210
+ [RDF::Repository]: https://ruby-rdf.github.io/rdf/RDF/Repository
211
211
  [DSL]: https://en.wikipedia.org/wiki/Domain-specific_language
212
212
  "domain-specific language"
213
213
  [YARD]: https://yardoc.org/
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.2.0
1
+ 3.2.2
@@ -111,7 +111,7 @@ class SPARQL::Client
111
111
 
112
112
  ##
113
113
  # @example ASK WHERE { ?s ?p ?o . }
114
- # query.ask.where([:s, :p, :o])
114
+ # Query.ask.where([:s, :p, :o])
115
115
  #
116
116
  # @return [Query]
117
117
  # @see https://www.w3.org/TR/sparql11-query/#ask
@@ -122,13 +122,13 @@ class SPARQL::Client
122
122
 
123
123
  ##
124
124
  # @example `SELECT * WHERE { ?s ?p ?o . }`
125
- # query.select.where([:s, :p, :o])
125
+ # Query.select.where([:s, :p, :o])
126
126
  #
127
127
  # @example `SELECT ?s WHERE {?s ?p ?o .}`
128
- # query.select(:s).where([:s, :p, :o])
128
+ # Query.select(:s).where([:s, :p, :o])
129
129
  #
130
130
  # @example `SELECT COUNT(?uri as ?c) WHERE {?uri a owl:Class}`
131
- # query.select(count: {uri: :c}).where([:uri, RDF.type, RDF::OWL.Class])
131
+ # Query.select(count: {uri: :c}).where([:uri, RDF.type, RDF::OWL.Class])
132
132
  #
133
133
  # @param [Array<Symbol>, Hash{Symbol => RDF::Query::Variable}] variables
134
134
  # @return [Query]
@@ -144,7 +144,7 @@ class SPARQL::Client
144
144
 
145
145
  ##
146
146
  # @example DESCRIBE * WHERE { ?s ?p ?o . }
147
- # query.describe.where([:s, :p, :o])
147
+ # Query.describe.where([:s, :p, :o])
148
148
  #
149
149
  # @param [Array<Symbol>] variables
150
150
  # @return [Query]
@@ -158,7 +158,7 @@ class SPARQL::Client
158
158
 
159
159
  ##
160
160
  # @example CONSTRUCT { ?s ?p ?o . } WHERE { ?s ?p ?o . }
161
- # query.construct([:s, :p, :o]).where([:s, :p, :o])
161
+ # Query.construct([:s, :p, :o]).where([:s, :p, :o])
162
162
  #
163
163
  # @param [Array<RDF::Query::Pattern, Array>] patterns
164
164
  # @return [Query]
@@ -170,7 +170,7 @@ class SPARQL::Client
170
170
 
171
171
  ##
172
172
  # @example SELECT * FROM <a> WHERE \{ ?s ?p ?o . \}
173
- # query.select.from(RDF::URI.new(a)).where([:s, :p, :o])
173
+ # Query.select.from(RDF::URI.new(a)).where([:s, :p, :o])
174
174
  #
175
175
  # @param [RDF::URI] uri
176
176
  # @return [Query]
@@ -182,22 +182,22 @@ class SPARQL::Client
182
182
 
183
183
  ##
184
184
  # @example SELECT * WHERE { ?s ?p ?o . }
185
- # query.select.where([:s, :p, :o])
186
- # query.select.whether([:s, :p, :o])
185
+ # Query.select.where([:s, :p, :o])
186
+ # Query.select.whether([:s, :p, :o])
187
187
  #
188
188
  # @example SELECT * WHERE { { SELECT * WHERE { ?s ?p ?o . } } . ?s ?p ?o . }
189
- # subquery = query.select.where([:s, :p, :o])
190
- # query.select.where([:s, :p, :o], subquery)
189
+ # subquery = Query.select.where([:s, :p, :o])
190
+ # Query.select.where([:s, :p, :o], subquery)
191
191
  #
192
192
  # @example SELECT * WHERE { { SELECT * WHERE { ?s ?p ?o . } } . ?s ?p ?o . }
193
- # query.select.where([:s, :p, :o]) do |q|
193
+ # Query.select.where([:s, :p, :o]) do |q|
194
194
  # q.select.where([:s, :p, :o])
195
195
  # end
196
196
  #
197
197
  # Block form can be used for chaining calls in addition to creating sub-select queries.
198
198
  #
199
199
  # @example SELECT * WHERE { ?s ?p ?o . } ORDER BY ?o
200
- # query.select.where([:s, :p, :o]) do
200
+ # Query.select.where([:s, :p, :o]) do
201
201
  # order(:o)
202
202
  # end
203
203
  #
@@ -236,14 +236,14 @@ class SPARQL::Client
236
236
 
237
237
  ##
238
238
  # @example SELECT * WHERE { ?s ?p ?o . } ORDER BY ?o
239
- # query.select.where([:s, :p, :o]).order(:o)
240
- # query.select.where([:s, :p, :o]).order_by(:o)
239
+ # Query.select.where([:s, :p, :o]).order(:o)
240
+ # Query.select.where([:s, :p, :o]).order_by(:o)
241
241
  #
242
242
  # @example SELECT * WHERE { ?s ?p ?o . } ORDER BY ?o ?p
243
- # query.select.where([:s, :p, :o]).order_by(:o, :p)
243
+ # Query.select.where([:s, :p, :o]).order_by(:o, :p)
244
244
  #
245
245
  # @example SELECT * WHERE { ?s ?p ?o . } ORDER BY ASC(?o) DESC(?p)
246
- # query.select.where([:s, :p, :o]).order_by(o: :asc, p: :desc)
246
+ # Query.select.where([:s, :p, :o]).order_by(o: :asc, p: :desc)
247
247
  #
248
248
  # @param [Array<Symbol, String>] variables
249
249
  # @return [Query]
@@ -257,8 +257,8 @@ class SPARQL::Client
257
257
 
258
258
  ##
259
259
  # @example SELECT * WHERE { ?s ?p ?o . } ORDER BY ASC(?o)
260
- # query.select.where([:s, :p, :o]).order.asc(:o)
261
- # query.select.where([:s, :p, :o]).asc(:o)
260
+ # Query.select.where([:s, :p, :o]).order.asc(:o)
261
+ # Query.select.where([:s, :p, :o]).asc(:o)
262
262
  #
263
263
  # @param [Array<Symbol, String>] var
264
264
  # @return [Query]
@@ -270,8 +270,8 @@ class SPARQL::Client
270
270
 
271
271
  ##
272
272
  # @example SELECT * WHERE { ?s ?p ?o . } ORDER BY DESC(?o)
273
- # query.select.where([:s, :p, :o]).order.desc(:o)
274
- # query.select.where([:s, :p, :o]).desc(:o)
273
+ # Query.select.where([:s, :p, :o]).order.desc(:o)
274
+ # Query.select.where([:s, :p, :o]).desc(:o)
275
275
  #
276
276
  # @param [Array<Symbol, String>] var
277
277
  # @return [Query]
@@ -283,7 +283,7 @@ class SPARQL::Client
283
283
 
284
284
  ##
285
285
  # @example SELECT ?s WHERE { ?s ?p ?o . } GROUP BY ?s
286
- # query.select(:s).where([:s, :p, :o]).group_by(:s)
286
+ # Query.select(:s).where([:s, :p, :o]).group_by(:s)
287
287
  #
288
288
  # @param [Array<Symbol, String>] variables
289
289
  # @return [Query]
@@ -297,7 +297,7 @@ class SPARQL::Client
297
297
 
298
298
  ##
299
299
  # @example SELECT DISTINCT ?s WHERE { ?s ?p ?o . }
300
- # query.select(:s).distinct.where([:s, :p, :o])
300
+ # Query.select(:s).distinct.where([:s, :p, :o])
301
301
  #
302
302
  # @return [Query]
303
303
  # @see https://www.w3.org/TR/sparql11-query/#modDuplicates
@@ -308,7 +308,7 @@ class SPARQL::Client
308
308
 
309
309
  ##
310
310
  # @example SELECT REDUCED ?s WHERE { ?s ?p ?o . }
311
- # query.select(:s).reduced.where([:s, :p, :o])
311
+ # Query.select(:s).reduced.where([:s, :p, :o])
312
312
  #
313
313
  # @return [Query]
314
314
  # @see https://www.w3.org/TR/sparql11-query/#modDuplicates
@@ -319,7 +319,8 @@ class SPARQL::Client
319
319
 
320
320
  ##
321
321
  # @example SELECT * WHERE { GRAPH ?g { ?s ?p ?o . } }
322
- # query.select.graph(:g).where([:s, :p, :o])
322
+ # Query.select.graph(:g).where([:s, :p, :o])
323
+ #
323
324
  # @param [RDF::Value] graph_uri_or_var
324
325
  # @return [Query]
325
326
  # @see https://www.w3.org/TR/sparql11-query/#queryDataset
@@ -335,7 +336,7 @@ class SPARQL::Client
335
336
 
336
337
  ##
337
338
  # @example SELECT * WHERE { ?s ?p ?o . } OFFSET 100
338
- # query.select.where([:s, :p, :o]).offset(100)
339
+ # Query.select.where([:s, :p, :o]).offset(100)
339
340
  #
340
341
  # @param [Integer, #to_i] start
341
342
  # @return [Query]
@@ -346,7 +347,7 @@ class SPARQL::Client
346
347
 
347
348
  ##
348
349
  # @example SELECT * WHERE { ?s ?p ?o . } LIMIT 10
349
- # query.select.where([:s, :p, :o]).limit(10)
350
+ # Query.select.where([:s, :p, :o]).limit(10)
350
351
  #
351
352
  # @param [Integer, #to_i] length
352
353
  # @return [Query]
@@ -357,7 +358,7 @@ class SPARQL::Client
357
358
 
358
359
  ##
359
360
  # @example SELECT * WHERE { ?s ?p ?o . } OFFSET 100 LIMIT 10
360
- # query.select.where([:s, :p, :o]).slice(100, 10)
361
+ # Query.select.where([:s, :p, :o]).slice(100, 10)
361
362
  #
362
363
  # @param [Integer, #to_i] start
363
364
  # @param [Integer, #to_i] length
@@ -371,7 +372,7 @@ class SPARQL::Client
371
372
  ##
372
373
  # @overload prefix(prefix: uri)
373
374
  # @example PREFIX dc: <http://purl.org/dc/elements/1.1/> PREFIX foaf: <http://xmlns.com/foaf/0.1/> SELECT * WHERE \{ ?s ?p ?o . \}
374
- # query.select.
375
+ # Query.select.
375
376
  # prefix(dc: RDF::URI("http://purl.org/dc/elements/1.1/")).
376
377
  # prefix(foaf: RDF::URI("http://xmlns.com/foaf/0.1/")).
377
378
  # where([:s, :p, :o])
@@ -382,7 +383,7 @@ class SPARQL::Client
382
383
  #
383
384
  # @overload prefix(string)
384
385
  # @example PREFIX dc: <http://purl.org/dc/elements/1.1/> PREFIX foaf: <http://xmlns.com/foaf/0.1/> SELECT * WHERE \{ ?s ?p ?o . \}
385
- # query.select.
386
+ # Query.select.
386
387
  # prefix("dc: <http://purl.org/dc/elements/1.1/>").
387
388
  # prefix("foaf: <http://xmlns.com/foaf/0.1/>").
388
389
  # where([:s, :p, :o])
@@ -406,13 +407,13 @@ class SPARQL::Client
406
407
 
407
408
  ##
408
409
  # @example SELECT * WHERE \{ ?s ?p ?o . OPTIONAL \{ ?s a ?o . ?s \<http://purl.org/dc/terms/abstract\> ?o . \} \}
409
- # query.select.where([:s, :p, :o]).
410
+ # Query.select.where([:s, :p, :o]).
410
411
  # optional([:s, RDF.type, :o], [:s, RDF::Vocab::DC.abstract, :o])
411
412
  #
412
413
  # The block form can be used for adding filters:
413
414
  #
414
415
  # @example ASK WHERE { ?s ?p ?o . OPTIONAL { ?s ?p ?o . FILTER(regex(?s, 'Abiline, Texas'))} }
415
- # query.ask.where([:s, :p, :o]).optional([:s, :p, :o]) do
416
+ # Query.ask.where([:s, :p, :o]).optional([:s, :p, :o]) do
416
417
  # filter("regex(?s, 'Abiline, Texas')")
417
418
  # end
418
419
  #
@@ -441,22 +442,89 @@ class SPARQL::Client
441
442
  self
442
443
  end
443
444
 
445
+ ##
446
+ # Federated Queries via the SERVICE keyword.
447
+ #
448
+ # Supports limited use of the SERVICE keyword with an endpoint term, a sequence of patterns, a query, or a block.
449
+ #
450
+ # @example SELECT * WHERE \{ ?s ?p1 ?o1 . SERVICE ?l \{ ?s ?p2 ?o2 \} \}
451
+ # Query.select.where([:s, :p1, :o1]).
452
+ # service(:l, [:s, :p2, :o2])
453
+ #
454
+ # @example SELECT * WHERE \{ ?book <http://purl.org/dc/terms/title> ?title . SERVICE ?l \{ ?book <http://purl.org/dc/elements/1.1/title> ?title . FILTER(langmatches(?title, 'en')) \} \}
455
+ # query1 = SPARQL::Client::Query.select.
456
+ # where([:book, RDF::Vocab::DC11.title, :title]).
457
+ # filter("langmatches(?title, 'en')")
458
+ # Query.select.where([:book, RDF::Vocab::DC.title, :title]).service(?l, query1)
459
+ #
460
+ # The block form can be used for more complicated queries, using the `select` form (note, use either block or argument forms, not both):
461
+ #
462
+ # @example SELECT * WHERE \{ ?book dc:title ?title \} SERVICE ?l \{ ?book dc11:title ?title \}
463
+ # query1 = SPARQL::Client::Query.select.where([:book, RDF::Vocab::DC11.title, :title])
464
+ # Query.select.where([:book, RDF::Vocab::DC.title, :title]).service :l do |q|
465
+ # q.select.
466
+ # where([:book, RDF::Vocab::DC11.title, :title])
467
+ # end
468
+ #
469
+ # @example SELECT * WHERE \{ ?s ?p1 ?o1 . SERVICE SILENT ?l \{ ?s ?p2 ?o2 \} \}
470
+ # Query.select.where([:s, :p1, :o1]).
471
+ # service(:l, [:s, :p2, :o2], silent: true)
472
+ #
473
+ # @param [Array<RDF::Query::Pattern, Array>] patterns
474
+ # splat of zero or more patterns followed by zero or more queries.
475
+ # @param [Boolean] silent
476
+ # @yield [query]
477
+ # Yield form with or without argument; without an argument, evaluates within the query.
478
+ # @yieldparam [SPARQL::Client::Query] query used for adding select clauses.
479
+ # @return [Query]
480
+ # @see https://www.w3.org/TR/sparql11-federated-query/
481
+ def service(endpoint, *patterns, silent: false, &block)
482
+ service = {
483
+ endpoint: (endpoint.is_a?(Symbol) ? RDF::Query::Variable.new(endpoint) : endpoint),
484
+ silent: silent,
485
+ query: nil
486
+ }
487
+ (options[:services] ||= []) << service
488
+
489
+ if block_given?
490
+ raise ArgumentError, "#service requires either arguments or a block, not both." unless patterns.empty?
491
+ # Evaluate calls in a new query instance
492
+ query = self.class.select.where
493
+ case block.arity
494
+ when 1 then block.call(query)
495
+ else query.instance_eval(&block)
496
+ end
497
+ service[:query] = query
498
+ elsif patterns.all? {|p| p.is_a?(SPARQL::Client::Query)}
499
+ # With argument form, all must be patterns or queries
500
+ raise ArgumentError, "#service arguments are triple patterns or a query, not both." if patterns.length != 1
501
+ service[:query] = patterns.first
502
+ elsif patterns.all? {|p| p.is_a?(Array)}
503
+ # With argument form, all must be patterns, or queries
504
+ service[:query] = self.class.select.where(*patterns)
505
+ else
506
+ raise ArgumentError, "#service arguments are triple patterns a query, not both."
507
+ end
508
+
509
+ self
510
+ end
511
+
444
512
  ##
445
513
  # @example SELECT * WHERE \{ ?book dc:title ?title \} UNION \{ ?book dc11:title ?title \}
446
- # query.select.where([:book, RDF::Vocab::DC.title, :title]).
514
+ # Query.select.where([:book, RDF::Vocab::DC.title, :title]).
447
515
  # union([:book, RDF::Vocab::DC11.title, :title])
448
516
  #
449
517
  # @example SELECT * WHERE \{ ?book dc:title ?title \} UNION \{ ?book dc11:title ?title . FILTER(langmatches(lang(?title), 'EN'))\}
450
518
  # query1 = SPARQL::Client::Query.select.
451
519
  # where([:book, RDF::Vocab::DC11.title, :title]).
452
520
  # filter("langmatches(?title, 'en')")
453
- # query.select.where([:book, RDF::Vocab::DC.title, :title]).union(query1)
521
+ # Query.select.where([:book, RDF::Vocab::DC.title, :title]).union(query1)
454
522
  #
455
523
  # The block form can be used for more complicated queries, using the `select` form (note, use either block or argument forms, not both):
456
524
  #
457
525
  # @example SELECT * WHERE \{ ?book dc:title ?title \} UNION \{ ?book dc11:title ?title . FILTER(langmatches(lang(?title), 'EN'))\}
458
526
  # query1 = SPARQL::Client::Query.select.where([:book, RDF::Vocab::DC11.title, :title]).filter("langmatches(?title, 'en')")
459
- # query.select.where([:book, RDF::Vocab::DC.title, :title]).union do |q|
527
+ # Query.select.where([:book, RDF::Vocab::DC.title, :title]).union do |q|
460
528
  # q.select.
461
529
  # where([:book, RDF::Vocab::DC11.title, :title]).
462
530
  # filter("langmatches(?title, 'en')")
@@ -468,7 +536,7 @@ class SPARQL::Client
468
536
  # Yield form with or without argument; without an argument, evaluates within the query.
469
537
  # @yieldparam [SPARQL::Client::Query] query used for adding select clauses.
470
538
  # @return [Query]
471
- # @see https://www.w3.org/TR/sparql11-query/#optionals
539
+ # @see https://www.w3.org/TR/sparql11-query/#alternatives
472
540
  def union(*patterns, &block)
473
541
  options[:unions] ||= []
474
542
 
@@ -488,7 +556,7 @@ class SPARQL::Client
488
556
  # With argument form, all must be patterns, or queries
489
557
  options[:unions] << self.class.select.where(*patterns)
490
558
  else
491
- raise ArgumentError, "#union arguments are triple patters or queries, not both."
559
+ raise ArgumentError, "#union arguments are triple patterns or queries, not both."
492
560
  end
493
561
 
494
562
  self
@@ -496,20 +564,20 @@ class SPARQL::Client
496
564
 
497
565
  ##
498
566
  # @example SELECT * WHERE \{ ?book dc:title ?title . MINUS \{ ?book dc11:title ?title \} \}
499
- # query.select.where([:book, RDF::Vocab::DC.title, :title]).
567
+ # Query.select.where([:book, RDF::Vocab::DC.title, :title]).
500
568
  # minus([:book, RDF::Vocab::DC11.title, :title])
501
569
  #
502
570
  # @example SELECT * WHERE \{ ?book dc:title ?title MINUS \{ ?book dc11:title ?title . FILTER(langmatches(lang(?title), 'EN')) \} \}
503
571
  # query1 = SPARQL::Client::Query.select.
504
572
  # where([:book, RDF::Vocab::DC11.title, :title]).
505
573
  # filter("langmatches(?title, 'en')")
506
- # query.select.where([:book, RDF::Vocab::DC.title, :title]).minus(query1)
574
+ # Query.select.where([:book, RDF::Vocab::DC.title, :title]).minus(query1)
507
575
  #
508
576
  # The block form can be used for more complicated queries, using the `select` form (note, use either block or argument forms, not both):
509
577
  #
510
578
  # @example SELECT * WHERE \{ ?book dc:title ?title MINUS \{ ?book dc11:title ?title . FILTER(langmatches(lang(?title), 'EN'))\} \}
511
579
  # query1 = SPARQL::Client::Query.select.where([:book, RDF::Vocab::DC11.title, :title]).filter("langmatches(?title, 'en')")
512
- # query.select.where([:book, RDF::Vocab::DC.title, :title]).minus do |q|
580
+ # Query.select.where([:book, RDF::Vocab::DC.title, :title]).minus do |q|
513
581
  # q.select.
514
582
  # where([:book, RDF::Vocab::DC11.title, :title]).
515
583
  # filter("langmatches(?title, 'en')")
@@ -521,7 +589,7 @@ class SPARQL::Client
521
589
  # Yield form with or without argument; without an argument, evaluates within the query.
522
590
  # @yieldparam [SPARQL::Client::Query] query used for adding select clauses.
523
591
  # @return [Query]
524
- # @see https://www.w3.org/TR/sparql11-query/#optionals
592
+ # @see https://www.w3.org/TR/sparql11-query/#negation
525
593
  def minus(*patterns, &block)
526
594
  options[:minuses] ||= []
527
595
 
@@ -541,7 +609,7 @@ class SPARQL::Client
541
609
  # With argument form, all must be patterns, or queries
542
610
  options[:minuses] << self.class.select.where(*patterns)
543
611
  else
544
- raise ArgumentError, "#minus arguments are triple patters or queries, not both."
612
+ raise ArgumentError, "#minus arguments are triple patterns or queries, not both."
545
613
  end
546
614
 
547
615
  self
@@ -557,12 +625,12 @@ class SPARQL::Client
557
625
  #
558
626
  # @overload values(vars, *data)
559
627
  # @example single variable with multiple values
560
- # query.select
628
+ # Query.select
561
629
  # .where([:s, RDF::URI('http://purl.org/dc/terms/title'), :title])
562
630
  # .values(:title, "This title", "Another title")
563
631
  #
564
632
  # @example multiple variables with multiple values
565
- # query.select
633
+ # Query.select
566
634
  # .where([:s, RDF::URI('http://purl.org/dc/terms/title'), :title],
567
635
  # [:s, RDF.type, :type])
568
636
  # .values([:type, :title],
@@ -570,7 +638,7 @@ class SPARQL::Client
570
638
  # [RDF::URI('http://pcdm.org/models#Collection', 'Another title'])
571
639
  #
572
640
  # @example multiple variables with UNDEF
573
- # query.select
641
+ # Query.select
574
642
  # .where([:s, RDF::URI('http://purl.org/dc/terms/title'), :title],
575
643
  # [:s, RDF.type, :type])
576
644
  # .values([:type, :title],
@@ -626,7 +694,7 @@ class SPARQL::Client
626
694
 
627
695
  ##
628
696
  # @example ASK WHERE { ?s ?p ?o . FILTER(regex(?s, 'Abiline, Texas')) }
629
- # query.ask.where([:s, :p, :o]).filter("regex(?s, 'Abiline, Texas')")
697
+ # Query.ask.where([:s, :p, :o]).filter("regex(?s, 'Abiline, Texas')")
630
698
  # @return [Query]
631
699
  def filter(string)
632
700
  ((options[:filters] ||= []) << Filter.new(string)) if string and not string.empty?
@@ -796,6 +864,16 @@ class SPARQL::Client
796
864
  if options[:filters]
797
865
  buffer += options[:filters].map(&:to_s)
798
866
  end
867
+
868
+ if options[:services]
869
+ options[:services].each do |service|
870
+ buffer << 'SERVICE'
871
+ buffer << 'SILENT' if service[:silent]
872
+ buffer << SPARQL::Client.serialize_value(service[:endpoint])
873
+ buffer << service[:query].to_s_ggp
874
+ end
875
+ end
876
+
799
877
  if options[:values]
800
878
  vars = options[:values].first.map {|var| SPARQL::Client.serialize_value(var)}
801
879
  buffer << "VALUES (#{vars.join(' ')}) {"
data/lib/sparql/client.rb CHANGED
@@ -116,7 +116,14 @@ module SPARQL
116
116
  # Close the http connection when object is deallocated
117
117
  def self.finalize(klass)
118
118
  proc do
119
- klass.shutdown if klass.respond_to?(:shutdown)
119
+ if klass.respond_to?(:shutdown)
120
+ begin
121
+ # Attempt asynchronous shutdown
122
+ Thread.new {klass.shutdown}
123
+ rescue ThreadError
124
+ klass.shutdown
125
+ end
126
+ end
120
127
  end
121
128
  end
122
129
 
@@ -423,7 +430,13 @@ module SPARQL
423
430
  end
424
431
  RDF::Query::Solution.new(row)
425
432
  end
426
- RDF::Query::Solutions.new(solutions)
433
+ solns = RDF::Query::Solutions.new(solutions)
434
+
435
+ # Set variable names explicitly
436
+ if json.fetch('head', {}).has_key?('vars')
437
+ solns.variable_names = json['head']['vars'].map(&:to_sym)
438
+ end
439
+ solns
427
440
  end
428
441
  end
429
442
 
@@ -484,20 +497,23 @@ module SPARQL
484
497
  vars = tsv.shift.map {|h| h.sub(/^\?/, '')}
485
498
  solutions = RDF::Query::Solutions.new
486
499
  tsv.each do |row|
500
+ # Flesh out columns which may be missing
501
+ vars.each_with_index do |_, i|
502
+ row[i] ||= ""
503
+ end
487
504
  solution = RDF::Query::Solution.new
488
505
  row.each_with_index do |v, i|
489
- if !v.empty?
490
- term = RDF::NTriples.unserialize(v) || case v
491
- when /^\d+\.\d*[eE][+-]?[0-9]+$/ then RDF::Literal::Double.new(v)
492
- when /^\d*\.\d+[eE][+-]?[0-9]+$/ then RDF::Literal::Double.new(v)
493
- when /^\d*\.\d+$/ then RDF::Literal::Decimal.new(v)
494
- when /^\d+$/ then RDF::Literal::Integer.new(v)
495
- else
496
- RDF::Literal(v)
497
- end
498
- nodes[term.id] = term if term.is_a? RDF::Node
499
- solution[vars[i].to_sym] = term
506
+ term = case v
507
+ when "" then RDF::Literal("")
508
+ when /^\d+\.\d*[eE][+-]?[0-9]+$/ then RDF::Literal::Double.new(v)
509
+ when /^\d*\.\d+[eE][+-]?[0-9]+$/ then RDF::Literal::Double.new(v)
510
+ when /^\d*\.\d+$/ then RDF::Literal::Decimal.new(v)
511
+ when /^\d+$/ then RDF::Literal::Integer.new(v)
512
+ else
513
+ RDF::NTriples.unserialize(v) || RDF::Literal(v)
500
514
  end
515
+ nodes[term.id] = term if term.is_a? RDF::Node
516
+ solution[vars[i].to_sym] = term
501
517
  end
502
518
  solutions << solution
503
519
  end
@@ -506,45 +522,57 @@ module SPARQL
506
522
 
507
523
  ##
508
524
  # @param [String, IO, Nokogiri::XML::Node, REXML::Element] xml
525
+ # @param [Symbol] library (:nokogiri)
526
+ # One of :nokogiri or :rexml.
509
527
  # @return [<RDF::Query::Solutions>]
510
528
  # @see https://www.w3.org/TR/rdf-sparql-json-res/#results
511
- def self.parse_xml_bindings(xml, nodes = {})
529
+ def self.parse_xml_bindings(xml, nodes = {}, library: :nokogiri)
512
530
  xml.force_encoding(::Encoding::UTF_8) if xml.respond_to?(:force_encoding)
513
531
 
514
- if defined?(::Nokogiri)
532
+ if defined?(::Nokogiri) && library == :nokogiri
515
533
  xml = Nokogiri::XML(xml).root unless xml.is_a?(Nokogiri::XML::Document)
516
534
  case
517
- when boolean = xml.xpath("//sparql:boolean", XMLNS)[0]
518
- boolean.text == 'true'
519
- when results = xml.xpath("//sparql:results", XMLNS)[0]
520
- solutions = results.elements.map do |result|
521
- row = {}
522
- result.elements.each do |binding|
523
- name = binding.attr('name').to_sym
524
- value = binding.elements.first
525
- row[name] = parse_xml_value(value, nodes)
526
- end
527
- RDF::Query::Solution.new(row)
535
+ when boolean = xml.xpath("//sparql:boolean", XMLNS)[0]
536
+ boolean.text == 'true'
537
+ when results = xml.xpath("//sparql:results", XMLNS)[0]
538
+ solutions = results.elements.map do |result|
539
+ row = {}
540
+ result.elements.each do |binding|
541
+ name = binding.attr('name').to_sym
542
+ value = binding.elements.first
543
+ row[name] = parse_xml_value(value, nodes) if value
528
544
  end
529
- RDF::Query::Solutions.new(solutions)
545
+ RDF::Query::Solution.new(row)
546
+ end
547
+ solns = RDF::Query::Solutions.new(solutions)
548
+
549
+ # Set variable names explicitly
550
+ var_names = xml.xpath("//sparql:head/sparql:variable/@name", XMLNS)
551
+ solns.variable_names = var_names.map(&:to_s)
552
+ solns
530
553
  end
531
554
  else
532
555
  # REXML
533
556
  xml = REXML::Document.new(xml).root unless xml.is_a?(REXML::Element)
534
557
  case
535
- when boolean = xml.elements['boolean']
536
- boolean.text == 'true'
537
- when results = xml.elements['results']
538
- solutions = results.elements.map do |result|
539
- row = {}
540
- result.elements.each do |binding|
541
- name = binding.attributes['name'].to_sym
542
- value = binding.select { |node| node.kind_of?(::REXML::Element) }.first
543
- row[name] = parse_xml_value(value, nodes)
544
- end
545
- RDF::Query::Solution.new(row)
558
+ when boolean = xml.elements['boolean']
559
+ boolean.text == 'true'
560
+ when results = xml.elements['results']
561
+ solutions = results.elements.map do |result|
562
+ row = {}
563
+ result.elements.each do |binding|
564
+ name = binding.attributes['name'].to_sym
565
+ value = binding.select { |node| node.kind_of?(::REXML::Element) }.first
566
+ row[name] = parse_xml_value(value, nodes) if value
546
567
  end
547
- RDF::Query::Solutions.new(solutions)
568
+ RDF::Query::Solution.new(row)
569
+ end
570
+ solns = RDF::Query::Solutions.new(solutions)
571
+
572
+ # Set variable names explicitly
573
+ var_names = xml.elements['head'].elements.map {|e| e.attributes['name']}
574
+ solns.variable_names = var_names.map(&:to_sym)
575
+ solns
548
576
  end
549
577
  end
550
578
  end
@@ -578,7 +606,7 @@ module SPARQL
578
606
  # @return [RDF::Enumerable]
579
607
  def parse_rdf_serialization(response, **options)
580
608
  options = {content_type: response.content_type} unless options[:content_type]
581
- if reader = RDF::Reader.for(options)
609
+ if reader = RDF::Reader.for(**options)
582
610
  reader.new(response.body)
583
611
  else
584
612
  raise RDF::ReaderError, "no RDF reader was found for #{options}."
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sparql-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.0
4
+ version: 3.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arto Bendiken
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2021-12-13 00:00:00.000000000 Z
13
+ date: 2023-07-23 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rdf
@@ -19,6 +19,9 @@ dependencies:
19
19
  - - "~>"
20
20
  - !ruby/object:Gem::Version
21
21
  version: '3.2'
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 3.2.11
22
25
  type: :runtime
23
26
  prerelease: false
24
27
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,6 +29,9 @@ dependencies:
26
29
  - - "~>"
27
30
  - !ruby/object:Gem::Version
28
31
  version: '3.2'
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 3.2.11
29
35
  - !ruby/object:Gem::Dependency
30
36
  name: net-http-persistent
31
37
  requirement: !ruby/object:Gem::Requirement
@@ -35,7 +41,7 @@ dependencies:
35
41
  version: '4.0'
36
42
  - - ">="
37
43
  - !ruby/object:Gem::Version
38
- version: 4.0.1
44
+ version: 4.0.2
39
45
  type: :runtime
40
46
  prerelease: false
41
47
  version_requirements: !ruby/object:Gem::Requirement
@@ -45,7 +51,7 @@ dependencies:
45
51
  version: '4.0'
46
52
  - - ">="
47
53
  - !ruby/object:Gem::Version
48
- version: 4.0.1
54
+ version: 4.0.2
49
55
  - !ruby/object:Gem::Dependency
50
56
  name: rdf-spec
51
57
  requirement: !ruby/object:Gem::Requirement
@@ -80,14 +86,14 @@ dependencies:
80
86
  requirements:
81
87
  - - "~>"
82
88
  - !ruby/object:Gem::Version
83
- version: '3.10'
89
+ version: '3.12'
84
90
  type: :development
85
91
  prerelease: false
86
92
  version_requirements: !ruby/object:Gem::Requirement
87
93
  requirements:
88
94
  - - "~>"
89
95
  - !ruby/object:Gem::Version
90
- version: '3.10'
96
+ version: '3.12'
91
97
  - !ruby/object:Gem::Dependency
92
98
  name: rspec-its
93
99
  requirement: !ruby/object:Gem::Requirement
@@ -150,10 +156,15 @@ files:
150
156
  - lib/sparql/client/repository.rb
151
157
  - lib/sparql/client/update.rb
152
158
  - lib/sparql/client/version.rb
153
- homepage: https://github.com/ruby-rdf/sparql-client/
159
+ homepage: https://github.com/ruby-rdf/sparql-client
154
160
  licenses:
155
161
  - Unlicense
156
- metadata: {}
162
+ metadata:
163
+ documentation_uri: https://ruby-rdf.github.io/sparql-client
164
+ bug_tracker_uri: https://github.com/ruby-rdf/sparql-client/issues
165
+ homepage_uri: https://github.com/ruby-rdf/sparql-client
166
+ mailing_list_uri: https://lists.w3.org/Archives/Public/public-rdf-ruby/
167
+ source_code_uri: https://github.com/ruby-rdf/sparql-client
157
168
  post_install_message:
158
169
  rdoc_options: []
159
170
  require_paths:
@@ -169,7 +180,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
169
180
  - !ruby/object:Gem::Version
170
181
  version: '0'
171
182
  requirements: []
172
- rubygems_version: 3.3.3
183
+ rubygems_version: 3.3.26
173
184
  signing_key:
174
185
  specification_version: 4
175
186
  summary: SPARQL client for RDF.rb.