sparql-client 0.3.2 → 0.3.3

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.
data/AUTHORS CHANGED
@@ -1,2 +1,3 @@
1
- * Arto Bendiken <arto.bendiken@gmail.com>
1
+ * Arto Bendiken <arto@bendiken.net>
2
2
  * Ben Lavender <blavender@gmail.com>
3
+ * Gregg Kellogg <gregg@greggkellogg.net>
data/CREDITS CHANGED
@@ -5,5 +5,5 @@
5
5
  * Fumihiro Kato <fumi@fumi.me>
6
6
  * David Nielsen <david@graveyard.dk>
7
7
  * Thamaraiselvan Poomalai <p.thamarai@gmail.com>
8
- * Gregg Kellogg <gregg@greggkellogg.net>
9
8
  * Michael Sokol <mikaa123@gmail.com>
9
+ * Yves Raimond <yves.raimond@bbc.co.uk>
data/README CHANGED
@@ -7,11 +7,12 @@ This is a [Ruby][] implementation of a [SPARQL][] client for [RDF.rb][].
7
7
 
8
8
  ##Features
9
9
 
10
- * Executes queries against any SPARQL 1.0-compatible endpoints over HTTP.
10
+ * Executes queries against any SPARQL 1.0-compatible endpoint over HTTP.
11
11
  * Provides a query builder [DSL][] for `ASK`, `SELECT`, `DESCRIBE` and
12
12
  `CONSTRUCT` queries.
13
+ * Includes preliminary support for some SPARQL 1.1 Update operations.
13
14
  * Supports tuple result sets in both XML and JSON formats, with JSON being
14
- the preferred default for content negotiation purposes.
15
+ the preferred default for content-negotiation purposes.
15
16
  * Supports graph results in any RDF serialization format understood by RDF.rb.
16
17
  * Returns results using the [RDF.rb object model][RDF.rb model].
17
18
  * Supports accessing endpoints as read-only [`RDF::Repository`][RDF::Repository]
@@ -56,8 +57,6 @@ This is a [Ruby][] implementation of a [SPARQL][] client for [RDF.rb][].
56
57
 
57
58
  ##Documentation
58
59
 
59
- <http://sparql.rubyforge.org/client/>
60
-
61
60
  * {SPARQL::Client}
62
61
  * {SPARQL::Client::Query}
63
62
  * {SPARQL::Client::Repository}
@@ -65,8 +64,9 @@ This is a [Ruby][] implementation of a [SPARQL][] client for [RDF.rb][].
65
64
  ##Dependencies
66
65
 
67
66
  * [Ruby](http://ruby-lang.org/) (>= 1.8.7) or (>= 1.8.1 with [Backports][])
68
- * [RDF.rb](http://rubygems.org/gems/rdf) (>= 0.3.0)
69
- * [JSON](http://rubygems.org/gems/json_pure) (>= 1.4.2)
67
+ * [RDF.rb](http://rubygems.org/gems/rdf) (>= 0.3.5)
68
+ * [Net::HTTP::Persistent](http://rubygems.org/gems/net-http-persistent) (>= 1.4.1)
69
+ * [JSON](http://rubygems.org/gems/json_pure) (>= 1.4.6)
70
70
 
71
71
  ##Installation
72
72
 
@@ -79,12 +79,12 @@ To install the latest official release of the `SPARQL::Client` gem, do:
79
79
 
80
80
  To get a local working copy of the development repository, do:
81
81
 
82
- % git clone git://github.com/bendiken/sparql-client.git
82
+ % git clone git://github.com/ruby-rdf/sparql-client.git
83
83
 
84
84
  Alternatively, download the latest development version as a tarball as
85
85
  follows:
86
86
 
87
- % wget http://github.com/bendiken/sparql-client/tarball/master
87
+ % wget http://github.com/ruby-rdf/sparql-client/tarball/master
88
88
 
89
89
  ##Mailing List
90
90
 
@@ -94,6 +94,7 @@ follows:
94
94
 
95
95
  * [Arto Bendiken](http://github.com/bendiken) - <http://ar.to/>
96
96
  * [Ben Lavender](http://github.com/bhuga) - <http://bhuga.net/>
97
+ * [Gregg Kellogg](http://github.com/gkellogg) - <http://kellogg-assoc.com/>
97
98
 
98
99
  ##Contributors
99
100
 
@@ -104,7 +105,6 @@ follows:
104
105
  * [Fumihiro Kato](http://github.com/fumi) - <http://fumi.me/>
105
106
  * [David Nielsen](http://github.com/drankard) - <http://github.com/drankard>
106
107
  * [Thamaraiselvan Poomalai](http://github.com/selvan) - <http://softonaut.blogspot.com/>
107
- * [Gregg Kellogg](http://github.com/gkellogg) - <http://kellogg-assoc.com/>
108
108
  * [Michael Sokol](http://github.com/mikaa123) - <http://sokolmichael.com/>
109
109
  * [Yves Raimond](http://github.com/moustaki) - <http://moustaki.org/>
110
110
 
@@ -124,8 +124,8 @@ follows:
124
124
 
125
125
  ##Resources
126
126
 
127
- * <http://sparql.rubyforge.org/client/>
128
- * <http://github.com/bendiken/sparql-client>
127
+ * <http://ruby-rdf.github.com/sparql-client/>
128
+ * <http://github.com/ruby-rdf/sparql-client>
129
129
  * <http://rubygems.org/gems/sparql-client>
130
130
  * <http://rubyforge.org/projects/sparql/>
131
131
  * <http://raa.ruby-lang.org/project/sparql-client/>
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.2
1
+ 0.3.3
data/lib/sparql/client.rb CHANGED
@@ -1,13 +1,13 @@
1
- require 'net/http/persistent'
2
- require 'rdf' # @see http://rubygems.org/gems/rdf
3
- require 'rdf/ntriples'
1
+ require 'net/http/persistent' # @see http://rubygems.org/gems/net-http-persistent
2
+ require 'rdf' # @see http://rubygems.org/gems/rdf
3
+ require 'rdf/ntriples' # @see http://rubygems.org/gems/rdf
4
4
 
5
5
  module SPARQL
6
6
  ##
7
7
  # A SPARQL client for RDF.rb.
8
8
  #
9
- # @see http://www.w3.org/TR/rdf-sparql-protocol/
10
- # @see http://www.w3.org/TR/rdf-sparql-json-res/
9
+ # @see http://www.w3.org/TR/sparql11-query/
10
+ # @see http://www.w3.org/TR/sparql11-results-json/
11
11
  class Client
12
12
  autoload :Query, 'sparql/client/query'
13
13
  autoload :Repository, 'sparql/client/repository'
@@ -17,25 +17,33 @@ module SPARQL
17
17
  class MalformedQuery < ClientError; end
18
18
  class ServerError < StandardError; end
19
19
 
20
- RESULT_BOOL = 'text/boolean'.freeze # Sesame-specific
21
20
  RESULT_JSON = 'application/sparql-results+json'.freeze
22
21
  RESULT_XML = 'application/sparql-results+xml'.freeze
22
+ RESULT_BOOL = 'text/boolean'.freeze # Sesame-specific
23
+ RESULT_BRTR = 'application/x-binary-rdf-results-table'.freeze # Sesame-specific
23
24
  ACCEPT_JSON = {'Accept' => RESULT_JSON}.freeze
24
25
  ACCEPT_XML = {'Accept' => RESULT_XML}.freeze
26
+ ACCEPT_BRTR = {'Accept' => RESULT_BRTR}.freeze
25
27
 
28
+ # @return [RDF::URI]
26
29
  attr_reader :url
30
+
31
+ # @return [Hash{String => String}]
32
+ attr_reader :headers
33
+
34
+ # @return [Hash{Symbol => Object}]
27
35
  attr_reader :options
28
36
 
29
37
  ##
30
38
  # @param [String, #to_s] url
31
39
  # @param [Hash{Symbol => Object}] options
40
+ # @option options [Symbol] :method (:post)
32
41
  # @option options [Hash] :headers
33
42
  def initialize(url, options = {}, &block)
34
- @url, @options = RDF::URI.new(url.to_s), options
35
- #@headers = {'Accept' => "#{RESULT_JSON}, #{RESULT_XML}, text/plain"}
43
+ @url, @options = RDF::URI.new(url.to_s), options.dup
36
44
  @headers = {
37
45
  'Accept' => [RESULT_JSON, RESULT_XML, RDF::Format.content_types.keys.map(&:to_s)].join(', ')
38
- }.merge @options[:headers] || {}
46
+ }.merge(@options.delete(:headers) || {})
39
47
  @http = http_klass(@url.scheme)
40
48
 
41
49
  if block_given?
@@ -81,6 +89,128 @@ module SPARQL
81
89
  call_query_method(:construct, *args)
82
90
  end
83
91
 
92
+ ##
93
+ # Executes an `INSERT DATA` operation.
94
+ #
95
+ # This requires that the endpoint support SPARQL 1.1 Update.
96
+ #
97
+ # Note that for inserting non-trivial amounts of data, you probably
98
+ # ought to consider using the RDF store's native bulk-loading facilities
99
+ # or APIs, as `INSERT DATA` operations entail comparably higher
100
+ # parsing overhead.
101
+ #
102
+ # @example Inserting data constructed ad-hoc
103
+ # client.insert_data(RDF::Graph.new { |graph|
104
+ # graph << [:jhacker, RDF::FOAF.name, "J. Random Hacker"]
105
+ # })
106
+ #
107
+ # @example Inserting data sourced from a file or URL
108
+ # data = RDF::Graph.load("http://rdf.rubyforge.org/doap.nt")
109
+ # client.insert_data(data)
110
+ #
111
+ # @example Inserting data into a named graph
112
+ # client.insert_data(data, :graph => "http://example.org/")
113
+ #
114
+ # @param [RDF::Graph] data
115
+ # @param [Hash{Symbol => Object}] options
116
+ # @option options [RDF::URI, String] :graph
117
+ # @return [void] `self`
118
+ # @see http://www.w3.org/TR/sparql11-update/#insertData
119
+ def insert_data(data, options = {})
120
+ raise ArgumentError, "no data given" if data.empty?
121
+ query_text = 'INSERT DATA {'
122
+ query_text += ' GRAPH ' + self.class.serialize_uri(options[:graph]) + ' {' if options[:graph]
123
+ query_text += "\n"
124
+ query_text += RDF::NTriples::Writer.buffer { |writer| writer << data }
125
+ query_text += '}' if options[:graph]
126
+ query_text += "}\n"
127
+ query(query_text)
128
+ self
129
+ end
130
+
131
+ ##
132
+ # Executes a `DELETE DATA` operation.
133
+ #
134
+ # This requires that the endpoint support SPARQL 1.1 Update.
135
+ #
136
+ # @example Deleting data sourced from a file or URL
137
+ # data = RDF::Graph.load("http://rdf.rubyforge.org/doap.nt")
138
+ # client.delete_data(data)
139
+ #
140
+ # @example Deleting data from a named graph
141
+ # client.delete_data(data, :graph => "http://example.org/")
142
+ #
143
+ # @param [RDF::Graph] data
144
+ # @param [Hash{Symbol => Object}] options
145
+ # @option options [RDF::URI, String] :graph
146
+ # @return [void] `self`
147
+ # @see http://www.w3.org/TR/sparql11-update/#deleteData
148
+ def delete_data(data, options = {})
149
+ raise ArgumentError, "no data given" if data.empty?
150
+ query_text = 'DELETE DATA {'
151
+ query_text += ' GRAPH ' + self.class.serialize_uri(options[:graph]) + ' {' if options[:graph]
152
+ query_text += "\n"
153
+ query_text += RDF::NTriples::Writer.buffer { |writer| writer << data }
154
+ query_text += '}' if options[:graph]
155
+ query_text += "}\n"
156
+ query(query_text)
157
+ self
158
+ end
159
+
160
+ ##
161
+ # Executes a `CLEAR GRAPH` operation.
162
+ #
163
+ # This is a convenience wrapper for the {#clear} method.
164
+ #
165
+ # @example `CLEAR GRAPH <http://example.org/>`
166
+ # client.clear_graph("http://example.org/")
167
+ #
168
+ # @param [RDF::URI, String] graph_uri
169
+ # @param [Hash{Symbol => Object}] options
170
+ # @option options [Boolean] :silent
171
+ # @return [void] `self`
172
+ # @see http://www.w3.org/TR/sparql11-update/#clear
173
+ def clear_graph(graph_uri, options = {})
174
+ self.clear(:graph, graph_uri, options)
175
+ end
176
+
177
+ ##
178
+ # Executes a `CLEAR` operation.
179
+ #
180
+ # This requires that the endpoint support SPARQL 1.1 Update.
181
+ #
182
+ # @example `CLEAR GRAPH <http://example.org/>`
183
+ # client.clear(:graph, RDF::URI("http://example.org/"))
184
+ #
185
+ # @example `CLEAR DEFAULT`
186
+ # client.clear(:default)
187
+ #
188
+ # @example `CLEAR NAMED`
189
+ # client.clear(:named)
190
+ #
191
+ # @example `CLEAR ALL`
192
+ # client.clear(:all)
193
+ #
194
+ # @param [Symbol, #to_sym] what
195
+ # @param [Hash{Symbol => Object}] options
196
+ # @option options [Boolean] :silent
197
+ # @return [void] `self`
198
+ # @see http://www.w3.org/TR/sparql11-update/#clear
199
+ def clear(what, *arguments)
200
+ options = arguments.last.is_a?(Hash) ? arguments.pop : {}
201
+ query_text = 'CLEAR '
202
+ query_text += 'SILENT ' if options[:silent]
203
+ case what.to_sym
204
+ when :graph then query_text += 'GRAPH ' + self.class.serialize_uri(arguments.pop)
205
+ when :default then query_text += 'DEFAULT'
206
+ when :named then query_text += 'NAMED'
207
+ when :all then query_text += 'ALL'
208
+ else raise ArgumentError, "invalid CLEAR operation: #{what.inspect}"
209
+ end
210
+ query(query_text)
211
+ self
212
+ end
213
+
84
214
  ##
85
215
  # @private
86
216
  def call_query_method(meth, *args)
@@ -93,7 +223,8 @@ module SPARQL
93
223
  end
94
224
 
95
225
  ##
96
- # A mapping of blank node results for this client
226
+ # Returns a mapping of blank node results for this client.
227
+ #
97
228
  # @private
98
229
  def nodes
99
230
  @nodes ||= {}
@@ -112,7 +243,8 @@ module SPARQL
112
243
  end
113
244
 
114
245
  ##
115
- # Executes a SPARQL query and returns the Net::HTTP::Response of the result.
246
+ # Executes a SPARQL query and returns the Net::HTTP::Response of the
247
+ # result.
116
248
  #
117
249
  # @param [String, #to_s] query
118
250
  # @param [Hash{Symbol => Object}] options
@@ -120,8 +252,9 @@ module SPARQL
120
252
  # @option options [Hash] :headers
121
253
  # @return [String]
122
254
  def response(query, options = {})
123
- @headers['Accept'] = options[:content_type] if options[:content_type]
124
- get(query, options[:headers] || {}) do |response|
255
+ headers = options[:headers] || {}
256
+ headers['Accept'] = options[:content_type] if options[:content_type]
257
+ request(query, headers) do |response|
125
258
  case response
126
259
  when Net::HTTPBadRequest # 400 Bad Request
127
260
  raise MalformedQuery.new(response.body)
@@ -133,7 +266,6 @@ module SPARQL
133
266
  response
134
267
  end
135
268
  end
136
-
137
269
  end
138
270
 
139
271
  ##
@@ -160,7 +292,6 @@ module SPARQL
160
292
  def self.parse_json_bindings(json, nodes = {})
161
293
  require 'json' unless defined?(::JSON)
162
294
  json = JSON.parse(json.to_s) unless json.is_a?(Hash)
163
-
164
295
  case
165
296
  when json['boolean']
166
297
  json['boolean']
@@ -249,6 +380,35 @@ module SPARQL
249
380
  end
250
381
  end
251
382
 
383
+ ##
384
+ # Serializes a URI or URI string into SPARQL syntax.
385
+ #
386
+ # @param [RDF::URI, String] uri
387
+ # @return [String]
388
+ # @private
389
+ def self.serialize_uri(uri)
390
+ case uri
391
+ when String then RDF::NTriples.serialize(RDF::URI(uri))
392
+ when RDF::URI then RDF::NTriples.serialize(uri)
393
+ else raise ArgumentError, "expected the graph URI to be a String or RDF::URI, but got #{uri.inspect}"
394
+ end
395
+ end
396
+
397
+ ##
398
+ # Serializes an `RDF::Value` into SPARQL syntax.
399
+ #
400
+ # @param [RDF::Value] value
401
+ # @return [String]
402
+ # @private
403
+ def self.serialize_value(value)
404
+ # SPARQL queries are UTF-8, but support ASCII-style Unicode escapes, so
405
+ # the N-Triples serializer is fine unless it's a variable:
406
+ case
407
+ when value.variable? then value.to_s
408
+ else RDF::NTriples.serialize(value)
409
+ end
410
+ end
411
+
252
412
  ##
253
413
  # Outputs a developer-friendly representation of this object to `stderr`.
254
414
  #
@@ -268,41 +428,75 @@ module SPARQL
268
428
  protected
269
429
 
270
430
  ##
271
- # Returns an HTTP class or HTTP proxy class based on environment http_proxy & https_proxy settings
431
+ # Returns an HTTP class or HTTP proxy class based on the `http_proxy`
432
+ # and `https_proxy` environment variables.
433
+ #
434
+ # @param [String] scheme
272
435
  # @return [Net::HTTP::Proxy]
273
436
  def http_klass(scheme)
274
- proxy_uri = nil
437
+ proxy_url = nil
275
438
  case scheme
276
- when "http"
277
- proxy_uri = URI.parse(ENV['http_proxy']) unless ENV['http_proxy'].nil?
278
- when "https"
279
- proxy_uri = URI.parse(ENV['https_proxy']) unless ENV['https_proxy'].nil?
439
+ when 'http'
440
+ value = ENV['http_proxy']
441
+ proxy_url = URI.parse(value) unless value.nil? || value.empty?
442
+ when 'https'
443
+ value = ENV['https_proxy']
444
+ proxy_url = URI.parse(value) unless value.nil? || value.empty?
280
445
  end
281
- klass = Net::HTTP::Persistent.new(self.class.to_s, proxy_uri)
282
- klass.keep_alive = 120 # increase to 2 minutes
446
+ klass = Net::HTTP::Persistent.new(self.class.to_s, proxy_url)
447
+ klass.keep_alive = 120 # increase to 2 minutes
283
448
  klass
284
449
  end
285
450
 
286
451
  ##
287
- # Performs an HTTP GET request against the SPARQL endpoint.
452
+ # Performs an HTTP request against the SPARQL endpoint.
288
453
  #
289
454
  # @param [String, #to_s] query
290
455
  # @param [Hash{String => String}] headers
291
456
  # @yield [response]
292
457
  # @yieldparam [Net::HTTPResponse] response
293
458
  # @return [Net::HTTPResponse]
294
- def get(query, headers = {}, &block)
295
- url = self.url.dup
296
- url.query_values = (url.query_values || {}).merge(:query => query.to_s)
459
+ # @see http://www.w3.org/TR/sparql11-protocol/#query-operation
460
+ def request(query, headers = {}, &block)
461
+ method = (self.options[:method] || :post).to_sym
462
+ request = send("make_#{method}_request", query, headers)
297
463
 
298
- request = Net::HTTP::Get.new(url.request_uri, @headers.merge(headers))
299
- request.basic_auth url.user, url.password if url.user && !url.user.empty?
300
- response = @http.request url, request
464
+ request.basic_auth(url.user, url.password) if url.user && !url.user.empty?
465
+
466
+ response = @http.request(url, request)
301
467
  if block_given?
302
- block.call(response)
468
+ block.call(response)
303
469
  else
304
- response
470
+ response
305
471
  end
306
472
  end
473
+
474
+ ##
475
+ # Constructs an HTTP GET request according to the SPARQL Protocol.
476
+ #
477
+ # @param [String, #to_s] query
478
+ # @param [Hash{String => String}] headers
479
+ # @return [Net::HTTPRequest]
480
+ # @see http://www.w3.org/TR/sparql11-protocol/#query-via-get
481
+ def make_get_request(query, headers = {})
482
+ url = self.url.dup
483
+ url.query_values = (url.query_values || {}).merge(:query => query.to_s)
484
+ request = Net::HTTP::Get.new(url.request_uri, self.headers.merge(headers))
485
+ request
486
+ end
487
+
488
+ ##
489
+ # Constructs an HTTP POST request according to the SPARQL Protocol.
490
+ #
491
+ # @param [String, #to_s] query
492
+ # @param [Hash{String => String}] headers
493
+ # @return [Net::HTTPRequest]
494
+ # @see http://www.w3.org/TR/sparql11-protocol/#query-via-post-urlencoded
495
+ def make_post_request(query, headers = {})
496
+ url = self.url
497
+ request = Net::HTTP::Post.new(url.request_uri, self.headers.merge(headers))
498
+ request.set_form_data(:query => query.to_s)
499
+ request
500
+ end
307
501
  end # Client
308
502
  end # SPARQL
@@ -8,7 +8,7 @@ module SPARQL; class Client
8
8
  class Query < RDF::Query
9
9
  ##
10
10
  # @return [Symbol]
11
- # @see http://www.w3.org/TR/rdf-sparql-query/#QueryForms
11
+ # @see http://www.w3.org/TR/sparql11-query/#QueryForms
12
12
  attr_reader :form
13
13
 
14
14
  ##
@@ -24,7 +24,7 @@ module SPARQL; class Client
24
24
  #
25
25
  # @param [Hash{Symbol => Object}] options
26
26
  # @return [Query]
27
- # @see http://www.w3.org/TR/rdf-sparql-query/#ask
27
+ # @see http://www.w3.org/TR/sparql11-query/#ask
28
28
  def self.ask(options = {})
29
29
  self.new(:ask, options)
30
30
  end
@@ -38,7 +38,7 @@ module SPARQL; class Client
38
38
  # @overload self.select(*variables, options)
39
39
  # @param [Array<Symbol>] variables
40
40
  # @return [Query]
41
- # @see http://www.w3.org/TR/rdf-sparql-query/#select
41
+ # @see http://www.w3.org/TR/sparql11-query/#select
42
42
  def self.select(*variables)
43
43
  options = variables.last.is_a?(Hash) ? variables.pop : {}
44
44
  self.new(:select, options).select(*variables)
@@ -53,7 +53,7 @@ module SPARQL; class Client
53
53
  # @overload self.describe(*variables, options)
54
54
  # @param [Array<Symbol, RDF::URI>] variables
55
55
  # @return [Query]
56
- # @see http://www.w3.org/TR/rdf-sparql-query/#describe
56
+ # @see http://www.w3.org/TR/sparql11-query/#describe
57
57
  def self.describe(*variables)
58
58
  options = variables.last.is_a?(Hash) ? variables.pop : {}
59
59
  self.new(:describe, options).describe(*variables)
@@ -69,7 +69,7 @@ module SPARQL; class Client
69
69
  # @param [Array<RDF::Query::Pattern, Array>] patterns
70
70
  # @param [Hash{Symbol => Object}] options
71
71
  # @return [Query]
72
- # @see http://www.w3.org/TR/rdf-sparql-query/#construct
72
+ # @see http://www.w3.org/TR/sparql11-query/#construct
73
73
  def self.construct(*patterns)
74
74
  options = patterns.last.is_a?(Hash) ? patterns.pop : {}
75
75
  self.new(:construct, options).construct(*patterns) # FIXME
@@ -89,7 +89,7 @@ module SPARQL; class Client
89
89
 
90
90
  ##
91
91
  # @return [Query]
92
- # @see http://www.w3.org/TR/rdf-sparql-query/#ask
92
+ # @see http://www.w3.org/TR/sparql11-query/#ask
93
93
  def ask
94
94
  @form = :ask
95
95
  self
@@ -98,7 +98,7 @@ module SPARQL; class Client
98
98
  ##
99
99
  # @param [Array<Symbol>] variables
100
100
  # @return [Query]
101
- # @see http://www.w3.org/TR/rdf-sparql-query/#select
101
+ # @see http://www.w3.org/TR/sparql11-query/#select
102
102
  def select(*variables)
103
103
  @values = variables.map { |var| [var, RDF::Query::Variable.new(var)] }
104
104
  self
@@ -107,7 +107,7 @@ module SPARQL; class Client
107
107
  ##
108
108
  # @param [Array<Symbol>] variables
109
109
  # @return [Query]
110
- # @see http://www.w3.org/TR/rdf-sparql-query/#describe
110
+ # @see http://www.w3.org/TR/sparql11-query/#describe
111
111
  def describe(*variables)
112
112
  @values = variables.map { |var|
113
113
  [var, var.is_a?(RDF::URI) ? var : RDF::Query::Variable.new(var)]
@@ -118,6 +118,7 @@ module SPARQL; class Client
118
118
  ##
119
119
  # @param [Array<RDF::Query::Pattern, Array>] patterns
120
120
  # @return [Query]
121
+ # @see http://www.w3.org/TR/sparql11-query/#construct
121
122
  def construct(*patterns)
122
123
  options[:template] = build_patterns(patterns)
123
124
  self
@@ -125,7 +126,7 @@ module SPARQL; class Client
125
126
 
126
127
  # @param [RDF::URI] uri
127
128
  # @return [Query]
128
- # @see http://www.w3.org/TR/rdf-sparql-query/#specDataset
129
+ # @see http://www.w3.org/TR/sparql11-query/#specifyingDataset
129
130
  def from(uri)
130
131
  options[:from] = uri
131
132
  self
@@ -134,7 +135,7 @@ module SPARQL; class Client
134
135
  ##
135
136
  # @param [Array<RDF::Query::Pattern, Array>] patterns
136
137
  # @return [Query]
137
- # @see http://www.w3.org/TR/rdf-sparql-query/#GraphPattern
138
+ # @see http://www.w3.org/TR/sparql11-query/#GraphPattern
138
139
  def where(*patterns)
139
140
  @patterns += build_patterns(patterns)
140
141
  self
@@ -145,7 +146,7 @@ module SPARQL; class Client
145
146
  ##
146
147
  # @param [Array<Symbol, String>] variables
147
148
  # @return [Query]
148
- # @see http://www.w3.org/TR/rdf-sparql-query/#modOrderBy
149
+ # @see http://www.w3.org/TR/sparql11-query/#modOrderBy
149
150
  def order(*variables)
150
151
  options[:order_by] = variables
151
152
  self
@@ -166,7 +167,7 @@ module SPARQL; class Client
166
167
 
167
168
  ##
168
169
  # @return [Query]
169
- # @see http://www.w3.org/TR/rdf-sparql-query/#modDistinct
170
+ # @see http://www.w3.org/TR/sparql11-query/#modDuplicates
170
171
  def distinct(state = true)
171
172
  options[:distinct] = state
172
173
  self
@@ -174,16 +175,30 @@ module SPARQL; class Client
174
175
 
175
176
  ##
176
177
  # @return [Query]
177
- # @see http://www.w3.org/TR/rdf-sparql-query/#modReduced
178
+ # @see http://www.w3.org/TR/sparql11-query/#modDuplicates
178
179
  def reduced(state = true)
179
180
  options[:reduced] = state
180
181
  self
181
182
  end
182
183
 
184
+ ##
185
+ # @param [RDF::Value] graph_uri_or_var
186
+ # @return [Query]
187
+ # @see http://www.w3.org/TR/sparql11-query/#queryDataset
188
+ def graph(graph_uri_or_var)
189
+ options[:graph] = case graph_uri_or_var
190
+ when Symbol then RDF::Query::Variable.new(graph_uri_or_var)
191
+ when String then RDF::URI(graph_uri_or_var)
192
+ when RDF::Value then graph_uri_or_var
193
+ else raise ArgumentError
194
+ end
195
+ self
196
+ end
197
+
183
198
  ##
184
199
  # @param [Integer, #to_i] start
185
200
  # @return [Query]
186
- # @see http://www.w3.org/TR/rdf-sparql-query/#modOffset
201
+ # @see http://www.w3.org/TR/sparql11-query/#modOffset
187
202
  def offset(start)
188
203
  slice(start, nil)
189
204
  end
@@ -191,7 +206,7 @@ module SPARQL; class Client
191
206
  ##
192
207
  # @param [Integer, #to_i] length
193
208
  # @return [Query]
194
- # @see http://www.w3.org/TR/rdf-sparql-query/#modResultLimit
209
+ # @see http://www.w3.org/TR/sparql11-query/#modResultLimit
195
210
  def limit(length)
196
211
  slice(nil, length)
197
212
  end
@@ -208,7 +223,7 @@ module SPARQL; class Client
208
223
 
209
224
  ##
210
225
  # @return [Query]
211
- # @see http://www.w3.org/TR/rdf-sparql-query/#prefNames
226
+ # @see http://www.w3.org/TR/sparql11-query/#prefNames
212
227
  def prefix(string)
213
228
  (options[:prefixes] ||= []) << string
214
229
  self
@@ -216,7 +231,7 @@ module SPARQL; class Client
216
231
 
217
232
  ##
218
233
  # @return [Query]
219
- # @see http://www.w3.org/TR/rdf-sparql-query/#optionals
234
+ # @see http://www.w3.org/TR/sparql11-query/#optionals
220
235
  def optional(*patterns)
221
236
  (options[:optionals] ||= []) << build_patterns(patterns)
222
237
  self
@@ -298,15 +313,17 @@ module SPARQL; class Client
298
313
  # @return [String]
299
314
  def to_s
300
315
  buffer = [form.to_s.upcase]
316
+
301
317
  case form
302
318
  when :select, :describe
303
319
  only_count = values.empty? and options[:count]
304
320
  buffer << 'DISTINCT' if options[:distinct] and not only_count
305
321
  buffer << 'REDUCED' if options[:reduced]
306
- buffer << ((values.empty? and not options[:count]) ? '*' : values.map { |v| serialize_value(v[1]) }.join(' '))
322
+ buffer << ((values.empty? and not options[:count]) ? '*' : values.map { |v| SPARQL::Client.serialize_value(v[1]) }.join(' '))
307
323
  if options[:count]
308
324
  options[:count].each do |var, count|
309
- buffer << '( COUNT(' + (options[:distinct] ? 'DISTINCT ' : '') + (var.is_a?(String) ? var : "?#{var}") + ') AS ' + (count.is_a?(String) ? count : "?#{count}") + ' )'
325
+ buffer << '( COUNT(' + (options[:distinct] ? 'DISTINCT ' : '') +
326
+ (var.is_a?(String) ? var : "?#{var}") + ') AS ' + (count.is_a?(String) ? count : "?#{count}") + ' )'
310
327
  end
311
328
  end
312
329
  when :construct
@@ -315,10 +332,15 @@ module SPARQL; class Client
315
332
  buffer << '}'
316
333
  end
317
334
 
318
- buffer << "FROM #{serialize_value(options[:from])}" if options[:from]
335
+ buffer << "FROM #{SPARQL::Client.serialize_value(options[:from])}" if options[:from]
319
336
 
320
337
  unless patterns.empty? && form == :describe
321
338
  buffer << 'WHERE {'
339
+
340
+ if options[:graph]
341
+ buffer << 'GRAPH ' + SPARQL::Client.serialize_value(options[:graph])
342
+ buffer << '{'
343
+ end
322
344
  buffer += serialize_patterns(patterns)
323
345
  if options[:optionals]
324
346
  options[:optionals].each do |patterns|
@@ -330,7 +352,11 @@ module SPARQL; class Client
330
352
  if options[:filters]
331
353
  buffer += options[:filters].map { |filter| "FILTER(#{filter})" }
332
354
  end
333
- buffer << '}'
355
+ if options[:graph]
356
+ buffer << '}' # GRAPH
357
+ end
358
+
359
+ buffer << '}' # WHERE
334
360
  end
335
361
 
336
362
  if options[:group_by]
@@ -345,7 +371,7 @@ module SPARQL; class Client
345
371
 
346
372
  buffer << "OFFSET #{options[:offset]}" if options[:offset]
347
373
  buffer << "LIMIT #{options[:limit]}" if options[:limit]
348
- options[:prefixes].reverse.each {|e| buffer.unshift("PREFIX #{e}") } if options[:prefixes]
374
+ options[:prefixes].reverse.each { |e| buffer.unshift("PREFIX #{e}") } if options[:prefixes]
349
375
 
350
376
  buffer.join(' ')
351
377
  end
@@ -353,8 +379,16 @@ module SPARQL; class Client
353
379
  ##
354
380
  # @private
355
381
  def serialize_patterns(patterns)
356
- patterns.map do |p|
357
- p.to_triple.map { |v| serialize_value(v) }.join(' ') + " ."
382
+ rdf_type = RDF.type
383
+ patterns.map do |pattern|
384
+ serialized_pattern = pattern.to_triple.each_with_index.map do |v, i|
385
+ if i == 1 && v.equal?(rdf_type)
386
+ 'a' # abbreviate RDF.type in the predicate position per SPARQL grammar
387
+ else
388
+ SPARQL::Client.serialize_value(v)
389
+ end
390
+ end
391
+ serialized_pattern.join(' ') + ' .'
358
392
  end
359
393
  end
360
394
 
@@ -374,20 +408,5 @@ module SPARQL; class Client
374
408
  def inspect
375
409
  sprintf("#<%s:%#0x(%s)>", self.class.name, __id__, to_s)
376
410
  end
377
-
378
- ##
379
- # Serializes an RDF::Value into a format appropriate for select, construct, and where clauses
380
- #
381
- # @param [RDF::Value] value
382
- # @return [String]
383
- # @private
384
- def serialize_value(value)
385
- # SPARQL queries are UTF-8, but support ASCII-style Unicode escapes, so
386
- # the N-Triples serializer is fine unless it's a variable:
387
- case
388
- when value.variable? then value.to_s
389
- else RDF::NTriples.serialize(value)
390
- end
391
- end
392
411
  end
393
412
  end; end
@@ -1,7 +1,7 @@
1
1
  module SPARQL; class Client
2
2
  module VERSION
3
- VERSION_FILE = File.expand_path("../../../../VERSION", __FILE__)
4
- MAJOR, MINOR, TINY, EXTRA = File.read(VERSION_FILE).chop.split(".")
3
+ VERSION_FILE = File.expand_path('../../../../VERSION', __FILE__)
4
+ MAJOR, MINOR, TINY, EXTRA = File.read(VERSION_FILE).chop.split('.')
5
5
  STRING = [MAJOR, MINOR, TINY, EXTRA].compact.join('.')
6
6
 
7
7
  ##
metadata CHANGED
@@ -1,25 +1,26 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sparql-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.3.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Arto Bendiken
9
9
  - Ben Lavender
10
+ - Gregg Kellogg
10
11
  autorequire:
11
12
  bindir: bin
12
13
  cert_chain: []
13
- date: 2013-01-09 00:00:00.000000000 Z
14
+ date: 2013-01-11 00:00:00.000000000 Z
14
15
  dependencies:
15
16
  - !ruby/object:Gem::Dependency
16
- name: json_pure
17
+ name: rdf
17
18
  requirement: !ruby/object:Gem::Requirement
18
19
  none: false
19
20
  requirements:
20
21
  - - ! '>='
21
22
  - !ruby/object:Gem::Version
22
- version: 1.4.6
23
+ version: 0.3.5
23
24
  type: :runtime
24
25
  prerelease: false
25
26
  version_requirements: !ruby/object:Gem::Requirement
@@ -27,15 +28,15 @@ dependencies:
27
28
  requirements:
28
29
  - - ! '>='
29
30
  - !ruby/object:Gem::Version
30
- version: 1.4.6
31
+ version: 0.3.5
31
32
  - !ruby/object:Gem::Dependency
32
- name: rdf
33
+ name: net-http-persistent
33
34
  requirement: !ruby/object:Gem::Requirement
34
35
  none: false
35
36
  requirements:
36
37
  - - ! '>='
37
38
  - !ruby/object:Gem::Version
38
- version: 0.3.5
39
+ version: 1.4.1
39
40
  type: :runtime
40
41
  prerelease: false
41
42
  version_requirements: !ruby/object:Gem::Requirement
@@ -43,15 +44,15 @@ dependencies:
43
44
  requirements:
44
45
  - - ! '>='
45
46
  - !ruby/object:Gem::Version
46
- version: 0.3.5
47
+ version: 1.4.1
47
48
  - !ruby/object:Gem::Dependency
48
- name: net-http-persistent
49
+ name: json_pure
49
50
  requirement: !ruby/object:Gem::Requirement
50
51
  none: false
51
52
  requirements:
52
53
  - - ! '>='
53
54
  - !ruby/object:Gem::Version
54
- version: 1.4.1
55
+ version: 1.4.6
55
56
  type: :runtime
56
57
  prerelease: false
57
58
  version_requirements: !ruby/object:Gem::Requirement
@@ -59,15 +60,15 @@ dependencies:
59
60
  requirements:
60
61
  - - ! '>='
61
62
  - !ruby/object:Gem::Version
62
- version: 1.4.1
63
+ version: 1.4.6
63
64
  - !ruby/object:Gem::Dependency
64
- name: yard
65
+ name: rdf-spec
65
66
  requirement: !ruby/object:Gem::Requirement
66
67
  none: false
67
68
  requirements:
68
69
  - - ! '>='
69
70
  - !ruby/object:Gem::Version
70
- version: 0.7.5
71
+ version: 0.3.5
71
72
  type: :development
72
73
  prerelease: false
73
74
  version_requirements: !ruby/object:Gem::Requirement
@@ -75,7 +76,7 @@ dependencies:
75
76
  requirements:
76
77
  - - ! '>='
77
78
  - !ruby/object:Gem::Version
78
- version: 0.7.5
79
+ version: 0.3.5
79
80
  - !ruby/object:Gem::Dependency
80
81
  name: rspec
81
82
  requirement: !ruby/object:Gem::Requirement
@@ -93,13 +94,13 @@ dependencies:
93
94
  - !ruby/object:Gem::Version
94
95
  version: 2.10.0
95
96
  - !ruby/object:Gem::Dependency
96
- name: rdf-spec
97
+ name: yard
97
98
  requirement: !ruby/object:Gem::Requirement
98
99
  none: false
99
100
  requirements:
100
101
  - - ! '>='
101
102
  - !ruby/object:Gem::Version
102
- version: 0.3.5
103
+ version: 0.8.3
103
104
  type: :development
104
105
  prerelease: false
105
106
  version_requirements: !ruby/object:Gem::Requirement
@@ -107,7 +108,7 @@ dependencies:
107
108
  requirements:
108
109
  - - ! '>='
109
110
  - !ruby/object:Gem::Version
110
- version: 0.3.5
111
+ version: 0.8.3
111
112
  description: SPARQL client for RDF.rb.
112
113
  email: public-rdf-ruby@w3.org
113
114
  executables: []