sparql-client 2.0.2 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +85 -55
- data/VERSION +1 -1
- data/lib/sparql/client.rb +132 -52
- data/lib/sparql/client/query.rb +373 -68
- data/lib/sparql/client/repository.rb +39 -15
- data/lib/sparql/client/update.rb +28 -29
- data/lib/sparql/client/version.rb +2 -2
- metadata +21 -50
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 25fd44467b4b7014096fea7c336164c863b3da501ee747466ed486bdfab2f93d
|
4
|
+
data.tar.gz: f44d3e424e8c3fb13b0a323403212134c34e8fa7fb7ebaba562ded69a9d02fd7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 404e7f204b5bda734f531b29133705dcdf236a4bc7f348f32f6034595e43cd7e78814cb2d8cf66c696a9fd548496fd50b245b5bf2e705a551ef6e5012321c7d6
|
7
|
+
data.tar.gz: 4764b49167f0bd23e16455d9e1cf9ede6193db3dcd96eb17fd9ed4245557906dd5195424dbe88f098c8381e580ffc433f577e558b5472cb4f8f2a1756de3f911
|
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,90 +22,121 @@ 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
|
-
require 'sparql/client'
|
29
28
|
|
30
|
-
|
29
|
+
```ruby
|
30
|
+
require 'sparql/client'
|
31
|
+
sparql = SPARQL::Client.new("http://dbpedia.org/sparql")
|
32
|
+
```
|
31
33
|
|
32
|
-
### Querying a
|
34
|
+
### Querying a remote SPARQL endpoint with a custom User-Agent
|
35
|
+
By default, SPARQL::Client adds a `User-Agent` field to requests, but applications may choose to provide their own, using the `headers` option:
|
33
36
|
|
34
|
-
|
35
|
-
|
37
|
+
```ruby
|
38
|
+
require 'sparql/client'
|
39
|
+
sparql = SPARQL::Client.new("http://dbpedia.org/sparql", headers: {'User-Agent' => 'MyBotName'})
|
40
|
+
```
|
36
41
|
|
37
|
-
|
42
|
+
### Querying a remote SPARQL endpoint with a specified default graph
|
38
43
|
|
39
|
-
|
44
|
+
```ruby
|
45
|
+
require 'sparql/client'
|
46
|
+
sparql = SPARQL::Client.new("http://dbpedia.org/sparql", { graph: "http://dbpedia.org" })
|
47
|
+
```
|
48
|
+
|
49
|
+
|
50
|
+
### Querying a `RDF::Repository` instance
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
require 'rdf/trig'
|
54
|
+
repository = RDF::Repository.load("http://example/dataset.trig")
|
55
|
+
sparql = SPARQL::Client.new(repository)
|
56
|
+
```
|
40
57
|
|
41
|
-
|
42
|
-
result = sparql.ask.whether([:s, :p, :o]).true?
|
58
|
+
### Executing a boolean query and outputting the result
|
43
59
|
|
44
|
-
|
60
|
+
```ruby
|
61
|
+
# ASK WHERE { ?s ?p ?o }
|
62
|
+
result = sparql.ask.whether([:s, :p, :o]).true?
|
63
|
+
puts result.inspect #=> true or false
|
64
|
+
```
|
45
65
|
|
46
66
|
### Executing a tuple query and iterating over the returned solutions
|
47
67
|
|
48
|
-
|
49
|
-
|
68
|
+
```ruby
|
69
|
+
# SELECT * WHERE { ?s ?p ?o } OFFSET 100 LIMIT 10
|
70
|
+
query = sparql.select.where([:s, :p, :o]).offset(100).limit(10)
|
50
71
|
|
51
|
-
|
52
|
-
|
53
|
-
|
72
|
+
query.each_solution do |solution|
|
73
|
+
puts solution.inspect
|
74
|
+
end
|
75
|
+
```
|
54
76
|
|
55
77
|
### Executing a graph query and iterating over the returned statements
|
56
78
|
|
57
|
-
# CONSTRUCT { ?s ?p ?o } WHERE { ?s ?p ?o } LIMIT 10
|
58
|
-
query = sparql.construct([:s, :p, :o]).where([:s, :p, :o]).limit(10)
|
59
79
|
|
60
|
-
|
61
|
-
|
62
|
-
|
80
|
+
```ruby
|
81
|
+
# CONSTRUCT { ?s ?p ?o } WHERE { ?s ?p ?o } LIMIT 10
|
82
|
+
query = sparql.construct([:s, :p, :o]).where([:s, :p, :o]).limit(10)
|
83
|
+
|
84
|
+
query.each_statement do |statement|
|
85
|
+
puts statement.inspect
|
86
|
+
end
|
87
|
+
```
|
63
88
|
|
64
89
|
### Executing an arbitrary textual SPARQL query string
|
65
90
|
|
66
|
-
|
91
|
+
```ruby
|
92
|
+
result = sparql.query("ASK WHERE { ?s ?p ?o }")
|
67
93
|
|
68
|
-
|
94
|
+
puts result.inspect #=> true or false
|
95
|
+
```
|
69
96
|
|
70
97
|
### Inserting data into a graph
|
71
98
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
99
|
+
```ruby
|
100
|
+
# INSERT DATA { <http://example.org/jhacker> <http://xmlns.com/foaf/0.1/name> "J. Random Hacker" .}
|
101
|
+
data = RDF::Graph.new do |graph|
|
102
|
+
graph << [RDF::URI('http://example.org/jhacker'), RDF::Vocab::FOAF.name, "J. Random Hacker"]
|
103
|
+
end
|
104
|
+
sparql.insert_data(data)
|
105
|
+
```
|
77
106
|
|
78
107
|
### Deleting data from a graph
|
79
108
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
109
|
+
```ruby
|
110
|
+
# DELETE DATA { <http://example.org/jhacker> <http://xmlns.com/foaf/0.1/name> "J. Random Hacker" .}
|
111
|
+
data = RDF::Graph.new do |graph|
|
112
|
+
graph << [RDF::URI('http://example.org/jhacker'), RDF::Vocab::FOAF.name, "J. Random Hacker"]
|
113
|
+
end
|
114
|
+
sparql.delete_data(data)
|
115
|
+
```
|
85
116
|
|
86
|
-
##Documentation
|
117
|
+
## Documentation
|
87
118
|
|
88
|
-
*
|
89
|
-
*
|
90
|
-
*
|
91
|
-
*
|
119
|
+
* [SPARQL::Client](https://www.rubydoc.info/github/ruby-rdf/sparql-client/SPARQL/Client)
|
120
|
+
* [SPARQL::Client::Query](https://www.rubydoc.info/github/ruby-rdf/sparql-client/SPARQL/Client/Query)
|
121
|
+
* [SPARQL::Client::Repository](https://www.rubydoc.info/github/ruby-rdf/sparql-client/SPARQL/Client/Repository)
|
122
|
+
* [SPARQL::Client::Update](https://www.rubydoc.info/github/ruby-rdf/sparql-client/SPARQL/Client/Update)
|
92
123
|
|
93
|
-
##Dependencies
|
124
|
+
## Dependencies
|
94
125
|
|
95
|
-
* [Ruby](http://ruby-lang.org/) (>= 2.
|
96
|
-
* [RDF.rb](http://rubygems.org/gems/rdf) (
|
97
|
-
* [Net::HTTP::Persistent](http://rubygems.org/gems/net-http-persistent) (
|
98
|
-
* Soft dependency on [SPARQL](http://rubygems.org/gems/sparql) (
|
99
|
-
* Soft dependency on [Nokogiri](http://rubygems.org/gems/nokogiri) (>= 1.
|
126
|
+
* [Ruby](http://ruby-lang.org/) (>= 2.4)
|
127
|
+
* [RDF.rb](http://rubygems.org/gems/rdf) (~> 3.1)
|
128
|
+
* [Net::HTTP::Persistent](http://rubygems.org/gems/net-http-persistent) (~> 3.1)
|
129
|
+
* Soft dependency on [SPARQL](http://rubygems.org/gems/sparql) (~> 3.1)
|
130
|
+
* Soft dependency on [Nokogiri](http://rubygems.org/gems/nokogiri) (>= 1.10)
|
100
131
|
|
101
|
-
##Installation
|
132
|
+
## Installation
|
102
133
|
|
103
134
|
The recommended installation method is via [RubyGems](http://rubygems.org/).
|
104
135
|
To install the latest official release of the `SPARQL::Client` gem, do:
|
105
136
|
|
106
137
|
% [sudo] gem install sparql-client
|
107
138
|
|
108
|
-
##Download
|
139
|
+
## Download
|
109
140
|
|
110
141
|
To get a local working copy of the development repository, do:
|
111
142
|
|
@@ -116,17 +147,17 @@ follows:
|
|
116
147
|
|
117
148
|
% wget http://github.com/ruby-rdf/sparql-client/tarball/master
|
118
149
|
|
119
|
-
##Mailing List
|
150
|
+
## Mailing List
|
120
151
|
|
121
152
|
* <http://lists.w3.org/Archives/Public/public-rdf-ruby/>
|
122
153
|
|
123
|
-
##Authors
|
154
|
+
## Authors
|
124
155
|
|
125
156
|
* [Arto Bendiken](http://github.com/bendiken) - <http://ar.to/>
|
126
157
|
* [Ben Lavender](http://github.com/bhuga) - <http://bhuga.net/>
|
127
158
|
* [Gregg Kellogg](http://github.com/gkellogg) - <http://greggkellogg.net/>
|
128
159
|
|
129
|
-
##Contributors
|
160
|
+
## Contributors
|
130
161
|
|
131
162
|
* [Christoph Badura](http://github.com/bad) - <http://github.com/bad>
|
132
163
|
* [James Hetherington](http://github.com/jamespjh) - <http://twitter.com/jamespjh>
|
@@ -140,7 +171,7 @@ follows:
|
|
140
171
|
* [Thomas Feron](http://github.com/thoferon) - <http://github.com/thoferon>
|
141
172
|
* [Nick Gottlieb](http://github.com/ngottlieb) - <http://www.nicholasgottlieb.com>
|
142
173
|
|
143
|
-
##Contributing
|
174
|
+
## Contributing
|
144
175
|
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
176
|
|
146
177
|
* Do your best to adhere to the existing coding conventions and idioms.
|
@@ -155,16 +186,15 @@ This repository uses [Git Flow](https://github.com/nvie/gitflow) to mange develo
|
|
155
186
|
of thumb, additions larger than about 15 lines of code), we need an
|
156
187
|
explicit [public domain dedication][PDD] on record from you.
|
157
188
|
|
158
|
-
##Resources
|
189
|
+
## Resources
|
159
190
|
|
160
191
|
* <http://ruby-rdf.github.com/sparql-client/>
|
161
192
|
* <http://github.com/ruby-rdf/sparql-client>
|
162
193
|
* <http://rubygems.org/gems/sparql-client>
|
163
|
-
* <http://rubyforge.org/projects/sparql/>
|
164
194
|
* <http://raa.ruby-lang.org/project/sparql-client/>
|
165
195
|
* <http://www.ohloh.net/p/rdf>
|
166
196
|
|
167
|
-
##License
|
197
|
+
## License
|
168
198
|
|
169
199
|
This is free and unencumbered public domain software. For more information,
|
170
200
|
see <http://unlicense.org/> or the accompanying {file:UNLICENSE} file.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
3.1.0
|
data/lib/sparql/client.rb
CHANGED
@@ -40,7 +40,7 @@ module SPARQL
|
|
40
40
|
'*/*;q=0.1'
|
41
41
|
].join(', ').freeze
|
42
42
|
GRAPH_ALL = (
|
43
|
-
RDF::Format.content_types.keys +
|
43
|
+
RDF::Format.content_types.keys +
|
44
44
|
['*/*;q=0.1']
|
45
45
|
).join(', ').freeze
|
46
46
|
|
@@ -86,8 +86,13 @@ module SPARQL
|
|
86
86
|
# @option options [Symbol] :method (DEFAULT_METHOD)
|
87
87
|
# @option options [Number] :protocol (DEFAULT_PROTOCOL)
|
88
88
|
# @option options [Hash] :headers
|
89
|
+
# HTTP Request headers
|
90
|
+
#
|
91
|
+
# Defaults `Accept` header based on available reader content types if triples are expected and to SPARQL result types otherwise, to allow for content negotiation based on available readers.
|
92
|
+
#
|
93
|
+
# Defaults `User-Agent` header, unless one is specified.
|
89
94
|
# @option options [Hash] :read_timeout
|
90
|
-
def initialize(url, options
|
95
|
+
def initialize(url, **options, &block)
|
91
96
|
case url
|
92
97
|
when RDF::Queryable
|
93
98
|
@url, @options = url, options.dup
|
@@ -95,6 +100,9 @@ module SPARQL
|
|
95
100
|
@url, @options = RDF::URI.new(url.to_s), options.dup
|
96
101
|
@headers = @options.delete(:headers) || {}
|
97
102
|
@http = http_klass(@url.scheme)
|
103
|
+
|
104
|
+
# Close the http connection when object is deallocated
|
105
|
+
ObjectSpace.define_finalizer(self, proc {@http.shutdown if @http.respond_to?(:shutdown)})
|
98
106
|
end
|
99
107
|
|
100
108
|
if block_given?
|
@@ -105,13 +113,23 @@ module SPARQL
|
|
105
113
|
end
|
106
114
|
end
|
107
115
|
|
116
|
+
##
|
117
|
+
# Closes a client instance by finishing the connection.
|
118
|
+
# The client is unavailable for any further data operations; an IOError is raised if such an attempt is made. I/O streams are automatically closed when they are claimed by the garbage collector.
|
119
|
+
# @return [void] `self`
|
120
|
+
def close
|
121
|
+
@http.shutdown if @http
|
122
|
+
@http = nil
|
123
|
+
self
|
124
|
+
end
|
125
|
+
|
108
126
|
##
|
109
127
|
# Executes a boolean `ASK` query.
|
110
128
|
#
|
111
129
|
# @param (see Query.ask)
|
112
130
|
# @return [Query]
|
113
|
-
def ask(*args)
|
114
|
-
call_query_method(:ask, *args)
|
131
|
+
def ask(*args, **options)
|
132
|
+
call_query_method(:ask, *args, **options)
|
115
133
|
end
|
116
134
|
|
117
135
|
##
|
@@ -119,8 +137,8 @@ module SPARQL
|
|
119
137
|
#
|
120
138
|
# @param (see Query.select)
|
121
139
|
# @return [Query]
|
122
|
-
def select(*args)
|
123
|
-
call_query_method(:select, *args)
|
140
|
+
def select(*args, **options)
|
141
|
+
call_query_method(:select, *args, **options)
|
124
142
|
end
|
125
143
|
|
126
144
|
##
|
@@ -128,8 +146,8 @@ module SPARQL
|
|
128
146
|
#
|
129
147
|
# @param (see Query.describe)
|
130
148
|
# @return [Query]
|
131
|
-
def describe(*args)
|
132
|
-
call_query_method(:describe, *args)
|
149
|
+
def describe(*args, **options)
|
150
|
+
call_query_method(:describe, *args, **options)
|
133
151
|
end
|
134
152
|
|
135
153
|
##
|
@@ -137,8 +155,8 @@ module SPARQL
|
|
137
155
|
#
|
138
156
|
# @param (see Query.construct)
|
139
157
|
# @return [Query]
|
140
|
-
def construct(*args)
|
141
|
-
call_query_method(:construct, *args)
|
158
|
+
def construct(*args, **options)
|
159
|
+
call_query_method(:construct, *args, **options)
|
142
160
|
end
|
143
161
|
|
144
162
|
##
|
@@ -157,19 +175,19 @@ module SPARQL
|
|
157
175
|
# })
|
158
176
|
#
|
159
177
|
# @example Inserting data sourced from a file or URL
|
160
|
-
# data = RDF::Graph.load("
|
178
|
+
# data = RDF::Graph.load("https://raw.githubusercontent.com/ruby-rdf/rdf/develop/etc/doap.nt")
|
161
179
|
# client.insert_data(data)
|
162
180
|
#
|
163
181
|
# @example Inserting data into a named graph
|
164
|
-
# client.insert_data(data, :
|
182
|
+
# client.insert_data(data, graph: "http://example.org/")
|
165
183
|
#
|
166
184
|
# @param [RDF::Enumerable] data
|
167
185
|
# @param [Hash{Symbol => Object}] options
|
168
186
|
# @option options [RDF::URI, String] :graph
|
169
187
|
# @return [void] `self`
|
170
188
|
# @see http://www.w3.org/TR/sparql11-update/#insertData
|
171
|
-
def insert_data(data, options
|
172
|
-
self.update(Update::InsertData.new(data, options))
|
189
|
+
def insert_data(data, **options)
|
190
|
+
self.update(Update::InsertData.new(data, **options))
|
173
191
|
end
|
174
192
|
|
175
193
|
##
|
@@ -178,19 +196,19 @@ module SPARQL
|
|
178
196
|
# This requires that the endpoint support SPARQL 1.1 Update.
|
179
197
|
#
|
180
198
|
# @example Deleting data sourced from a file or URL
|
181
|
-
# data = RDF::Graph.load("
|
199
|
+
# data = RDF::Graph.load("https://raw.githubusercontent.com/ruby-rdf/rdf/develop/etc/doap.nt")
|
182
200
|
# client.delete_data(data)
|
183
201
|
#
|
184
202
|
# @example Deleting data from a named graph
|
185
|
-
# client.delete_data(data, :
|
203
|
+
# client.delete_data(data, graph: "http://example.org/")
|
186
204
|
#
|
187
205
|
# @param [RDF::Enumerable] data
|
188
206
|
# @param [Hash{Symbol => Object}] options
|
189
207
|
# @option options [RDF::URI, String] :graph
|
190
208
|
# @return [void] `self`
|
191
209
|
# @see http://www.w3.org/TR/sparql11-update/#deleteData
|
192
|
-
def delete_data(data, options
|
193
|
-
self.update(Update::DeleteData.new(data, options))
|
210
|
+
def delete_data(data, **options)
|
211
|
+
self.update(Update::DeleteData.new(data, **options))
|
194
212
|
end
|
195
213
|
|
196
214
|
##
|
@@ -205,8 +223,8 @@ module SPARQL
|
|
205
223
|
# @option options [RDF::URI, String] :graph
|
206
224
|
# @return [void] `self`
|
207
225
|
# @see http://www.w3.org/TR/sparql11-update/#deleteInsert
|
208
|
-
def delete_insert(delete_graph, insert_graph = nil, where_graph = nil, options
|
209
|
-
self.update(Update::DeleteInsert.new(delete_graph, insert_graph, where_graph, options))
|
226
|
+
def delete_insert(delete_graph, insert_graph = nil, where_graph = nil, **options)
|
227
|
+
self.update(Update::DeleteInsert.new(delete_graph, insert_graph, where_graph, **options))
|
210
228
|
end
|
211
229
|
|
212
230
|
##
|
@@ -222,8 +240,8 @@ module SPARQL
|
|
222
240
|
# @option options [Boolean] :silent
|
223
241
|
# @return [void] `self`
|
224
242
|
# @see http://www.w3.org/TR/sparql11-update/#clear
|
225
|
-
def clear_graph(graph_uri, options
|
226
|
-
self.clear(:graph, graph_uri, options)
|
243
|
+
def clear_graph(graph_uri, **options)
|
244
|
+
self.clear(:graph, graph_uri, **options)
|
227
245
|
end
|
228
246
|
|
229
247
|
##
|
@@ -249,7 +267,7 @@ module SPARQL
|
|
249
267
|
# @option options [Boolean] :silent
|
250
268
|
# @return [void] `self`
|
251
269
|
#
|
252
|
-
# @overload clear(what, *arguments, options
|
270
|
+
# @overload clear(what, *arguments, **options)
|
253
271
|
# @param [Symbol, #to_sym] what
|
254
272
|
# @param [Array] arguments splat of other arguments to {Update::Clear}.
|
255
273
|
# @param [Hash{Symbol => Object}] options
|
@@ -263,9 +281,9 @@ module SPARQL
|
|
263
281
|
|
264
282
|
##
|
265
283
|
# @private
|
266
|
-
def call_query_method(meth, *args)
|
284
|
+
def call_query_method(meth, *args, **options)
|
267
285
|
client = self
|
268
|
-
result = Query.send(meth, *args)
|
286
|
+
result = Query.send(meth, *args, **options)
|
269
287
|
(class << result; self; end).send(:define_method, :execute) do
|
270
288
|
client.query(self)
|
271
289
|
end
|
@@ -288,21 +306,22 @@ module SPARQL
|
|
288
306
|
# @option options [String] :content_type
|
289
307
|
# @option options [Hash] :headers
|
290
308
|
# @return [Array<RDF::Query::Solution>]
|
309
|
+
# @raise [IOError] if connection is closed
|
291
310
|
# @see http://www.w3.org/TR/sparql11-protocol/#query-operation
|
292
|
-
def query(query, options
|
311
|
+
def query(query, **options)
|
293
312
|
@op = :query
|
294
313
|
@alt_endpoint = options[:endpoint]
|
295
314
|
case @url
|
296
315
|
when RDF::Queryable
|
297
316
|
require 'sparql' unless defined?(::SPARQL::Grammar)
|
298
317
|
begin
|
299
|
-
SPARQL.execute(query, @url, options)
|
318
|
+
SPARQL.execute(query, @url, **options)
|
300
319
|
rescue SPARQL::MalformedQuery
|
301
320
|
$stderr.puts "error running #{query}: #{$!}"
|
302
321
|
raise
|
303
322
|
end
|
304
323
|
else
|
305
|
-
parse_response(response(query, options), options)
|
324
|
+
parse_response(response(query, **options), **options)
|
306
325
|
end
|
307
326
|
end
|
308
327
|
|
@@ -315,16 +334,17 @@ module SPARQL
|
|
315
334
|
# @option options [String] :content_type
|
316
335
|
# @option options [Hash] :headers
|
317
336
|
# @return [void] `self`
|
337
|
+
# @raise [IOError] if connection is closed
|
318
338
|
# @see http://www.w3.org/TR/sparql11-protocol/#update-operation
|
319
|
-
def update(query, options
|
339
|
+
def update(query, **options)
|
320
340
|
@op = :update
|
321
341
|
@alt_endpoint = options[:endpoint]
|
322
342
|
case @url
|
323
343
|
when RDF::Queryable
|
324
344
|
require 'sparql' unless defined?(::SPARQL::Grammar)
|
325
|
-
SPARQL.execute(query, @url,
|
345
|
+
SPARQL.execute(query, @url, update: true, **options)
|
326
346
|
else
|
327
|
-
response(query, options)
|
347
|
+
response(query, **options)
|
328
348
|
end
|
329
349
|
self
|
330
350
|
end
|
@@ -338,8 +358,9 @@ module SPARQL
|
|
338
358
|
# @option options [String] :content_type
|
339
359
|
# @option options [Hash] :headers
|
340
360
|
# @return [String]
|
341
|
-
|
342
|
-
|
361
|
+
# @raise [IOError] if connection is closed
|
362
|
+
def response(query, **options)
|
363
|
+
headers = options[:headers] || @headers
|
343
364
|
headers['Accept'] = options[:content_type] if options[:content_type]
|
344
365
|
request(query, headers) do |response|
|
345
366
|
case response
|
@@ -359,7 +380,7 @@ module SPARQL
|
|
359
380
|
# @param [Net::HTTPSuccess] response
|
360
381
|
# @param [Hash{Symbol => Object}] options
|
361
382
|
# @return [Object]
|
362
|
-
def parse_response(response, options
|
383
|
+
def parse_response(response, **options)
|
363
384
|
case options[:content_type] || response.content_type
|
364
385
|
when NilClass
|
365
386
|
response.body
|
@@ -374,7 +395,7 @@ module SPARQL
|
|
374
395
|
when RESULT_TSV
|
375
396
|
self.class.parse_tsv_bindings(response.body, nodes)
|
376
397
|
else
|
377
|
-
parse_rdf_serialization(response, options)
|
398
|
+
parse_rdf_serialization(response, **options)
|
378
399
|
end
|
379
400
|
end
|
380
401
|
|
@@ -411,9 +432,9 @@ module SPARQL
|
|
411
432
|
when :uri
|
412
433
|
RDF::URI.new(value['value'])
|
413
434
|
when :literal
|
414
|
-
RDF::Literal.new(value['value'], :
|
435
|
+
RDF::Literal.new(value['value'], datatype: value['datatype'], language: value['xml:lang'])
|
415
436
|
when :'typed-literal'
|
416
|
-
RDF::Literal.new(value['value'], :
|
437
|
+
RDF::Literal.new(value['value'], datatype: value['datatype'])
|
417
438
|
else nil
|
418
439
|
end
|
419
440
|
end
|
@@ -529,7 +550,7 @@ module SPARQL
|
|
529
550
|
when :literal
|
530
551
|
lang = value.respond_to?(:attr) ? value.attr('xml:lang') : value.attributes['xml:lang']
|
531
552
|
datatype = value.respond_to?(:attr) ? value.attr('datatype') : value.attributes['datatype']
|
532
|
-
RDF::Literal.new(value.text, :
|
553
|
+
RDF::Literal.new(value.text, language: lang, datatype: datatype)
|
533
554
|
else nil
|
534
555
|
end
|
535
556
|
end
|
@@ -538,12 +559,12 @@ module SPARQL
|
|
538
559
|
# @param [Net::HTTPSuccess] response
|
539
560
|
# @param [Hash{Symbol => Object}] options
|
540
561
|
# @return [RDF::Enumerable]
|
541
|
-
def parse_rdf_serialization(response, options
|
542
|
-
options = {:
|
562
|
+
def parse_rdf_serialization(response, **options)
|
563
|
+
options = {content_type: response.content_type} unless options[:content_type]
|
543
564
|
if reader = RDF::Reader.for(options)
|
544
565
|
reader.new(response.body)
|
545
566
|
else
|
546
|
-
raise RDF::ReaderError, "no
|
567
|
+
raise RDF::ReaderError, "no RDF reader was found for #{options}."
|
547
568
|
end
|
548
569
|
end
|
549
570
|
|
@@ -609,11 +630,15 @@ module SPARQL
|
|
609
630
|
# @private
|
610
631
|
def self.serialize_patterns(patterns, use_vars = false)
|
611
632
|
patterns.map do |pattern|
|
612
|
-
serialized_pattern =
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
633
|
+
serialized_pattern = case pattern
|
634
|
+
when SPARQL::Client::QueryElement then [pattern.to_s]
|
635
|
+
else
|
636
|
+
RDF::Statement.from(pattern).to_triple.each_with_index.map do |v, i|
|
637
|
+
if i == 1
|
638
|
+
SPARQL::Client.serialize_predicate(v)
|
639
|
+
else
|
640
|
+
SPARQL::Client.serialize_value(v, use_vars)
|
641
|
+
end
|
617
642
|
end
|
618
643
|
end
|
619
644
|
serialized_pattern.join(' ') + ' .'
|
@@ -654,7 +679,7 @@ module SPARQL
|
|
654
679
|
value = ENV['https_proxy']
|
655
680
|
proxy_url = URI.parse(value) unless value.nil? || value.empty?
|
656
681
|
end
|
657
|
-
klass = Net::HTTP::Persistent.new(self.class.to_s, proxy_url)
|
682
|
+
klass = Net::HTTP::Persistent.new(name: self.class.to_s, proxy: proxy_url)
|
658
683
|
klass.keep_alive = @options[:keep_alive] || 120
|
659
684
|
klass.read_timeout = @options[:read_timeout] || 60
|
660
685
|
klass
|
@@ -665,9 +690,15 @@ module SPARQL
|
|
665
690
|
#
|
666
691
|
# @param [String, #to_s] query
|
667
692
|
# @param [Hash{String => String}] headers
|
693
|
+
# HTTP Request headers
|
694
|
+
#
|
695
|
+
# Defaults `Accept` header based on available reader content types if triples are expected and to SPARQL result types otherwise, to allow for content negotiation based on available readers.
|
696
|
+
#
|
697
|
+
# Defaults `User-Agent` header, unless one is specified.
|
668
698
|
# @yield [response]
|
669
699
|
# @yieldparam [Net::HTTPResponse] response
|
670
700
|
# @return [Net::HTTPResponse]
|
701
|
+
# @raise [IOError] if connection is closed
|
671
702
|
# @see http://www.w3.org/TR/sparql11-protocol/#query-operation
|
672
703
|
def request(query, headers = {}, &block)
|
673
704
|
# Make sure an appropriate Accept header is present
|
@@ -678,6 +709,7 @@ module SPARQL
|
|
678
709
|
else
|
679
710
|
RESULT_ALL
|
680
711
|
end
|
712
|
+
headers['User-Agent'] ||= "Ruby SPARQL::Client/#{SPARQL::Client::VERSION}"
|
681
713
|
|
682
714
|
request = send("make_#{request_method(query)}_request", query, headers)
|
683
715
|
|
@@ -685,6 +717,7 @@ module SPARQL
|
|
685
717
|
|
686
718
|
pre_http_hook(request) if respond_to?(:pre_http_hook)
|
687
719
|
|
720
|
+
raise IOError, "Client has been closed" unless @http
|
688
721
|
response = @http.request(::URI.parse(url.to_s), request)
|
689
722
|
|
690
723
|
post_http_hook(response) if respond_to?(:post_http_hook)
|
@@ -693,8 +726,8 @@ module SPARQL
|
|
693
726
|
if response.kind_of? Net::HTTPRedirection
|
694
727
|
response = @http.request(::URI.parse(response['location']), request)
|
695
728
|
else
|
696
|
-
return block_given? ? block.call(response) : response
|
697
|
-
end
|
729
|
+
return block_given? ? block.call(response) : response
|
730
|
+
end
|
698
731
|
end
|
699
732
|
raise ServerError, "Infinite redirect at #{url}. Redirected more than 10 times."
|
700
733
|
end
|
@@ -717,7 +750,8 @@ module SPARQL
|
|
717
750
|
# @see http://www.w3.org/TR/sparql11-protocol/#query-via-get
|
718
751
|
def make_get_request(query, headers = {})
|
719
752
|
url = self.url.dup
|
720
|
-
url.query_values = (url.query_values || {}).merge(:
|
753
|
+
url.query_values = (url.query_values || {}).merge(query: query.to_s)
|
754
|
+
set_url_default_graph url unless @options[:graph].nil?
|
721
755
|
request = Net::HTTP::Get.new(url.request_uri, self.headers.merge(headers))
|
722
756
|
request
|
723
757
|
end
|
@@ -732,21 +766,67 @@ module SPARQL
|
|
732
766
|
# @see http://www.w3.org/TR/sparql11-protocol/#query-via-post-urlencoded
|
733
767
|
def make_post_request(query, headers = {})
|
734
768
|
if @alt_endpoint.nil?
|
735
|
-
|
769
|
+
url = self.url.dup
|
770
|
+
set_url_default_graph url unless @options[:graph].nil?
|
771
|
+
endpoint = url.request_uri
|
736
772
|
else
|
737
773
|
endpoint = @alt_endpoint
|
738
774
|
end
|
775
|
+
|
739
776
|
request = Net::HTTP::Post.new(endpoint, self.headers.merge(headers))
|
740
777
|
case (self.options[:protocol] || DEFAULT_PROTOCOL).to_s
|
741
778
|
when '1.1'
|
742
779
|
request['Content-Type'] = 'application/sparql-' + (@op || :query).to_s
|
743
780
|
request.body = query.to_s
|
744
781
|
when '1.0'
|
745
|
-
|
782
|
+
form_data = {(@op || :query) => query.to_s}
|
783
|
+
form_data.merge!(
|
784
|
+
{:'default-graph-uri' => @options[:graph]}
|
785
|
+
) if !@options[:graph].nil? && (@op.eql? :query)
|
786
|
+
form_data.merge!(
|
787
|
+
{:'using-graph-uri' => @options[:graph]}
|
788
|
+
) if !@options[:graph].nil? && (@op.eql? :update)
|
789
|
+
request.set_form_data(form_data)
|
746
790
|
else
|
747
791
|
raise ArgumentError, "unknown SPARQL protocol version: #{self.options[:protocol].inspect}"
|
748
792
|
end
|
749
793
|
request
|
750
794
|
end
|
795
|
+
|
796
|
+
##
|
797
|
+
# Setup url query parameter to use a specified default graph
|
798
|
+
#
|
799
|
+
# @see https://www.w3.org/TR/sparql11-protocol/#query-operation
|
800
|
+
# @see https://www.w3.org/TR/sparql11-protocol/#update-operation
|
801
|
+
def set_url_default_graph url
|
802
|
+
if @options[:graph].is_a? Array
|
803
|
+
graphs = @options[:graph].map {|graph|
|
804
|
+
CGI::escape(graph)
|
805
|
+
}
|
806
|
+
else
|
807
|
+
graphs = CGI::escape(@options[:graph])
|
808
|
+
end
|
809
|
+
case @op
|
810
|
+
when :query
|
811
|
+
url.query_values = (url.query_values || {})
|
812
|
+
.merge(:'default-graph-uri' => graphs)
|
813
|
+
when :update
|
814
|
+
url.query_values = (url.query_values || {})
|
815
|
+
.merge(:'using-graph-uri' => graphs)
|
816
|
+
end
|
817
|
+
end
|
818
|
+
|
819
|
+
# 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.
|
820
|
+
class QueryElement
|
821
|
+
attr_reader :elements
|
822
|
+
|
823
|
+
def initialize(*args)
|
824
|
+
@elements = args
|
825
|
+
end
|
826
|
+
|
827
|
+
def to_s
|
828
|
+
raise NotImplemented
|
829
|
+
end
|
830
|
+
end
|
751
831
|
end # Client
|
752
832
|
end # SPARQL
|