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 +2 -1
- data/CREDITS +1 -1
- data/README +11 -11
- data/VERSION +1 -1
- data/lib/sparql/client.rb +226 -32
- data/lib/sparql/client/query.rb +58 -39
- data/lib/sparql/client/version.rb +2 -2
- metadata +18 -17
data/AUTHORS
CHANGED
data/CREDITS
CHANGED
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
|
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
|
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.
|
69
|
-
* [
|
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/
|
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/
|
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://
|
128
|
-
* <http://github.com/
|
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.
|
1
|
+
0.3.3
|
data/lib/sparql/client.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
|
-
require 'net/http/persistent'
|
2
|
-
require '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/
|
10
|
-
# @see http://www.w3.org/TR/
|
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
|
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
|
-
#
|
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
|
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
|
-
|
124
|
-
|
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
|
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
|
-
|
437
|
+
proxy_url = nil
|
275
438
|
case scheme
|
276
|
-
when
|
277
|
-
|
278
|
-
|
279
|
-
|
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,
|
282
|
-
klass.keep_alive = 120
|
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
|
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
|
-
|
295
|
-
|
296
|
-
|
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
|
299
|
-
|
300
|
-
response = @http.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
|
-
|
468
|
+
block.call(response)
|
303
469
|
else
|
304
|
-
|
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
|
data/lib/sparql/client/query.rb
CHANGED
@@ -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/
|
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/
|
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/
|
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/
|
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/
|
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/
|
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/
|
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/
|
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/
|
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/
|
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/
|
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/
|
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/
|
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/
|
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/
|
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/
|
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/
|
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 ' : '') +
|
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
|
-
|
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
|
-
|
357
|
-
|
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(
|
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.
|
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-
|
14
|
+
date: 2013-01-11 00:00:00.000000000 Z
|
14
15
|
dependencies:
|
15
16
|
- !ruby/object:Gem::Dependency
|
16
|
-
name:
|
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:
|
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:
|
31
|
+
version: 0.3.5
|
31
32
|
- !ruby/object:Gem::Dependency
|
32
|
-
name:
|
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:
|
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:
|
47
|
+
version: 1.4.1
|
47
48
|
- !ruby/object:Gem::Dependency
|
48
|
-
name:
|
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.
|
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.
|
63
|
+
version: 1.4.6
|
63
64
|
- !ruby/object:Gem::Dependency
|
64
|
-
name:
|
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.
|
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.
|
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:
|
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
|
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
|
111
|
+
version: 0.8.3
|
111
112
|
description: SPARQL client for RDF.rb.
|
112
113
|
email: public-rdf-ruby@w3.org
|
113
114
|
executables: []
|