sparql-client 2.1.0 → 2.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7bb3fbfde7825e70b178ae2e502f4145fc75db84
4
- data.tar.gz: 128998297c153debdc7ec09547eedd1c6106f84e
3
+ metadata.gz: 63643389b5260847e6a5ff81f8ec4e7a8d754adf
4
+ data.tar.gz: b0ed32a9d7f1fd58efe6de87ab64f2eb0f10a758
5
5
  SHA512:
6
- metadata.gz: a64de18fb22d1f3f7662e02c9e65e5cbfa41ce083c9f73379112b833178ce3694575871675c2a18d1abb5a5950dd47d3e3b6732a15e239690128ca91fefb6cfa
7
- data.tar.gz: 168112994fc8f38b83ddb20a850042ea55c6b766b119cbb0054a6bcd83d6c32bb5ab441ff8e543e43d695e9e48153cb2f44c61205b5ce1f47ea47ee1f5cc7f61
6
+ metadata.gz: fcfec9d172d4bb98f27136bdde32f242780080b05b1fa92390fa69f3c4faea3aad03971dc7d19b22026e228065210b86ccd543d6a749d7fe1d132737480e9459
7
+ data.tar.gz: b0a1ce446f6930c620b78aee2978cd46b0c9d54f9fec3c08ea00c91f5761eeae083a19f07f00d8a48867505addb370d986d54ad9cb345dcd026826244caed2c3
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- #SPARQL Client for RDF.rb
1
+ # SPARQL Client for RDF.rb
2
2
 
3
3
  This is a [Ruby][] implementation of a [SPARQL][] client for [RDF.rb][].
4
4
 
@@ -8,7 +8,7 @@ This is a [Ruby][] implementation of a [SPARQL][] client for [RDF.rb][].
8
8
  [![Build Status](https://travis-ci.org/ruby-rdf/sparql-client.png?branch=master)](http://travis-ci.org/ruby-rdf/sparql-client)
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
 
11
- ##Features
11
+ ## Features
12
12
 
13
13
  * Executes queries against any SPARQL 1.0/1.1-compatible endpoint over HTTP,
14
14
  or against an `RDF::Queryable` instance, using the `SPARQL` gem.
@@ -22,7 +22,7 @@ This is a [Ruby][] implementation of a [SPARQL][] client for [RDF.rb][].
22
22
  * Supports accessing endpoints as read/write [`RDF::Repository`][RDF::Repository]
23
23
  instances {SPARQL::Client::Repository}.
24
24
 
25
- ##Examples
25
+ ## Examples
26
26
 
27
27
  ### Querying a remote SPARQL endpoint
28
28
  require 'sparql/client'
@@ -73,7 +73,7 @@ This is a [Ruby][] implementation of a [SPARQL][] client for [RDF.rb][].
73
73
  data = RDF::Graph.new do |graph|
74
74
  graph << [RDF::URI('http://example.org/jhacker'), RDF::Vocab::FOAF.name, "J. Random Hacker"]
75
75
  end
76
- insert_data(data)
76
+ sparql.insert_data(data)
77
77
 
78
78
  ### Deleting data from a graph
79
79
 
@@ -81,16 +81,16 @@ This is a [Ruby][] implementation of a [SPARQL][] client for [RDF.rb][].
81
81
  data = RDF::Graph.new do |graph|
82
82
  graph << [RDF::URI('http://example.org/jhacker'), RDF::Vocab::FOAF.name, "J. Random Hacker"]
83
83
  end
84
- delete_data(data)
84
+ sparql.delete_data(data)
85
85
 
86
- ##Documentation
86
+ ## Documentation
87
87
 
88
88
  * {SPARQL::Client}
89
89
  * {SPARQL::Client::Query}
90
90
  * {SPARQL::Client::Repository}
91
91
  * {SPARQL::Client::Update}
92
92
 
93
- ##Dependencies
93
+ ## Dependencies
94
94
 
95
95
  * [Ruby](http://ruby-lang.org/) (>= 2.2.2)
96
96
  * [RDF.rb](http://rubygems.org/gems/rdf) (>= 2.0)
@@ -98,14 +98,14 @@ This is a [Ruby][] implementation of a [SPARQL][] client for [RDF.rb][].
98
98
  * Soft dependency on [SPARQL](http://rubygems.org/gems/sparql) (>= 2.0)
99
99
  * Soft dependency on [Nokogiri](http://rubygems.org/gems/nokogiri) (>= 1.6)
100
100
 
101
- ##Installation
101
+ ## Installation
102
102
 
103
103
  The recommended installation method is via [RubyGems](http://rubygems.org/).
104
104
  To install the latest official release of the `SPARQL::Client` gem, do:
105
105
 
106
106
  % [sudo] gem install sparql-client
107
107
 
108
- ##Download
108
+ ## Download
109
109
 
110
110
  To get a local working copy of the development repository, do:
111
111
 
@@ -116,17 +116,17 @@ follows:
116
116
 
117
117
  % wget http://github.com/ruby-rdf/sparql-client/tarball/master
118
118
 
119
- ##Mailing List
119
+ ## Mailing List
120
120
 
121
121
  * <http://lists.w3.org/Archives/Public/public-rdf-ruby/>
122
122
 
123
- ##Authors
123
+ ## Authors
124
124
 
125
125
  * [Arto Bendiken](http://github.com/bendiken) - <http://ar.to/>
126
126
  * [Ben Lavender](http://github.com/bhuga) - <http://bhuga.net/>
127
127
  * [Gregg Kellogg](http://github.com/gkellogg) - <http://greggkellogg.net/>
128
128
 
129
- ##Contributors
129
+ ## Contributors
130
130
 
131
131
  * [Christoph Badura](http://github.com/bad) - <http://github.com/bad>
132
132
  * [James Hetherington](http://github.com/jamespjh) - <http://twitter.com/jamespjh>
@@ -140,7 +140,7 @@ follows:
140
140
  * [Thomas Feron](http://github.com/thoferon) - <http://github.com/thoferon>
141
141
  * [Nick Gottlieb](http://github.com/ngottlieb) - <http://www.nicholasgottlieb.com>
142
142
 
143
- ##Contributing
143
+ ## Contributing
144
144
  This repository uses [Git Flow](https://github.com/nvie/gitflow) to mange development and release activity. All submissions _must_ be on a feature branch based on the _develop_ branch to ease staging and integration.
145
145
 
146
146
  * Do your best to adhere to the existing coding conventions and idioms.
@@ -155,16 +155,15 @@ This repository uses [Git Flow](https://github.com/nvie/gitflow) to mange develo
155
155
  of thumb, additions larger than about 15 lines of code), we need an
156
156
  explicit [public domain dedication][PDD] on record from you.
157
157
 
158
- ##Resources
158
+ ## Resources
159
159
 
160
160
  * <http://ruby-rdf.github.com/sparql-client/>
161
161
  * <http://github.com/ruby-rdf/sparql-client>
162
162
  * <http://rubygems.org/gems/sparql-client>
163
- * <http://rubyforge.org/projects/sparql/>
164
163
  * <http://raa.ruby-lang.org/project/sparql-client/>
165
164
  * <http://www.ohloh.net/p/rdf>
166
165
 
167
- ##License
166
+ ## License
168
167
 
169
168
  This is free and unencumbered public domain software. For more information,
170
169
  see <http://unlicense.org/> or the accompanying {file:UNLICENSE} file.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.1.0
1
+ 2.2.1
@@ -157,7 +157,7 @@ module SPARQL
157
157
  # })
158
158
  #
159
159
  # @example Inserting data sourced from a file or URL
160
- # data = RDF::Graph.load("http://rdf.rubyforge.org/doap.nt")
160
+ # data = RDF::Graph.load("https://raw.githubusercontent.com/ruby-rdf/rdf/develop/etc/doap.nt")
161
161
  # client.insert_data(data)
162
162
  #
163
163
  # @example Inserting data into a named graph
@@ -178,7 +178,7 @@ module SPARQL
178
178
  # This requires that the endpoint support SPARQL 1.1 Update.
179
179
  #
180
180
  # @example Deleting data sourced from a file or URL
181
- # data = RDF::Graph.load("http://rdf.rubyforge.org/doap.nt")
181
+ # data = RDF::Graph.load("https://raw.githubusercontent.com/ruby-rdf/rdf/develop/etc/doap.nt")
182
182
  # client.delete_data(data)
183
183
  #
184
184
  # @example Deleting data from a named graph
@@ -609,11 +609,15 @@ module SPARQL
609
609
  # @private
610
610
  def self.serialize_patterns(patterns, use_vars = false)
611
611
  patterns.map do |pattern|
612
- serialized_pattern = RDF::Statement.from(pattern).to_triple.each_with_index.map do |v, i|
613
- if i == 1
614
- SPARQL::Client.serialize_predicate(v)
615
- else
616
- SPARQL::Client.serialize_value(v, use_vars)
612
+ serialized_pattern = case pattern
613
+ when SPARQL::Client::QueryElement then [pattern.to_s]
614
+ else
615
+ RDF::Statement.from(pattern).to_triple.each_with_index.map do |v, i|
616
+ if i == 1
617
+ SPARQL::Client.serialize_predicate(v)
618
+ else
619
+ SPARQL::Client.serialize_value(v, use_vars)
620
+ end
617
621
  end
618
622
  end
619
623
  serialized_pattern.join(' ') + ' .'
@@ -654,7 +658,11 @@ module SPARQL
654
658
  value = ENV['https_proxy']
655
659
  proxy_url = URI.parse(value) unless value.nil? || value.empty?
656
660
  end
657
- klass = Net::HTTP::Persistent.new(self.class.to_s, proxy_url)
661
+ klass = if Net::HTTP::Persistent::VERSION >= '3.0'
662
+ Net::HTTP::Persistent.new(name: self.class.to_s, proxy: proxy_url)
663
+ else
664
+ Net::HTTP::Persistent.new(self.class.to_s, proxy_url)
665
+ end
658
666
  klass.keep_alive = @options[:keep_alive] || 120
659
667
  klass.read_timeout = @options[:read_timeout] || 60
660
668
  klass
@@ -748,5 +756,18 @@ module SPARQL
748
756
  end
749
757
  request
750
758
  end
759
+
760
+ # A query element can be used as a component of a query. It may be initialized with a string, which is wrapped in an appropriate container depending on the type of QueryElement. Implements {#to_s} to property serialize when generating a SPARQL query.
761
+ class QueryElement
762
+ attr_reader :elements
763
+
764
+ def initialize(*args)
765
+ @elements = args
766
+ end
767
+
768
+ def to_s
769
+ raise NotImplemented
770
+ end
771
+ end
751
772
  end # Client
752
773
  end # SPARQL
@@ -42,6 +42,12 @@ module SPARQL; class Client
42
42
  # @example SELECT * WHERE { ?s ?p ?o . }
43
43
  # Query.select.where([:s, :p, :o])
44
44
  #
45
+ # @example SELECT ?s WHERE {?s ?p ?o .}
46
+ # Query.select(:s).where([:s, :p, :o])
47
+ #
48
+ # @example SELECT COUNT(?uri as ?c) WHERE {?uri a owl:Class}
49
+ # Query.select(count: {uri: :c}).where([:uri, RDF.type, RDF::OWL.Class])
50
+ #
45
51
  # @param [Array<Symbol>] variables
46
52
  # @return [Query]
47
53
  #
@@ -98,6 +104,10 @@ module SPARQL; class Client
98
104
  # @overload self.construct(*variables, options)
99
105
  # @param [Symbol, #to_s] form
100
106
  # @param [Hash{Symbol => Object}] options (see {Client#initialize})
107
+ # @option options [Hash{Symbol => Symbol}] :count
108
+ # Contents are symbols relating a variable described within the query,
109
+ # to the projected variable.
110
+ #
101
111
  # @yield [query]
102
112
  # @yieldparam [Query]
103
113
  def initialize(form = :ask, options = {}, &block)
@@ -121,6 +131,12 @@ module SPARQL; class Client
121
131
  # @example SELECT * WHERE { ?s ?p ?o . }
122
132
  # query.select.where([:s, :p, :o])
123
133
  #
134
+ # @example SELECT ?s WHERE {?s ?p ?o .}
135
+ # query.select(:s).where([:s, :p, :o])
136
+ #
137
+ # @example SELECT COUNT(?uri as ?c) WHERE {?uri a owl:Class}
138
+ # query.select(count: {uri: :c}).where([:uri, RDF.type, RDF::OWL.Class])
139
+ #
124
140
  # @param [Array<Symbol>] variables
125
141
  # @return [Query]
126
142
  # @see http://www.w3.org/TR/sparql11-query/#select
@@ -172,19 +188,55 @@ module SPARQL; class Client
172
188
  # query.select.where([:s, :p, :o])
173
189
  # query.select.whether([:s, :p, :o])
174
190
  #
191
+ # @example SELECT * WHERE { { SELECT * WHERE { ?s ?p ?o . } } . ?s ?p ?o . }
192
+ # subquery = query.select.where([:s, :p, :o])
193
+ # query.select.where([:s, :p, :o], subquery)
194
+ #
195
+ # @example SELECT * WHERE { { SELECT * WHERE { ?s ?p ?o . } } . ?s ?p ?o . }
196
+ # query.select.where([:s, :p, :o]) do |q|
197
+ # q.select.where([:s, :p, :o])
198
+ # end
199
+ #
200
+ # Block form can be used for chaining calls in addition to creating sub-select queries.
201
+ #
202
+ # @example SELECT * WHERE { ?s ?p ?o . } ORDER BY ?o
203
+ # query.select.where([:s, :p, :o]) do
204
+ # order(:o)
205
+ # end
206
+ #
175
207
  # @param [Array<RDF::Query::Pattern, Array>] patterns_queries
176
208
  # splat of zero or more patterns followed by zero or more queries.
209
+ # @yield [query]
210
+ # Yield form with or without argument; without an argument, evaluates within the query.
211
+ # @yieldparam [SPARQL::Client::Query] query Actually a delegator to query. Methods other than `#select` are evaluated against `self`. For `#select`, a new Query is created, and the result added as a subquery.
177
212
  # @return [Query]
178
213
  # @see http://www.w3.org/TR/sparql11-query/#GraphPattern
179
- def where(*patterns_queries)
214
+ def where(*patterns_queries, &block)
180
215
  subqueries, patterns = patterns_queries.partition {|pq| pq.is_a? SPARQL::Client::Query}
181
216
  @patterns += build_patterns(patterns)
182
217
  @subqueries += subqueries
218
+
219
+ if block_given?
220
+ decorated_query = WhereDecorator.new(self)
221
+ case block.arity
222
+ when 1 then block.call(decorated_query)
223
+ else decorated_query.instance_eval(&block)
224
+ end
225
+ end
183
226
  self
184
227
  end
185
228
 
186
229
  alias_method :whether, :where
187
230
 
231
+ # @private
232
+ class WhereDecorator < SimpleDelegator
233
+ def select(*variables)
234
+ query = SPARQL::Client::Query.select(*variables)
235
+ __getobj__.instance_variable_get(:@subqueries) << query
236
+ query
237
+ end
238
+ end
239
+
188
240
  ##
189
241
  # @example SELECT * WHERE { ?s ?p ?o . } ORDER BY ?o
190
242
  # query.select.where([:s, :p, :o]).order(:o)
@@ -338,10 +390,141 @@ module SPARQL; class Client
338
390
  # query.select.where([:s, :p, :o]).
339
391
  # optional([:s, RDF.type, :o], [:s, RDF::Vocab::DC.abstract, :o])
340
392
  #
393
+ # The block form can be used for adding filters:
394
+ #
395
+ # @example ASK WHERE { ?s ?p ?o . OPTIONAL { ?s ?p ?o . FILTER(regex(?s, 'Abiline, Texas'))} }
396
+ # query.ask.where([:s, :p, :o]).optional([:s, :p, :o]) do
397
+ # filter("regex(?s, 'Abiline, Texas')")
398
+ # end
399
+ #
400
+ # @param [Array<RDF::Query::Pattern, Array>] patterns
401
+ # splat of zero or more patterns followed by zero or more queries.
402
+ # @yield [query]
403
+ # Yield form with or without argument; without an argument, evaluates within the query.
404
+ # @yieldparam [SPARQL::Client::Query] query used for creating filters on the optional patterns.
341
405
  # @return [Query]
342
406
  # @see http://www.w3.org/TR/sparql11-query/#optionals
343
- def optional(*patterns)
407
+ def optional(*patterns, &block)
344
408
  (options[:optionals] ||= []) << build_patterns(patterns)
409
+
410
+ if block_given?
411
+ # Steal options[:filters]
412
+ query_filters = options[:filters]
413
+ options[:filters] = []
414
+ case block.arity
415
+ when 1 then block.call(self)
416
+ else instance_eval(&block)
417
+ end
418
+ options[:optionals].last.concat(options[:filters])
419
+ options[:filters] = query_filters
420
+ end
421
+
422
+ self
423
+ end
424
+
425
+ ##
426
+ # @example SELECT * WHERE \{ ?book dc:title ?title \} UNION \{ ?book dc11:title ?title \}
427
+ # query.select.where([:book, RDF::Vocab::DC.title, :title]).
428
+ # union([:book, RDF::Vocab::DC11.title, :title])
429
+ #
430
+ # @example SELECT * WHERE \{ ?book dc:title ?title \} UNION \{ ?book dc11:title ?title . FILTER(langmatches(lang(?title), 'EN'))\}
431
+ # query1 = SPARQL::Client::Query.select.
432
+ # where([:book, RDF::Vocab::DC11.title, :title]).
433
+ # filter("langmatches(?title, 'en')")
434
+ # query.select.where([:book, RDF::Vocab::DC.title, :title]).union(query1)
435
+ #
436
+ # The block form can be used for more complicated queries, using the `select` form (note, use either block or argument forms, not both):
437
+ #
438
+ # @example SELECT * WHERE \{ ?book dc:title ?title \} UNION \{ ?book dc11:title ?title . FILTER(langmatches(lang(?title), 'EN'))\}
439
+ # query1 = SPARQL::Client::Query.select.where([:book, RDF::Vocab::DC11.title, :title]).filter("langmatches(?title, 'en')")
440
+ # query.select.where([:book, RDF::Vocab::DC.title, :title]).union do |q|
441
+ # q.select.
442
+ # where([:book, RDF::Vocab::DC11.title, :title]).
443
+ # filter("langmatches(?title, 'en')")
444
+ # end
445
+ #
446
+ # @param [Array<RDF::Query::Pattern, Array>] patterns
447
+ # splat of zero or more patterns followed by zero or more queries.
448
+ # @yield [query]
449
+ # Yield form with or without argument; without an argument, evaluates within the query.
450
+ # @yieldparam [SPARQL::Client::Query] query used for adding select clauses.
451
+ # @return [Query]
452
+ # @see http://www.w3.org/TR/sparql11-query/#optionals
453
+ def union(*patterns, &block)
454
+ options[:unions] ||= []
455
+
456
+ if block_given?
457
+ raise ArgumentError, "#union requires either arguments or a block, not both." unless patterns.empty?
458
+ # Evaluate calls in a new query instance
459
+ query = self.class.select
460
+ case block.arity
461
+ when 1 then block.call(query)
462
+ else query.instance_eval(&block)
463
+ end
464
+ options[:unions] << query
465
+ elsif patterns.all? {|p| p.is_a?(SPARQL::Client::Query)}
466
+ # With argument form, all must be patterns or queries
467
+ options[:unions] += patterns
468
+ elsif patterns.all? {|p| p.is_a?(Array)}
469
+ # With argument form, all must be patterns, or queries
470
+ options[:unions] << self.class.select.where(*patterns)
471
+ else
472
+ raise ArgumentError, "#union arguments are triple patters or queries, not both."
473
+ end
474
+
475
+ self
476
+ end
477
+
478
+ ##
479
+ # @example SELECT * WHERE \{ ?book dc:title ?title . MINUS \{ ?book dc11:title ?title \} \}
480
+ # query.select.where([:book, RDF::Vocab::DC.title, :title]).
481
+ # minus([:book, RDF::Vocab::DC11.title, :title])
482
+ #
483
+ # @example SELECT * WHERE \{ ?book dc:title ?title MINUS \{ ?book dc11:title ?title . FILTER(langmatches(lang(?title), 'EN')) \} \}
484
+ # query1 = SPARQL::Client::Query.select.
485
+ # where([:book, RDF::Vocab::DC11.title, :title]).
486
+ # filter("langmatches(?title, 'en')")
487
+ # query.select.where([:book, RDF::Vocab::DC.title, :title]).minus(query1)
488
+ #
489
+ # The block form can be used for more complicated queries, using the `select` form (note, use either block or argument forms, not both):
490
+ #
491
+ # @example SELECT * WHERE \{ ?book dc:title ?title MINUS \{ ?book dc11:title ?title . FILTER(langmatches(lang(?title), 'EN'))\} \}
492
+ # query1 = SPARQL::Client::Query.select.where([:book, RDF::Vocab::DC11.title, :title]).filter("langmatches(?title, 'en')")
493
+ # query.select.where([:book, RDF::Vocab::DC.title, :title]).minus do |q|
494
+ # q.select.
495
+ # where([:book, RDF::Vocab::DC11.title, :title]).
496
+ # filter("langmatches(?title, 'en')")
497
+ # end
498
+ #
499
+ # @param [Array<RDF::Query::Pattern, Array>] patterns
500
+ # splat of zero or more patterns followed by zero or more queries.
501
+ # @yield [query]
502
+ # Yield form with or without argument; without an argument, evaluates within the query.
503
+ # @yieldparam [SPARQL::Client::Query] query used for adding select clauses.
504
+ # @return [Query]
505
+ # @see http://www.w3.org/TR/sparql11-query/#optionals
506
+ def minus(*patterns, &block)
507
+ options[:minuses] ||= []
508
+
509
+ if block_given?
510
+ raise ArgumentError, "#minus requires either arguments or a block, not both." unless patterns.empty?
511
+ # Evaluate calls in a new query instance
512
+ query = self.class.select
513
+ case block.arity
514
+ when 1 then block.call(query)
515
+ else query.instance_eval(&block)
516
+ end
517
+ options[:minuses] << query
518
+ elsif patterns.all? {|p| p.is_a?(SPARQL::Client::Query)}
519
+ # With argument form, all must be patterns or queries
520
+ options[:minuses] += patterns
521
+ elsif patterns.all? {|p| p.is_a?(Array)}
522
+ # With argument form, all must be patterns, or queries
523
+ options[:minuses] << self.class.select.where(*patterns)
524
+ else
525
+ raise ArgumentError, "#minus arguments are triple patters or queries, not both."
526
+ end
527
+
345
528
  self
346
529
  end
347
530
 
@@ -352,15 +535,17 @@ module SPARQL; class Client
352
535
  end
353
536
 
354
537
  ##
355
- # @private
538
+ # @private
356
539
  def build_patterns(patterns)
357
540
  patterns.map {|pattern| RDF::Query::Pattern.from(pattern)}
358
541
  end
359
542
 
360
543
  ##
361
- # @private
544
+ # @example ASK WHERE { ?s ?p ?o . FILTER(regex(?s, 'Abiline, Texas')) }
545
+ # query.ask.where([:s, :p, :o]).filter("regex(?s, 'Abiline, Texas')")
546
+ # @return [Query]
362
547
  def filter(string)
363
- ((options[:filters] ||= []) << string) if string and not string.empty?
548
+ ((options[:filters] ||= []) << Filter.new(string)) if string and not string.empty?
364
549
  self
365
550
  end
366
551
 
@@ -445,33 +630,11 @@ module SPARQL; class Client
445
630
  buffer << "FROM #{SPARQL::Client.serialize_value(options[:from])}" if options[:from]
446
631
 
447
632
  unless patterns.empty? && form == :describe
448
- buffer << 'WHERE {'
449
-
450
- if options[:graph]
451
- buffer << 'GRAPH ' + SPARQL::Client.serialize_value(options[:graph])
452
- buffer << '{'
453
- end
454
-
455
- @subqueries.each do |sq|
456
- buffer << "{ #{sq.to_s} } ."
457
- end
458
-
459
- buffer += SPARQL::Client.serialize_patterns(patterns)
460
- if options[:optionals]
461
- options[:optionals].each do |patterns|
462
- buffer << 'OPTIONAL {'
463
- buffer += SPARQL::Client.serialize_patterns(patterns)
464
- buffer << '}'
465
- end
466
- end
467
- if options[:filters]
468
- buffer += options[:filters].map { |filter| "FILTER(#{filter})" }
469
- end
470
- if options[:graph]
471
- buffer << '}' # GRAPH
472
- end
633
+ buffer += self.to_s_ggp.unshift('WHERE')
634
+ end
473
635
 
474
- buffer << '}' # WHERE
636
+ options.fetch(:unions, []).each do |query|
637
+ buffer += query.to_s_ggp.unshift('UNION')
475
638
  end
476
639
 
477
640
  if options[:group_by]
@@ -524,6 +687,43 @@ module SPARQL; class Client
524
687
  buffer.join(' ')
525
688
  end
526
689
 
690
+ # Serialize a Group Graph Pattern
691
+ # @private
692
+ def to_s_ggp
693
+ buffer = ["{"]
694
+
695
+ if options[:graph]
696
+ buffer << 'GRAPH ' + SPARQL::Client.serialize_value(options[:graph])
697
+ buffer << '{'
698
+ end
699
+
700
+ @subqueries.each do |sq|
701
+ buffer << "{ #{sq.to_s} } ."
702
+ end
703
+
704
+ buffer += SPARQL::Client.serialize_patterns(patterns)
705
+ if options[:optionals]
706
+ options[:optionals].each do |patterns|
707
+ buffer << 'OPTIONAL {'
708
+ buffer += SPARQL::Client.serialize_patterns(patterns)
709
+ buffer << '}'
710
+ end
711
+ end
712
+ if options[:filters]
713
+ buffer += options[:filters].map(&:to_s)
714
+ end
715
+ if options[:graph]
716
+ buffer << '}' # GRAPH
717
+ end
718
+
719
+ options.fetch(:minuses, []).each do |query|
720
+ buffer += query.to_s_ggp.unshift('MINUS')
721
+ end
722
+
723
+ buffer << '}'
724
+ buffer
725
+ end
726
+
527
727
  ##
528
728
  # Outputs a developer-friendly representation of this query to `stderr`.
529
729
  #
@@ -540,5 +740,16 @@ module SPARQL; class Client
540
740
  def inspect
541
741
  sprintf("#<%s:%#0x(%s)>", self.class.name, __id__, to_s)
542
742
  end
743
+
744
+ # Allow Filters to be
745
+ class Filter < SPARQL::Client::QueryElement
746
+ def initialize(*args)
747
+ super
748
+ end
749
+
750
+ def to_s
751
+ "FILTER(#{elements.join(' ')})"
752
+ end
753
+ end
543
754
  end
544
755
  end; end
@@ -38,6 +38,30 @@ module SPARQL; class Client
38
38
  client.construct([:s, :p, :o]).where([:s, :p, :o]).each_statement(&block)
39
39
  end
40
40
 
41
+ ##
42
+ # Iterates the given block for each RDF statement.
43
+ #
44
+ # If no block was given, returns an enumerator.
45
+ #
46
+ # The order in which statements are yielded is undefined.
47
+ #
48
+ # @overload each_statement
49
+ # @yield [statement]
50
+ # each statement
51
+ # @yieldparam [RDF::Statement] statement
52
+ # @yieldreturn [void] ignored
53
+ # @return [void]
54
+ #
55
+ # @overload each_statement
56
+ # @return [Enumerator<RDF::Statement>]
57
+ def each_statement(&block)
58
+ if block_given?
59
+ # Invoke {#each} in the containing class:
60
+ each(&block)
61
+ end
62
+ enum_statement
63
+ end
64
+
41
65
  ##
42
66
  # @private
43
67
  # @see RDF::Enumerable#supports?
@@ -48,6 +72,7 @@ module SPARQL; class Client
48
72
  when :graph_name then false
49
73
  when :inference then false # forward-chaining inference
50
74
  when :validity then false
75
+ when :literal_equality then true
51
76
  else false
52
77
  end
53
78
  end
@@ -151,7 +176,7 @@ module SPARQL; class Client
151
176
  # @see RDF::Repository#count?
152
177
  def count
153
178
  begin
154
- binding = client.query("SELECT (COUNT(*) AS ?count) WHERE { ?s ?p ?o }").first.to_hash
179
+ binding = client.query("SELECT (COUNT(*) AS ?count) WHERE { ?s ?p ?o }").first.to_h
155
180
  binding[:count].value.to_i rescue 0
156
181
  rescue SPARQL::Client::MalformedQuery => e
157
182
  # SPARQL 1.0 does not include support for aggregate functions:
@@ -58,7 +58,7 @@ class SPARQL::Client
58
58
  end
59
59
 
60
60
  ##
61
- # Load statements into the graph
61
+ # Clear the graph
62
62
  #
63
63
  # @example CLEAR GRAPH <http://example.org/data.rdf>
64
64
  # clear.graph(RDF::URI(http://example.org/data.rdf))
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: 2.1.0
4
+ version: 2.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arto Bendiken
@@ -10,78 +10,102 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2016-09-06 00:00:00.000000000 Z
13
+ date: 2017-12-13 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rdf
17
17
  requirement: !ruby/object:Gem::Requirement
18
18
  requirements:
19
- - - "~>"
19
+ - - ">="
20
+ - !ruby/object:Gem::Version
21
+ version: '2.2'
22
+ - - "<"
20
23
  - !ruby/object:Gem::Version
21
- version: '2.0'
24
+ version: '4.0'
22
25
  type: :runtime
23
26
  prerelease: false
24
27
  version_requirements: !ruby/object:Gem::Requirement
25
28
  requirements:
26
- - - "~>"
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: '2.2'
32
+ - - "<"
27
33
  - !ruby/object:Gem::Version
28
- version: '2.0'
34
+ version: '4.0'
29
35
  - !ruby/object:Gem::Dependency
30
36
  name: net-http-persistent
31
37
  requirement: !ruby/object:Gem::Requirement
32
38
  requirements:
33
- - - "~>"
39
+ - - ">="
34
40
  - !ruby/object:Gem::Version
35
41
  version: '2.9'
42
+ - - "<"
43
+ - !ruby/object:Gem::Version
44
+ version: '4'
36
45
  type: :runtime
37
46
  prerelease: false
38
47
  version_requirements: !ruby/object:Gem::Requirement
39
48
  requirements:
40
- - - "~>"
49
+ - - ">="
41
50
  - !ruby/object:Gem::Version
42
51
  version: '2.9'
52
+ - - "<"
53
+ - !ruby/object:Gem::Version
54
+ version: '4'
43
55
  - !ruby/object:Gem::Dependency
44
56
  name: sparql
45
57
  requirement: !ruby/object:Gem::Requirement
46
58
  requirements:
47
- - - "~>"
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '2.2'
62
+ - - "<"
48
63
  - !ruby/object:Gem::Version
49
- version: '2.0'
64
+ version: '4.0'
50
65
  type: :development
51
66
  prerelease: false
52
67
  version_requirements: !ruby/object:Gem::Requirement
53
68
  requirements:
54
- - - "~>"
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '2.2'
72
+ - - "<"
55
73
  - !ruby/object:Gem::Version
56
- version: '2.0'
74
+ version: '4.0'
57
75
  - !ruby/object:Gem::Dependency
58
76
  name: rdf-spec
59
77
  requirement: !ruby/object:Gem::Requirement
60
78
  requirements:
61
- - - "~>"
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '2.2'
82
+ - - "<"
62
83
  - !ruby/object:Gem::Version
63
- version: '2.0'
84
+ version: '4.0'
64
85
  type: :development
65
86
  prerelease: false
66
87
  version_requirements: !ruby/object:Gem::Requirement
67
88
  requirements:
68
- - - "~>"
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '2.2'
92
+ - - "<"
69
93
  - !ruby/object:Gem::Version
70
- version: '2.0'
94
+ version: '4.0'
71
95
  - !ruby/object:Gem::Dependency
72
96
  name: rspec
73
97
  requirement: !ruby/object:Gem::Requirement
74
98
  requirements:
75
99
  - - "~>"
76
100
  - !ruby/object:Gem::Version
77
- version: '3.4'
101
+ version: '3.7'
78
102
  type: :development
79
103
  prerelease: false
80
104
  version_requirements: !ruby/object:Gem::Requirement
81
105
  requirements:
82
106
  - - "~>"
83
107
  - !ruby/object:Gem::Version
84
- version: '3.4'
108
+ version: '3.7'
85
109
  - !ruby/object:Gem::Dependency
86
110
  name: rspec-its
87
111
  requirement: !ruby/object:Gem::Requirement
@@ -102,28 +126,28 @@ dependencies:
102
126
  requirements:
103
127
  - - "~>"
104
128
  - !ruby/object:Gem::Version
105
- version: '1.15'
129
+ version: '3.0'
106
130
  type: :development
107
131
  prerelease: false
108
132
  version_requirements: !ruby/object:Gem::Requirement
109
133
  requirements:
110
134
  - - "~>"
111
135
  - !ruby/object:Gem::Version
112
- version: '1.15'
136
+ version: '3.0'
113
137
  - !ruby/object:Gem::Dependency
114
138
  name: yard
115
139
  requirement: !ruby/object:Gem::Requirement
116
140
  requirements:
117
141
  - - "~>"
118
142
  - !ruby/object:Gem::Version
119
- version: '0.8'
143
+ version: '0.9'
120
144
  type: :development
121
145
  prerelease: false
122
146
  version_requirements: !ruby/object:Gem::Requirement
123
147
  requirements:
124
148
  - - "~>"
125
149
  - !ruby/object:Gem::Version
126
- version: '0.8'
150
+ version: '0.9'
127
151
  description: |-
128
152
  Executes SPARQL queries and updates against a remote SPARQL 1.0 or 1.1 endpoint,
129
153
  or against a local repository. Generates SPARQL queries using a simple DSL.
@@ -163,8 +187,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
163
187
  - !ruby/object:Gem::Version
164
188
  version: '0'
165
189
  requirements: []
166
- rubyforge_project: sparql-client
167
- rubygems_version: 2.5.1
190
+ rubyforge_project:
191
+ rubygems_version: 2.6.14
168
192
  signing_key:
169
193
  specification_version: 4
170
194
  summary: SPARQL client for RDF.rb.