sparql-client 2.1.0 → 2.2.1

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
  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.