sparql-client 2.2.1 → 3.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/README.md +115 -82
- data/UNLICENSE +1 -1
- data/VERSION +1 -1
- data/lib/sparql/client.rb +141 -75
- data/lib/sparql/client/query.rb +163 -67
- data/lib/sparql/client/repository.rb +16 -17
- data/lib/sparql/client/update.rb +37 -38
- data/lib/sparql/client/version.rb +2 -2
- metadata +36 -55
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 512a63b7dcf77b57309f5c1cd734a4db60e84ba1977df4e3c8fab3529c0b96be
|
|
4
|
+
data.tar.gz: ea1e7413c3b92668960da2ad9ed632a5511d3ff334702631a29bb6bd3cf523b9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 185b11ee8c1597a3ed72a1161d101fccae20dcadb025fa333d0c956930d92c0ff2d98f979c9213cd8ceef73cb287fb7073b338aefa47afb51c075c307172906d
|
|
7
|
+
data.tar.gz: 68c871d80127d46298bddd60b4bf4df7326d67a00d1d8c522862b870846bb08326a27a44ca5aa15a9a813fd2bb4299ec98d69a3b4a554e2ad8b78f307b5432cf
|
data/README.md
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
This is a [Ruby][] implementation of a [SPARQL][] client for [RDF.rb][].
|
|
4
4
|
|
|
5
|
-
* <
|
|
5
|
+
* <https://ruby-rdf.github.com/sparql-client/>
|
|
6
6
|
|
|
7
|
-
[](
|
|
8
|
-
[](https://badge.fury.io/rb/sparql-client)
|
|
8
|
+
[](https://github.com/ruby-rdf/sparql-client/actions?query=workflow%3ACI)
|
|
9
9
|
[](https://coveralls.io/github/ruby-rdf/sparql-client?branch=master)
|
|
10
|
+
[](https://gitter.im/ruby-rdf/rdf)
|
|
10
11
|
|
|
11
12
|
## Features
|
|
12
13
|
|
|
@@ -18,89 +19,120 @@ This is a [Ruby][] implementation of a [SPARQL][] client for [RDF.rb][].
|
|
|
18
19
|
* Supports tuple result sets in both XML, JSON, CSV and TSV formats, with JSON being
|
|
19
20
|
the preferred default for content-negotiation purposes.
|
|
20
21
|
* Supports graph results in any RDF serialization format understood by RDF.rb.
|
|
21
|
-
* Returns results using the
|
|
22
|
+
* Returns results using the RDF.rb object model.
|
|
22
23
|
* Supports accessing endpoints as read/write [`RDF::Repository`][RDF::Repository]
|
|
23
24
|
instances {SPARQL::Client::Repository}.
|
|
24
25
|
|
|
25
26
|
## Examples
|
|
26
27
|
|
|
27
28
|
### Querying a remote SPARQL endpoint
|
|
28
|
-
require 'sparql/client'
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
```ruby
|
|
31
|
+
require 'sparql/client'
|
|
32
|
+
sparql = SPARQL::Client.new("http://dbpedia.org/sparql")
|
|
33
|
+
```
|
|
31
34
|
|
|
32
|
-
### Querying a
|
|
35
|
+
### Querying a remote SPARQL endpoint with a custom User-Agent
|
|
36
|
+
By default, SPARQL::Client adds a `User-Agent` field to requests, but applications may choose to provide their own, using the `headers` option:
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
```ruby
|
|
39
|
+
require 'sparql/client'
|
|
40
|
+
sparql = SPARQL::Client.new("http://dbpedia.org/sparql", headers: {'User-Agent' => 'MyBotName'})
|
|
41
|
+
```
|
|
36
42
|
|
|
37
|
-
|
|
43
|
+
### Querying a remote SPARQL endpoint with a specified default graph
|
|
38
44
|
|
|
39
|
-
|
|
45
|
+
```ruby
|
|
46
|
+
require 'sparql/client'
|
|
47
|
+
sparql = SPARQL::Client.new("http://dbpedia.org/sparql", { graph: "http://dbpedia.org" })
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
### Querying a `RDF::Repository` instance
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
require 'rdf/trig'
|
|
55
|
+
repository = RDF::Repository.load("http://example/dataset.trig")
|
|
56
|
+
sparql = SPARQL::Client.new(repository)
|
|
57
|
+
```
|
|
40
58
|
|
|
41
|
-
|
|
42
|
-
result = sparql.ask.whether([:s, :p, :o]).true?
|
|
59
|
+
### Executing a boolean query and outputting the result
|
|
43
60
|
|
|
44
|
-
|
|
61
|
+
```ruby
|
|
62
|
+
# ASK WHERE { ?s ?p ?o }
|
|
63
|
+
result = sparql.ask.whether([:s, :p, :o]).true?
|
|
64
|
+
puts result.inspect #=> true or false
|
|
65
|
+
```
|
|
45
66
|
|
|
46
67
|
### Executing a tuple query and iterating over the returned solutions
|
|
47
68
|
|
|
48
|
-
|
|
49
|
-
|
|
69
|
+
```ruby
|
|
70
|
+
# SELECT * WHERE { ?s ?p ?o } OFFSET 100 LIMIT 10
|
|
71
|
+
query = sparql.select.where([:s, :p, :o]).offset(100).limit(10)
|
|
50
72
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
73
|
+
query.each_solution do |solution|
|
|
74
|
+
puts solution.inspect
|
|
75
|
+
end
|
|
76
|
+
```
|
|
54
77
|
|
|
55
78
|
### Executing a graph query and iterating over the returned statements
|
|
56
79
|
|
|
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
80
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
81
|
+
```ruby
|
|
82
|
+
# CONSTRUCT { ?s ?p ?o } WHERE { ?s ?p ?o } LIMIT 10
|
|
83
|
+
query = sparql.construct([:s, :p, :o]).where([:s, :p, :o]).limit(10)
|
|
84
|
+
|
|
85
|
+
query.each_statement do |statement|
|
|
86
|
+
puts statement.inspect
|
|
87
|
+
end
|
|
88
|
+
```
|
|
63
89
|
|
|
64
90
|
### Executing an arbitrary textual SPARQL query string
|
|
65
91
|
|
|
66
|
-
|
|
92
|
+
```ruby
|
|
93
|
+
result = sparql.query("ASK WHERE { ?s ?p ?o }")
|
|
67
94
|
|
|
68
|
-
|
|
95
|
+
puts result.inspect #=> true or false
|
|
96
|
+
```
|
|
69
97
|
|
|
70
98
|
### Inserting data into a graph
|
|
71
99
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
100
|
+
```ruby
|
|
101
|
+
# INSERT DATA { <http://example.org/jhacker> <http://xmlns.com/foaf/0.1/name> "J. Random Hacker" .}
|
|
102
|
+
data = RDF::Graph.new do |graph|
|
|
103
|
+
graph << [RDF::URI('http://example.org/jhacker'), RDF::Vocab::FOAF.name, "J. Random Hacker"]
|
|
104
|
+
end
|
|
105
|
+
sparql.insert_data(data)
|
|
106
|
+
```
|
|
77
107
|
|
|
78
108
|
### Deleting data from a graph
|
|
79
109
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
110
|
+
```ruby
|
|
111
|
+
# DELETE DATA { <http://example.org/jhacker> <http://xmlns.com/foaf/0.1/name> "J. Random Hacker" .}
|
|
112
|
+
data = RDF::Graph.new do |graph|
|
|
113
|
+
graph << [RDF::URI('http://example.org/jhacker'), RDF::Vocab::FOAF.name, "J. Random Hacker"]
|
|
114
|
+
end
|
|
115
|
+
sparql.delete_data(data)
|
|
116
|
+
```
|
|
85
117
|
|
|
86
118
|
## Documentation
|
|
87
119
|
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
120
|
+
* [SPARQL::Client](https://www.rubydoc.info/github/ruby-rdf/sparql-client/SPARQL/Client)
|
|
121
|
+
* [SPARQL::Client::Query](https://www.rubydoc.info/github/ruby-rdf/sparql-client/SPARQL/Client/Query)
|
|
122
|
+
* [SPARQL::Client::Repository](https://www.rubydoc.info/github/ruby-rdf/sparql-client/SPARQL/Client/Repository)
|
|
123
|
+
* [SPARQL::Client::Update](https://www.rubydoc.info/github/ruby-rdf/sparql-client/SPARQL/Client/Update)
|
|
92
124
|
|
|
93
125
|
## Dependencies
|
|
94
126
|
|
|
95
|
-
* [Ruby](
|
|
96
|
-
* [RDF.rb](
|
|
97
|
-
* [Net::HTTP::Persistent](
|
|
98
|
-
* Soft dependency on [SPARQL](
|
|
99
|
-
* Soft dependency on [Nokogiri](
|
|
127
|
+
* [Ruby](https://ruby-lang.org/) (>= 2.4)
|
|
128
|
+
* [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.1)
|
|
129
|
+
* [Net::HTTP::Persistent](https://rubygems.org/gems/net-http-persistent) (~> 4.0, >= 4.0.1)
|
|
130
|
+
* Soft dependency on [SPARQL](https://rubygems.org/gems/sparql) (~> 3.1)
|
|
131
|
+
* Soft dependency on [Nokogiri](https://rubygems.org/gems/nokogiri) (>= 1.11)
|
|
100
132
|
|
|
101
133
|
## Installation
|
|
102
134
|
|
|
103
|
-
The recommended installation method is via [RubyGems](
|
|
135
|
+
The recommended installation method is via [RubyGems](https://rubygems.org/).
|
|
104
136
|
To install the latest official release of the `SPARQL::Client` gem, do:
|
|
105
137
|
|
|
106
138
|
% [sudo] gem install sparql-client
|
|
@@ -114,31 +146,31 @@ To get a local working copy of the development repository, do:
|
|
|
114
146
|
Alternatively, download the latest development version as a tarball as
|
|
115
147
|
follows:
|
|
116
148
|
|
|
117
|
-
% wget
|
|
149
|
+
% wget https://github.com/ruby-rdf/sparql-client/tarball/master
|
|
118
150
|
|
|
119
151
|
## Mailing List
|
|
120
152
|
|
|
121
|
-
* <
|
|
153
|
+
* <https://lists.w3.org/Archives/Public/public-rdf-ruby/>
|
|
122
154
|
|
|
123
155
|
## Authors
|
|
124
156
|
|
|
125
|
-
* [Arto Bendiken](
|
|
126
|
-
* [Ben Lavender](
|
|
127
|
-
* [Gregg Kellogg](
|
|
157
|
+
* [Arto Bendiken](https://github.com/artob) - <https://ar.to/>
|
|
158
|
+
* [Ben Lavender](https://github.com/bhuga) - <https://bhuga.net/>
|
|
159
|
+
* [Gregg Kellogg](https://github.com/gkellogg) - <https://greggkellogg.net/>
|
|
128
160
|
|
|
129
161
|
## Contributors
|
|
130
162
|
|
|
131
|
-
* [Christoph Badura](
|
|
132
|
-
* [James Hetherington](
|
|
133
|
-
* [Gabriel Horner](
|
|
134
|
-
* [Nicholas Humfrey](
|
|
135
|
-
* [Fumihiro Kato](
|
|
136
|
-
* [David Nielsen](
|
|
137
|
-
* [Thamaraiselvan Poomalai](
|
|
138
|
-
* [Michael Sokol](
|
|
139
|
-
* [Yves Raimond](
|
|
140
|
-
* [Thomas Feron](
|
|
141
|
-
* [Nick Gottlieb](
|
|
163
|
+
* [Christoph Badura](https://github.com/bad) - <https://github.com/bad>
|
|
164
|
+
* [James Hetherington](https://github.com/jamespjh) - <https://twitter.com/jamespjh>
|
|
165
|
+
* [Gabriel Horner](https://github.com/cldwalker) - <https://tagaholic.me/>
|
|
166
|
+
* [Nicholas Humfrey](https://github.com/njh) - <https://www.aelius.com/njh/>
|
|
167
|
+
* [Fumihiro Kato](https://github.com/fumi) - <https://fumi.me/>
|
|
168
|
+
* [David Nielsen](https://github.com/drankard) - <https://github.com/drankard>
|
|
169
|
+
* [Thamaraiselvan Poomalai](https://github.com/selvan) - <https://softonaut.blogspot.com/>
|
|
170
|
+
* [Michael Sokol](https://github.com/mikaa123) - <https://sokolmichael.com/>
|
|
171
|
+
* [Yves Raimond](https://github.com/moustaki) - <https://moustaki.org/>
|
|
172
|
+
* [Thomas Feron](https://github.com/thoferon) - <https://github.com/thoferon>
|
|
173
|
+
* [Nick Gottlieb](https://github.com/ngottlieb) - <https://www.nicholasgottlieb.com>
|
|
142
174
|
|
|
143
175
|
## Contributing
|
|
144
176
|
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.
|
|
@@ -153,31 +185,32 @@ This repository uses [Git Flow](https://github.com/nvie/gitflow) to mange develo
|
|
|
153
185
|
list in the the `README`. Alphabetical order applies.
|
|
154
186
|
* Do note that in order for us to merge any non-trivial changes (as a rule
|
|
155
187
|
of thumb, additions larger than about 15 lines of code), we need an
|
|
156
|
-
explicit [public domain dedication][PDD] on record from you
|
|
188
|
+
explicit [public domain dedication][PDD] on record from you,
|
|
189
|
+
which you will be asked to agree to on the first commit to a repo within the organization.
|
|
190
|
+
Note that the agreement applies to all repos in the [Ruby RDF](https://github.com/ruby-rdf/) organization.
|
|
157
191
|
|
|
158
192
|
## Resources
|
|
159
193
|
|
|
160
|
-
* <
|
|
161
|
-
* <
|
|
162
|
-
* <
|
|
163
|
-
* <
|
|
164
|
-
* <
|
|
194
|
+
* <https://ruby-rdf.github.com/sparql-client/>
|
|
195
|
+
* <https://github.com/ruby-rdf/sparql-client>
|
|
196
|
+
* <https://rubygems.org/gems/sparql-client>
|
|
197
|
+
* <https://raa.ruby-lang.org/project/sparql-client/>
|
|
198
|
+
* <https://www.ohloh.net/p/rdf>
|
|
165
199
|
|
|
166
200
|
## License
|
|
167
201
|
|
|
168
202
|
This is free and unencumbered public domain software. For more information,
|
|
169
|
-
see <
|
|
170
|
-
|
|
171
|
-
[Ruby]:
|
|
172
|
-
[RDF]:
|
|
173
|
-
[SPARQL]:
|
|
174
|
-
[SPARQL JSON]:
|
|
175
|
-
[RDF.rb]:
|
|
176
|
-
[RDF
|
|
177
|
-
[
|
|
178
|
-
[DSL]: http://en.wikipedia.org/wiki/Domain-specific_language
|
|
203
|
+
see <https://unlicense.org/> or the accompanying {file:UNLICENSE} file.
|
|
204
|
+
|
|
205
|
+
[Ruby]: https://ruby-lang.org/
|
|
206
|
+
[RDF]: https://www.w3.org/RDF/
|
|
207
|
+
[SPARQL]: https://en.wikipedia.org/wiki/SPARQL
|
|
208
|
+
[SPARQL JSON]: https://www.w3.org/TR/rdf-sparql-json-res/
|
|
209
|
+
[RDF.rb]: https://rubygems.org/gems/rdf
|
|
210
|
+
[RDF::Repository]: https://rubydoc.info/github/ruby-rdf/rdf/RDF/Repository
|
|
211
|
+
[DSL]: https://en.wikipedia.org/wiki/Domain-specific_language
|
|
179
212
|
"domain-specific language"
|
|
180
|
-
[YARD]:
|
|
181
|
-
[YARD-GS]:
|
|
182
|
-
[PDD]:
|
|
183
|
-
[Backports]:
|
|
213
|
+
[YARD]: https://yardoc.org/
|
|
214
|
+
[YARD-GS]: https://rubydoc.info/docs/yard/file/docs/GettingStarted.md
|
|
215
|
+
[PDD]: https://unlicense.org/#unlicensing-contributions
|
|
216
|
+
[Backports]: https://rubygems.org/gems/backports
|
data/UNLICENSE
CHANGED
|
@@ -21,4 +21,4 @@ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
|
21
21
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
22
22
|
OTHER DEALINGS IN THE SOFTWARE.
|
|
23
23
|
|
|
24
|
-
For more information, please refer to <
|
|
24
|
+
For more information, please refer to <https://unlicense.org/>
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
3.1.2
|
data/lib/sparql/client.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
require 'net/http/persistent' # @see
|
|
2
|
-
require 'rdf' # @see
|
|
3
|
-
require 'rdf/ntriples' # @see
|
|
1
|
+
require 'net/http/persistent' # @see https://rubygems.org/gems/net-http-persistent
|
|
2
|
+
require 'rdf' # @see https://rubygems.org/gems/rdf
|
|
3
|
+
require 'rdf/ntriples' # @see https://rubygems.org/gems/rdf
|
|
4
4
|
begin
|
|
5
5
|
require 'nokogiri'
|
|
6
6
|
rescue LoadError
|
|
@@ -11,10 +11,10 @@ module SPARQL
|
|
|
11
11
|
##
|
|
12
12
|
# A SPARQL 1.0/1.1 client for RDF.rb.
|
|
13
13
|
#
|
|
14
|
-
# @see
|
|
15
|
-
# @see
|
|
16
|
-
# @see
|
|
17
|
-
# @see
|
|
14
|
+
# @see https://www.w3.org/TR/sparql11-query/
|
|
15
|
+
# @see https://www.w3.org/TR/sparql11-protocol/
|
|
16
|
+
# @see https://www.w3.org/TR/sparql11-results-json/
|
|
17
|
+
# @see https://www.w3.org/TR/sparql11-results-csv-tsv/
|
|
18
18
|
class Client
|
|
19
19
|
autoload :Query, 'sparql/client/query'
|
|
20
20
|
autoload :Repository, 'sparql/client/repository'
|
|
@@ -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, self.class.finalize(@http))
|
|
98
106
|
end
|
|
99
107
|
|
|
100
108
|
if block_given?
|
|
@@ -105,13 +113,30 @@ module SPARQL
|
|
|
105
113
|
end
|
|
106
114
|
end
|
|
107
115
|
|
|
116
|
+
# Close the http connection when object is deallocated
|
|
117
|
+
def self.finalize(klass)
|
|
118
|
+
proc do
|
|
119
|
+
klass.shutdown if klass.respond_to?(:shutdown)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
##
|
|
124
|
+
# Closes a client instance by finishing the connection.
|
|
125
|
+
# 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.
|
|
126
|
+
# @return [void] `self`
|
|
127
|
+
def close
|
|
128
|
+
@http.shutdown if @http
|
|
129
|
+
@http = nil
|
|
130
|
+
self
|
|
131
|
+
end
|
|
132
|
+
|
|
108
133
|
##
|
|
109
134
|
# Executes a boolean `ASK` query.
|
|
110
135
|
#
|
|
111
136
|
# @param (see Query.ask)
|
|
112
137
|
# @return [Query]
|
|
113
|
-
def ask(*args)
|
|
114
|
-
call_query_method(:ask, *args)
|
|
138
|
+
def ask(*args, **options)
|
|
139
|
+
call_query_method(:ask, *args, **options)
|
|
115
140
|
end
|
|
116
141
|
|
|
117
142
|
##
|
|
@@ -119,8 +144,8 @@ module SPARQL
|
|
|
119
144
|
#
|
|
120
145
|
# @param (see Query.select)
|
|
121
146
|
# @return [Query]
|
|
122
|
-
def select(*args)
|
|
123
|
-
call_query_method(:select, *args)
|
|
147
|
+
def select(*args, **options)
|
|
148
|
+
call_query_method(:select, *args, **options)
|
|
124
149
|
end
|
|
125
150
|
|
|
126
151
|
##
|
|
@@ -128,8 +153,8 @@ module SPARQL
|
|
|
128
153
|
#
|
|
129
154
|
# @param (see Query.describe)
|
|
130
155
|
# @return [Query]
|
|
131
|
-
def describe(*args)
|
|
132
|
-
call_query_method(:describe, *args)
|
|
156
|
+
def describe(*args, **options)
|
|
157
|
+
call_query_method(:describe, *args, **options)
|
|
133
158
|
end
|
|
134
159
|
|
|
135
160
|
##
|
|
@@ -137,8 +162,8 @@ module SPARQL
|
|
|
137
162
|
#
|
|
138
163
|
# @param (see Query.construct)
|
|
139
164
|
# @return [Query]
|
|
140
|
-
def construct(*args)
|
|
141
|
-
call_query_method(:construct, *args)
|
|
165
|
+
def construct(*args, **options)
|
|
166
|
+
call_query_method(:construct, *args, **options)
|
|
142
167
|
end
|
|
143
168
|
|
|
144
169
|
##
|
|
@@ -161,15 +186,15 @@ module SPARQL
|
|
|
161
186
|
# client.insert_data(data)
|
|
162
187
|
#
|
|
163
188
|
# @example Inserting data into a named graph
|
|
164
|
-
# client.insert_data(data, :
|
|
189
|
+
# client.insert_data(data, graph: "http://example.org/")
|
|
165
190
|
#
|
|
166
191
|
# @param [RDF::Enumerable] data
|
|
167
192
|
# @param [Hash{Symbol => Object}] options
|
|
168
193
|
# @option options [RDF::URI, String] :graph
|
|
169
194
|
# @return [void] `self`
|
|
170
|
-
# @see
|
|
171
|
-
def insert_data(data, options
|
|
172
|
-
self.update(Update::InsertData.new(data, options))
|
|
195
|
+
# @see https://www.w3.org/TR/sparql11-update/#insertData
|
|
196
|
+
def insert_data(data, **options)
|
|
197
|
+
self.update(Update::InsertData.new(data, **options))
|
|
173
198
|
end
|
|
174
199
|
|
|
175
200
|
##
|
|
@@ -182,15 +207,15 @@ module SPARQL
|
|
|
182
207
|
# client.delete_data(data)
|
|
183
208
|
#
|
|
184
209
|
# @example Deleting data from a named graph
|
|
185
|
-
# client.delete_data(data, :
|
|
210
|
+
# client.delete_data(data, graph: "http://example.org/")
|
|
186
211
|
#
|
|
187
212
|
# @param [RDF::Enumerable] data
|
|
188
213
|
# @param [Hash{Symbol => Object}] options
|
|
189
214
|
# @option options [RDF::URI, String] :graph
|
|
190
215
|
# @return [void] `self`
|
|
191
|
-
# @see
|
|
192
|
-
def delete_data(data, options
|
|
193
|
-
self.update(Update::DeleteData.new(data, options))
|
|
216
|
+
# @see https://www.w3.org/TR/sparql11-update/#deleteData
|
|
217
|
+
def delete_data(data, **options)
|
|
218
|
+
self.update(Update::DeleteData.new(data, **options))
|
|
194
219
|
end
|
|
195
220
|
|
|
196
221
|
##
|
|
@@ -204,9 +229,9 @@ module SPARQL
|
|
|
204
229
|
# @param [Hash{Symbol => Object}] options
|
|
205
230
|
# @option options [RDF::URI, String] :graph
|
|
206
231
|
# @return [void] `self`
|
|
207
|
-
# @see
|
|
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))
|
|
232
|
+
# @see https://www.w3.org/TR/sparql11-update/#deleteInsert
|
|
233
|
+
def delete_insert(delete_graph, insert_graph = nil, where_graph = nil, **options)
|
|
234
|
+
self.update(Update::DeleteInsert.new(delete_graph, insert_graph, where_graph, **options))
|
|
210
235
|
end
|
|
211
236
|
|
|
212
237
|
##
|
|
@@ -221,9 +246,9 @@ module SPARQL
|
|
|
221
246
|
# @param [Hash{Symbol => Object}] options
|
|
222
247
|
# @option options [Boolean] :silent
|
|
223
248
|
# @return [void] `self`
|
|
224
|
-
# @see
|
|
225
|
-
def clear_graph(graph_uri, options
|
|
226
|
-
self.clear(:graph, graph_uri, options)
|
|
249
|
+
# @see https://www.w3.org/TR/sparql11-update/#clear
|
|
250
|
+
def clear_graph(graph_uri, **options)
|
|
251
|
+
self.clear(:graph, graph_uri, **options)
|
|
227
252
|
end
|
|
228
253
|
|
|
229
254
|
##
|
|
@@ -249,23 +274,23 @@ module SPARQL
|
|
|
249
274
|
# @option options [Boolean] :silent
|
|
250
275
|
# @return [void] `self`
|
|
251
276
|
#
|
|
252
|
-
# @overload clear(what, *arguments, options
|
|
277
|
+
# @overload clear(what, *arguments, **options)
|
|
253
278
|
# @param [Symbol, #to_sym] what
|
|
254
279
|
# @param [Array] arguments splat of other arguments to {Update::Clear}.
|
|
255
280
|
# @param [Hash{Symbol => Object}] options
|
|
256
281
|
# @option options [Boolean] :silent
|
|
257
282
|
# @return [void] `self`
|
|
258
283
|
#
|
|
259
|
-
# @see
|
|
284
|
+
# @see https://www.w3.org/TR/sparql11-update/#clear
|
|
260
285
|
def clear(what, *arguments)
|
|
261
286
|
self.update(Update::Clear.new(what, *arguments))
|
|
262
287
|
end
|
|
263
288
|
|
|
264
289
|
##
|
|
265
290
|
# @private
|
|
266
|
-
def call_query_method(meth, *args)
|
|
291
|
+
def call_query_method(meth, *args, **options)
|
|
267
292
|
client = self
|
|
268
|
-
result = Query.send(meth, *args)
|
|
293
|
+
result = Query.send(meth, *args, **options)
|
|
269
294
|
(class << result; self; end).send(:define_method, :execute) do
|
|
270
295
|
client.query(self)
|
|
271
296
|
end
|
|
@@ -288,21 +313,22 @@ module SPARQL
|
|
|
288
313
|
# @option options [String] :content_type
|
|
289
314
|
# @option options [Hash] :headers
|
|
290
315
|
# @return [Array<RDF::Query::Solution>]
|
|
291
|
-
# @
|
|
292
|
-
|
|
316
|
+
# @raise [IOError] if connection is closed
|
|
317
|
+
# @see https://www.w3.org/TR/sparql11-protocol/#query-operation
|
|
318
|
+
def query(query, **options)
|
|
293
319
|
@op = :query
|
|
294
320
|
@alt_endpoint = options[:endpoint]
|
|
295
321
|
case @url
|
|
296
322
|
when RDF::Queryable
|
|
297
323
|
require 'sparql' unless defined?(::SPARQL::Grammar)
|
|
298
324
|
begin
|
|
299
|
-
SPARQL.execute(query, @url, options)
|
|
325
|
+
SPARQL.execute(query, @url, optimize: true, **options)
|
|
300
326
|
rescue SPARQL::MalformedQuery
|
|
301
327
|
$stderr.puts "error running #{query}: #{$!}"
|
|
302
328
|
raise
|
|
303
329
|
end
|
|
304
330
|
else
|
|
305
|
-
parse_response(response(query, options), options)
|
|
331
|
+
parse_response(response(query, **options), **options)
|
|
306
332
|
end
|
|
307
333
|
end
|
|
308
334
|
|
|
@@ -315,16 +341,17 @@ module SPARQL
|
|
|
315
341
|
# @option options [String] :content_type
|
|
316
342
|
# @option options [Hash] :headers
|
|
317
343
|
# @return [void] `self`
|
|
318
|
-
# @
|
|
319
|
-
|
|
344
|
+
# @raise [IOError] if connection is closed
|
|
345
|
+
# @see https://www.w3.org/TR/sparql11-protocol/#update-operation
|
|
346
|
+
def update(query, **options)
|
|
320
347
|
@op = :update
|
|
321
348
|
@alt_endpoint = options[:endpoint]
|
|
322
349
|
case @url
|
|
323
350
|
when RDF::Queryable
|
|
324
351
|
require 'sparql' unless defined?(::SPARQL::Grammar)
|
|
325
|
-
SPARQL.execute(query, @url,
|
|
352
|
+
SPARQL.execute(query, @url, update: true, optimize: true, **options)
|
|
326
353
|
else
|
|
327
|
-
response(query, options)
|
|
354
|
+
response(query, **options)
|
|
328
355
|
end
|
|
329
356
|
self
|
|
330
357
|
end
|
|
@@ -338,8 +365,9 @@ module SPARQL
|
|
|
338
365
|
# @option options [String] :content_type
|
|
339
366
|
# @option options [Hash] :headers
|
|
340
367
|
# @return [String]
|
|
341
|
-
|
|
342
|
-
|
|
368
|
+
# @raise [IOError] if connection is closed
|
|
369
|
+
def response(query, **options)
|
|
370
|
+
headers = options[:headers] || @headers
|
|
343
371
|
headers['Accept'] = options[:content_type] if options[:content_type]
|
|
344
372
|
request(query, headers) do |response|
|
|
345
373
|
case response
|
|
@@ -359,7 +387,7 @@ module SPARQL
|
|
|
359
387
|
# @param [Net::HTTPSuccess] response
|
|
360
388
|
# @param [Hash{Symbol => Object}] options
|
|
361
389
|
# @return [Object]
|
|
362
|
-
def parse_response(response, options
|
|
390
|
+
def parse_response(response, **options)
|
|
363
391
|
case options[:content_type] || response.content_type
|
|
364
392
|
when NilClass
|
|
365
393
|
response.body
|
|
@@ -374,14 +402,14 @@ module SPARQL
|
|
|
374
402
|
when RESULT_TSV
|
|
375
403
|
self.class.parse_tsv_bindings(response.body, nodes)
|
|
376
404
|
else
|
|
377
|
-
parse_rdf_serialization(response, options)
|
|
405
|
+
parse_rdf_serialization(response, **options)
|
|
378
406
|
end
|
|
379
407
|
end
|
|
380
408
|
|
|
381
409
|
##
|
|
382
410
|
# @param [String, Hash] json
|
|
383
411
|
# @return [<RDF::Query::Solutions>]
|
|
384
|
-
# @see
|
|
412
|
+
# @see https://www.w3.org/TR/rdf-sparql-json-res/#results
|
|
385
413
|
def self.parse_json_bindings(json, nodes = {})
|
|
386
414
|
require 'json' unless defined?(::JSON)
|
|
387
415
|
json = JSON.parse(json.to_s) unless json.is_a?(Hash)
|
|
@@ -402,8 +430,8 @@ module SPARQL
|
|
|
402
430
|
##
|
|
403
431
|
# @param [Hash{String => String}] value
|
|
404
432
|
# @return [RDF::Value]
|
|
405
|
-
# @see
|
|
406
|
-
# @see
|
|
433
|
+
# @see https://www.w3.org/TR/sparql11-results-json/#select-encode-terms
|
|
434
|
+
# @see https://www.w3.org/TR/rdf-sparql-json-res/#variable-binding-results
|
|
407
435
|
def self.parse_json_value(value, nodes = {})
|
|
408
436
|
case value['type'].to_sym
|
|
409
437
|
when :bnode
|
|
@@ -411,9 +439,9 @@ module SPARQL
|
|
|
411
439
|
when :uri
|
|
412
440
|
RDF::URI.new(value['value'])
|
|
413
441
|
when :literal
|
|
414
|
-
RDF::Literal.new(value['value'], :
|
|
442
|
+
RDF::Literal.new(value['value'], datatype: value['datatype'], language: value['xml:lang'])
|
|
415
443
|
when :'typed-literal'
|
|
416
|
-
RDF::Literal.new(value['value'], :
|
|
444
|
+
RDF::Literal.new(value['value'], datatype: value['datatype'])
|
|
417
445
|
else nil
|
|
418
446
|
end
|
|
419
447
|
end
|
|
@@ -421,7 +449,7 @@ module SPARQL
|
|
|
421
449
|
##
|
|
422
450
|
# @param [String, Array<Array<String>>] csv
|
|
423
451
|
# @return [<RDF::Query::Solutions>]
|
|
424
|
-
# @see
|
|
452
|
+
# @see https://www.w3.org/TR/sparql11-results-csv-tsv/
|
|
425
453
|
def self.parse_csv_bindings(csv, nodes = {})
|
|
426
454
|
require 'csv' unless defined?(::CSV)
|
|
427
455
|
csv = CSV.parse(csv.to_s) unless csv.is_a?(Array)
|
|
@@ -445,7 +473,7 @@ module SPARQL
|
|
|
445
473
|
##
|
|
446
474
|
# @param [String, Array<Array<String>>] tsv
|
|
447
475
|
# @return [<RDF::Query::Solutions>]
|
|
448
|
-
# @see
|
|
476
|
+
# @see https://www.w3.org/TR/sparql11-results-csv-tsv/
|
|
449
477
|
def self.parse_tsv_bindings(tsv, nodes = {})
|
|
450
478
|
tsv = tsv.lines.map {|l| l.chomp.split("\t")} unless tsv.is_a?(Array)
|
|
451
479
|
vars = tsv.shift.map {|h| h.sub(/^\?/, '')}
|
|
@@ -474,7 +502,7 @@ module SPARQL
|
|
|
474
502
|
##
|
|
475
503
|
# @param [String, IO, Nokogiri::XML::Node, REXML::Element] xml
|
|
476
504
|
# @return [<RDF::Query::Solutions>]
|
|
477
|
-
# @see
|
|
505
|
+
# @see https://www.w3.org/TR/rdf-sparql-json-res/#results
|
|
478
506
|
def self.parse_xml_bindings(xml, nodes = {})
|
|
479
507
|
xml.force_encoding(::Encoding::UTF_8) if xml.respond_to?(:force_encoding)
|
|
480
508
|
|
|
@@ -519,7 +547,7 @@ module SPARQL
|
|
|
519
547
|
##
|
|
520
548
|
# @param [Nokogiri::XML::Element, REXML::Element] value
|
|
521
549
|
# @return [RDF::Value]
|
|
522
|
-
# @see
|
|
550
|
+
# @see https://www.w3.org/TR/rdf-sparql-json-res/#variable-binding-results
|
|
523
551
|
def self.parse_xml_value(value, nodes = {})
|
|
524
552
|
case value.name.to_sym
|
|
525
553
|
when :bnode
|
|
@@ -529,7 +557,7 @@ module SPARQL
|
|
|
529
557
|
when :literal
|
|
530
558
|
lang = value.respond_to?(:attr) ? value.attr('xml:lang') : value.attributes['xml:lang']
|
|
531
559
|
datatype = value.respond_to?(:attr) ? value.attr('datatype') : value.attributes['datatype']
|
|
532
|
-
RDF::Literal.new(value.text, :
|
|
560
|
+
RDF::Literal.new(value.text, language: lang, datatype: datatype)
|
|
533
561
|
else nil
|
|
534
562
|
end
|
|
535
563
|
end
|
|
@@ -538,12 +566,12 @@ module SPARQL
|
|
|
538
566
|
# @param [Net::HTTPSuccess] response
|
|
539
567
|
# @param [Hash{Symbol => Object}] options
|
|
540
568
|
# @return [RDF::Enumerable]
|
|
541
|
-
def parse_rdf_serialization(response, options
|
|
542
|
-
options = {:
|
|
569
|
+
def parse_rdf_serialization(response, **options)
|
|
570
|
+
options = {content_type: response.content_type} unless options[:content_type]
|
|
543
571
|
if reader = RDF::Reader.for(options)
|
|
544
572
|
reader.new(response.body)
|
|
545
573
|
else
|
|
546
|
-
raise RDF::ReaderError, "no
|
|
574
|
+
raise RDF::ReaderError, "no RDF reader was found for #{options}."
|
|
547
575
|
end
|
|
548
576
|
end
|
|
549
577
|
|
|
@@ -615,7 +643,7 @@ module SPARQL
|
|
|
615
643
|
RDF::Statement.from(pattern).to_triple.each_with_index.map do |v, i|
|
|
616
644
|
if i == 1
|
|
617
645
|
SPARQL::Client.serialize_predicate(v)
|
|
618
|
-
|
|
646
|
+
else
|
|
619
647
|
SPARQL::Client.serialize_value(v, use_vars)
|
|
620
648
|
end
|
|
621
649
|
end
|
|
@@ -658,11 +686,7 @@ module SPARQL
|
|
|
658
686
|
value = ENV['https_proxy']
|
|
659
687
|
proxy_url = URI.parse(value) unless value.nil? || value.empty?
|
|
660
688
|
end
|
|
661
|
-
klass =
|
|
662
|
-
Net::HTTP::Persistent.new(name: self.class.to_s, proxy: proxy_url)
|
|
663
|
-
else
|
|
664
|
-
Net::HTTP::Persistent.new(self.class.to_s, proxy_url)
|
|
665
|
-
end
|
|
689
|
+
klass = Net::HTTP::Persistent.new(name: self.class.to_s, proxy: proxy_url)
|
|
666
690
|
klass.keep_alive = @options[:keep_alive] || 120
|
|
667
691
|
klass.read_timeout = @options[:read_timeout] || 60
|
|
668
692
|
klass
|
|
@@ -673,10 +697,16 @@ module SPARQL
|
|
|
673
697
|
#
|
|
674
698
|
# @param [String, #to_s] query
|
|
675
699
|
# @param [Hash{String => String}] headers
|
|
700
|
+
# HTTP Request headers
|
|
701
|
+
#
|
|
702
|
+
# 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.
|
|
703
|
+
#
|
|
704
|
+
# Defaults `User-Agent` header, unless one is specified.
|
|
676
705
|
# @yield [response]
|
|
677
706
|
# @yieldparam [Net::HTTPResponse] response
|
|
678
707
|
# @return [Net::HTTPResponse]
|
|
679
|
-
# @
|
|
708
|
+
# @raise [IOError] if connection is closed
|
|
709
|
+
# @see https://www.w3.org/TR/sparql11-protocol/#query-operation
|
|
680
710
|
def request(query, headers = {}, &block)
|
|
681
711
|
# Make sure an appropriate Accept header is present
|
|
682
712
|
headers['Accept'] ||= if (query.respond_to?(:expects_statements?) ?
|
|
@@ -686,6 +716,7 @@ module SPARQL
|
|
|
686
716
|
else
|
|
687
717
|
RESULT_ALL
|
|
688
718
|
end
|
|
719
|
+
headers['User-Agent'] ||= "Ruby SPARQL::Client/#{SPARQL::Client::VERSION}"
|
|
689
720
|
|
|
690
721
|
request = send("make_#{request_method(query)}_request", query, headers)
|
|
691
722
|
|
|
@@ -693,6 +724,7 @@ module SPARQL
|
|
|
693
724
|
|
|
694
725
|
pre_http_hook(request) if respond_to?(:pre_http_hook)
|
|
695
726
|
|
|
727
|
+
raise IOError, "Client has been closed" unless @http
|
|
696
728
|
response = @http.request(::URI.parse(url.to_s), request)
|
|
697
729
|
|
|
698
730
|
post_http_hook(response) if respond_to?(:post_http_hook)
|
|
@@ -701,8 +733,8 @@ module SPARQL
|
|
|
701
733
|
if response.kind_of? Net::HTTPRedirection
|
|
702
734
|
response = @http.request(::URI.parse(response['location']), request)
|
|
703
735
|
else
|
|
704
|
-
return block_given? ? block.call(response) : response
|
|
705
|
-
end
|
|
736
|
+
return block_given? ? block.call(response) : response
|
|
737
|
+
end
|
|
706
738
|
end
|
|
707
739
|
raise ServerError, "Infinite redirect at #{url}. Redirected more than 10 times."
|
|
708
740
|
end
|
|
@@ -722,10 +754,11 @@ module SPARQL
|
|
|
722
754
|
# @param [String, #to_s] query
|
|
723
755
|
# @param [Hash{String => String}] headers
|
|
724
756
|
# @return [Net::HTTPRequest]
|
|
725
|
-
# @see
|
|
757
|
+
# @see https://www.w3.org/TR/sparql11-protocol/#query-via-get
|
|
726
758
|
def make_get_request(query, headers = {})
|
|
727
759
|
url = self.url.dup
|
|
728
|
-
url.query_values = (url.query_values || {}).merge(:
|
|
760
|
+
url.query_values = (url.query_values || {}).merge(query: query.to_s)
|
|
761
|
+
set_url_default_graph url unless @options[:graph].nil?
|
|
729
762
|
request = Net::HTTP::Get.new(url.request_uri, self.headers.merge(headers))
|
|
730
763
|
request
|
|
731
764
|
end
|
|
@@ -736,27 +769,60 @@ module SPARQL
|
|
|
736
769
|
# @param [String, #to_s] query
|
|
737
770
|
# @param [Hash{String => String}] headers
|
|
738
771
|
# @return [Net::HTTPRequest]
|
|
739
|
-
# @see
|
|
740
|
-
# @see
|
|
772
|
+
# @see https://www.w3.org/TR/sparql11-protocol/#query-via-post-direct
|
|
773
|
+
# @see https://www.w3.org/TR/sparql11-protocol/#query-via-post-urlencoded
|
|
741
774
|
def make_post_request(query, headers = {})
|
|
742
775
|
if @alt_endpoint.nil?
|
|
743
|
-
|
|
776
|
+
url = self.url.dup
|
|
777
|
+
set_url_default_graph url unless @options[:graph].nil?
|
|
778
|
+
endpoint = url.request_uri
|
|
744
779
|
else
|
|
745
780
|
endpoint = @alt_endpoint
|
|
746
781
|
end
|
|
782
|
+
|
|
747
783
|
request = Net::HTTP::Post.new(endpoint, self.headers.merge(headers))
|
|
748
784
|
case (self.options[:protocol] || DEFAULT_PROTOCOL).to_s
|
|
749
785
|
when '1.1'
|
|
750
786
|
request['Content-Type'] = 'application/sparql-' + (@op || :query).to_s
|
|
751
787
|
request.body = query.to_s
|
|
752
788
|
when '1.0'
|
|
753
|
-
|
|
789
|
+
form_data = {(@op || :query) => query.to_s}
|
|
790
|
+
form_data.merge!(
|
|
791
|
+
{:'default-graph-uri' => @options[:graph]}
|
|
792
|
+
) if !@options[:graph].nil? && (@op.eql? :query)
|
|
793
|
+
form_data.merge!(
|
|
794
|
+
{:'using-graph-uri' => @options[:graph]}
|
|
795
|
+
) if !@options[:graph].nil? && (@op.eql? :update)
|
|
796
|
+
request.set_form_data(form_data)
|
|
754
797
|
else
|
|
755
798
|
raise ArgumentError, "unknown SPARQL protocol version: #{self.options[:protocol].inspect}"
|
|
756
799
|
end
|
|
757
800
|
request
|
|
758
801
|
end
|
|
759
802
|
|
|
803
|
+
##
|
|
804
|
+
# Setup url query parameter to use a specified default graph
|
|
805
|
+
#
|
|
806
|
+
# @see https://www.w3.org/TR/sparql11-protocol/#query-operation
|
|
807
|
+
# @see https://www.w3.org/TR/sparql11-protocol/#update-operation
|
|
808
|
+
def set_url_default_graph url
|
|
809
|
+
if @options[:graph].is_a? Array
|
|
810
|
+
graphs = @options[:graph].map {|graph|
|
|
811
|
+
CGI::escape(graph)
|
|
812
|
+
}
|
|
813
|
+
else
|
|
814
|
+
graphs = CGI::escape(@options[:graph])
|
|
815
|
+
end
|
|
816
|
+
case @op
|
|
817
|
+
when :query
|
|
818
|
+
url.query_values = (url.query_values || {})
|
|
819
|
+
.merge(:'default-graph-uri' => graphs)
|
|
820
|
+
when :update
|
|
821
|
+
url.query_values = (url.query_values || {})
|
|
822
|
+
.merge(:'using-graph-uri' => graphs)
|
|
823
|
+
end
|
|
824
|
+
end
|
|
825
|
+
|
|
760
826
|
# A query element can be used as a component of a query. It may be initialized with a string, which is wrapped in an appropriate container depending on the type of QueryElement. Implements {#to_s} to property serialize when generating a SPARQL query.
|
|
761
827
|
class QueryElement
|
|
762
828
|
attr_reader :elements
|