sparql-client 2.1.0 → 3.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 7bb3fbfde7825e70b178ae2e502f4145fc75db84
4
- data.tar.gz: 128998297c153debdc7ec09547eedd1c6106f84e
2
+ SHA256:
3
+ metadata.gz: b464200c11f2c711f8fae5cb6d75a2deea216a2d682246b7b74ba8316c515404
4
+ data.tar.gz: 63822682605b809841d008beee3599c81caa72df9d6d7c1004f9e7e1f136ed34
5
5
  SHA512:
6
- metadata.gz: a64de18fb22d1f3f7662e02c9e65e5cbfa41ce083c9f73379112b833178ce3694575871675c2a18d1abb5a5950dd47d3e3b6732a15e239690128ca91fefb6cfa
7
- data.tar.gz: 168112994fc8f38b83ddb20a850042ea55c6b766b119cbb0054a6bcd83d6c32bb5ab441ff8e543e43d695e9e48153cb2f44c61205b5ce1f47ea47ee1f5cc7f61
6
+ metadata.gz: da4608ed0bc2c17af4bc7eba4c9c82f0be8095174fb18e8ec455441622a7efd3782e375f85eb8200b51617472fa0a6a94d0c7352e21e00e07dc21b1ec2709e23
7
+ data.tar.gz: 1c78bbf4de5d7c6a30126938813991175598084ef19ebd38b3bd20d941ea8ab1b94cc347f3a7a1a2d7238745c2589ef173974e300edbb581f53e072c9b637724
data/README.md CHANGED
@@ -1,14 +1,15 @@
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
 
5
- * <http://ruby-rdf.github.com/sparql-client/>
5
+ * <https://ruby-rdf.github.com/sparql-client/>
6
6
 
7
- [![Gem Version](https://badge.fury.io/rb/sparql-client.png)](http://badge.fury.io/rb/sparql-client)
8
- [![Build Status](https://travis-ci.org/ruby-rdf/sparql-client.png?branch=master)](http://travis-ci.org/ruby-rdf/sparql-client)
7
+ [![Gem Version](https://badge.fury.io/rb/sparql-client.png)](https://badge.fury.io/rb/sparql-client)
8
+ [![Build Status](https://github.com/ruby-rdf/sparql-client/workflows/CI/badge.svg?branch=develop)](https://github.com/ruby-rdf/sparql-client/actions?query=workflow%3ACI)
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
+ [![Gitter chat](https://badges.gitter.im/ruby-rdf/rdf.png)](https://gitter.im/ruby-rdf/rdf)
10
11
 
11
- ##Features
12
+ ## Features
12
13
 
13
14
  * Executes queries against any SPARQL 1.0/1.1-compatible endpoint over HTTP,
14
15
  or against an `RDF::Queryable` instance, using the `SPARQL` gem.
@@ -18,94 +19,125 @@ 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 [RDF.rb object model][RDF.rb model].
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
- ##Examples
26
+ ## Examples
26
27
 
27
28
  ### Querying a remote SPARQL endpoint
28
- require 'sparql/client'
29
29
 
30
- sparql = SPARQL::Client.new("http://dbpedia.org/sparql")
30
+ ```ruby
31
+ require 'sparql/client'
32
+ sparql = SPARQL::Client.new("http://dbpedia.org/sparql")
33
+ ```
31
34
 
32
- ### Querying a `RDF::Repository` instance
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
- require 'rdf/trig'
35
- repository = RDF::Repository.load("http://example/dataset.trig")
38
+ ```ruby
39
+ require 'sparql/client'
40
+ sparql = SPARQL::Client.new("http://dbpedia.org/sparql", headers: {'User-Agent' => 'MyBotName'})
41
+ ```
36
42
 
37
- sparql = SPARQL::Client.new(repository)
43
+ ### Querying a remote SPARQL endpoint with a specified default graph
38
44
 
39
- ### Executing a boolean query and outputting the result
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
- # ASK WHERE { ?s ?p ?o }
42
- result = sparql.ask.whether([:s, :p, :o]).true?
59
+ ### Executing a boolean query and outputting the result
43
60
 
44
- puts result.inspect #=> true or false
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
- # SELECT * WHERE { ?s ?p ?o } OFFSET 100 LIMIT 10
49
- query = sparql.select.where([:s, :p, :o]).offset(100).limit(10)
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
- query.each_solution do |solution|
52
- puts solution.inspect
53
- end
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
- query.each_statement do |statement|
61
- puts statement.inspect
62
- end
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
- result = sparql.query("ASK WHERE { ?s ?p ?o }")
92
+ ```ruby
93
+ result = sparql.query("ASK WHERE { ?s ?p ?o }")
67
94
 
68
- puts result.inspect #=> true or false
95
+ puts result.inspect #=> true or false
96
+ ```
69
97
 
70
98
  ### Inserting data into a graph
71
99
 
72
- # INSERT DATA { <http://example.org/jhacker> <http://xmlns.com/foaf/0.1/name> "J. Random Hacker" .}
73
- data = RDF::Graph.new do |graph|
74
- graph << [RDF::URI('http://example.org/jhacker'), RDF::Vocab::FOAF.name, "J. Random Hacker"]
75
- end
76
- insert_data(data)
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
- # DELETE DATA { <http://example.org/jhacker> <http://xmlns.com/foaf/0.1/name> "J. Random Hacker" .}
81
- data = RDF::Graph.new do |graph|
82
- graph << [RDF::URI('http://example.org/jhacker'), RDF::Vocab::FOAF.name, "J. Random Hacker"]
83
- end
84
- delete_data(data)
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
- ##Documentation
118
+ ## Documentation
87
119
 
88
- * {SPARQL::Client}
89
- * {SPARQL::Client::Query}
90
- * {SPARQL::Client::Repository}
91
- * {SPARQL::Client::Update}
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
- ##Dependencies
125
+ ## Dependencies
94
126
 
95
- * [Ruby](http://ruby-lang.org/) (>= 2.2.2)
96
- * [RDF.rb](http://rubygems.org/gems/rdf) (>= 2.0)
97
- * [Net::HTTP::Persistent](http://rubygems.org/gems/net-http-persistent) (>= 1.4)
98
- * Soft dependency on [SPARQL](http://rubygems.org/gems/sparql) (>= 2.0)
99
- * Soft dependency on [Nokogiri](http://rubygems.org/gems/nokogiri) (>= 1.6)
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) (~> 3.1)
130
+ * Soft dependency on [SPARQL](https://rubygems.org/gems/sparql) (~> 3.1)
131
+ * Soft dependency on [Nokogiri](https://rubygems.org/gems/nokogiri) (>= 1.10)
100
132
 
101
- ##Installation
133
+ ## Installation
102
134
 
103
- The recommended installation method is via [RubyGems](http://rubygems.org/).
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
107
139
 
108
- ##Download
140
+ ## Download
109
141
 
110
142
  To get a local working copy of the development repository, do:
111
143
 
@@ -114,33 +146,33 @@ 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 http://github.com/ruby-rdf/sparql-client/tarball/master
149
+ % wget https://github.com/ruby-rdf/sparql-client/tarball/master
118
150
 
119
- ##Mailing List
151
+ ## Mailing List
120
152
 
121
- * <http://lists.w3.org/Archives/Public/public-rdf-ruby/>
153
+ * <https://lists.w3.org/Archives/Public/public-rdf-ruby/>
122
154
 
123
- ##Authors
155
+ ## Authors
124
156
 
125
- * [Arto Bendiken](http://github.com/bendiken) - <http://ar.to/>
126
- * [Ben Lavender](http://github.com/bhuga) - <http://bhuga.net/>
127
- * [Gregg Kellogg](http://github.com/gkellogg) - <http://greggkellogg.net/>
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
- ##Contributors
161
+ ## Contributors
130
162
 
131
- * [Christoph Badura](http://github.com/bad) - <http://github.com/bad>
132
- * [James Hetherington](http://github.com/jamespjh) - <http://twitter.com/jamespjh>
133
- * [Gabriel Horner](http://github.com/cldwalker) - <http://tagaholic.me/>
134
- * [Nicholas Humfrey](http://github.com/njh) - <http://www.aelius.com/njh/>
135
- * [Fumihiro Kato](http://github.com/fumi) - <http://fumi.me/>
136
- * [David Nielsen](http://github.com/drankard) - <http://github.com/drankard>
137
- * [Thamaraiselvan Poomalai](http://github.com/selvan) - <http://softonaut.blogspot.com/>
138
- * [Michael Sokol](http://github.com/mikaa123) - <http://sokolmichael.com/>
139
- * [Yves Raimond](http://github.com/moustaki) - <http://moustaki.org/>
140
- * [Thomas Feron](http://github.com/thoferon) - <http://github.com/thoferon>
141
- * [Nick Gottlieb](http://github.com/ngottlieb) - <http://www.nicholasgottlieb.com>
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
- ##Contributing
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.
145
177
 
146
178
  * Do your best to adhere to the existing coding conventions and idioms.
@@ -153,32 +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
- ##Resources
192
+ ## Resources
159
193
 
160
- * <http://ruby-rdf.github.com/sparql-client/>
161
- * <http://github.com/ruby-rdf/sparql-client>
162
- * <http://rubygems.org/gems/sparql-client>
163
- * <http://rubyforge.org/projects/sparql/>
164
- * <http://raa.ruby-lang.org/project/sparql-client/>
165
- * <http://www.ohloh.net/p/rdf>
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>
166
199
 
167
- ##License
200
+ ## License
168
201
 
169
202
  This is free and unencumbered public domain software. For more information,
170
- see <http://unlicense.org/> or the accompanying {file:UNLICENSE} file.
171
-
172
- [Ruby]: http://ruby-lang.org/
173
- [RDF]: http://www.w3.org/RDF/
174
- [SPARQL]: http://en.wikipedia.org/wiki/SPARQL
175
- [SPARQL JSON]: http://www.w3.org/TR/rdf-sparql-json-res/
176
- [RDF.rb]: http://rubygems.org/gems/rdf
177
- [RDF.rb model]: http://blog.datagraph.org/2010/03/rdf-for-ruby
178
- [RDF::Repository]: http://rubydoc.info/github/ruby-rdf/rdf/RDF/Repository
179
- [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
180
212
  "domain-specific language"
181
- [YARD]: http://yardoc.org/
182
- [YARD-GS]: http://rubydoc.info/docs/yard/file/docs/GettingStarted.md
183
- [PDD]: http://unlicense.org/#unlicensing-contributions
184
- [Backports]: http://rubygems.org/gems/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 <http://unlicense.org/>
24
+ For more information, please refer to <https://unlicense.org/>
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.1.0
1
+ 3.1.1
@@ -1,6 +1,6 @@
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
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 http://www.w3.org/TR/sparql11-query/
15
- # @see http://www.w3.org/TR/sparql11-protocol/
16
- # @see http://www.w3.org/TR/sparql11-results-json/
17
- # @see http://www.w3.org/TR/sparql11-results-csv-tsv/
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 = {}, &block)
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("http://rdf.rubyforge.org/doap.nt")
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, :graph => "http://example.org/")
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
- # @see http://www.w3.org/TR/sparql11-update/#insertData
171
- def insert_data(data, options = {})
172
- self.update(Update::InsertData.new(data, options))
188
+ # @see https://www.w3.org/TR/sparql11-update/#insertData
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("http://rdf.rubyforge.org/doap.nt")
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, :graph => "http://example.org/")
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
- # @see http://www.w3.org/TR/sparql11-update/#deleteData
192
- def delete_data(data, options = {})
193
- self.update(Update::DeleteData.new(data, options))
209
+ # @see https://www.w3.org/TR/sparql11-update/#deleteData
210
+ def delete_data(data, **options)
211
+ self.update(Update::DeleteData.new(data, **options))
194
212
  end
195
213
 
196
214
  ##
@@ -204,9 +222,9 @@ module SPARQL
204
222
  # @param [Hash{Symbol => Object}] options
205
223
  # @option options [RDF::URI, String] :graph
206
224
  # @return [void] `self`
207
- # @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))
225
+ # @see https://www.w3.org/TR/sparql11-update/#deleteInsert
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
  ##
@@ -221,9 +239,9 @@ module SPARQL
221
239
  # @param [Hash{Symbol => Object}] options
222
240
  # @option options [Boolean] :silent
223
241
  # @return [void] `self`
224
- # @see http://www.w3.org/TR/sparql11-update/#clear
225
- def clear_graph(graph_uri, options = {})
226
- self.clear(:graph, graph_uri, options)
242
+ # @see https://www.w3.org/TR/sparql11-update/#clear
243
+ def clear_graph(graph_uri, **options)
244
+ self.clear(:graph, graph_uri, **options)
227
245
  end
228
246
 
229
247
  ##
@@ -249,23 +267,23 @@ 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
256
274
  # @option options [Boolean] :silent
257
275
  # @return [void] `self`
258
276
  #
259
- # @see http://www.w3.org/TR/sparql11-update/#clear
277
+ # @see https://www.w3.org/TR/sparql11-update/#clear
260
278
  def clear(what, *arguments)
261
279
  self.update(Update::Clear.new(what, *arguments))
262
280
  end
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>]
291
- # @see http://www.w3.org/TR/sparql11-protocol/#query-operation
292
- def query(query, options = {})
309
+ # @raise [IOError] if connection is closed
310
+ # @see https://www.w3.org/TR/sparql11-protocol/#query-operation
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, optimize: true, **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`
318
- # @see http://www.w3.org/TR/sparql11-protocol/#update-operation
319
- def update(query, options = {})
337
+ # @raise [IOError] if connection is closed
338
+ # @see https://www.w3.org/TR/sparql11-protocol/#update-operation
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, options.merge(update: true))
345
+ SPARQL.execute(query, @url, update: true, optimize: 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
- def response(query, options = {})
342
- headers = options[:headers] || {}
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,14 +395,14 @@ 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
 
381
402
  ##
382
403
  # @param [String, Hash] json
383
404
  # @return [<RDF::Query::Solutions>]
384
- # @see http://www.w3.org/TR/rdf-sparql-json-res/#results
405
+ # @see https://www.w3.org/TR/rdf-sparql-json-res/#results
385
406
  def self.parse_json_bindings(json, nodes = {})
386
407
  require 'json' unless defined?(::JSON)
387
408
  json = JSON.parse(json.to_s) unless json.is_a?(Hash)
@@ -402,8 +423,8 @@ module SPARQL
402
423
  ##
403
424
  # @param [Hash{String => String}] value
404
425
  # @return [RDF::Value]
405
- # @see http://www.w3.org/TR/sparql11-results-json/#select-encode-terms
406
- # @see http://www.w3.org/TR/rdf-sparql-json-res/#variable-binding-results
426
+ # @see https://www.w3.org/TR/sparql11-results-json/#select-encode-terms
427
+ # @see https://www.w3.org/TR/rdf-sparql-json-res/#variable-binding-results
407
428
  def self.parse_json_value(value, nodes = {})
408
429
  case value['type'].to_sym
409
430
  when :bnode
@@ -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'], :datatype => value['datatype'], :language => value['xml:lang'])
435
+ RDF::Literal.new(value['value'], datatype: value['datatype'], language: value['xml:lang'])
415
436
  when :'typed-literal'
416
- RDF::Literal.new(value['value'], :datatype => value['datatype'])
437
+ RDF::Literal.new(value['value'], datatype: value['datatype'])
417
438
  else nil
418
439
  end
419
440
  end
@@ -421,7 +442,7 @@ module SPARQL
421
442
  ##
422
443
  # @param [String, Array<Array<String>>] csv
423
444
  # @return [<RDF::Query::Solutions>]
424
- # @see http://www.w3.org/TR/sparql11-results-csv-tsv/
445
+ # @see https://www.w3.org/TR/sparql11-results-csv-tsv/
425
446
  def self.parse_csv_bindings(csv, nodes = {})
426
447
  require 'csv' unless defined?(::CSV)
427
448
  csv = CSV.parse(csv.to_s) unless csv.is_a?(Array)
@@ -445,7 +466,7 @@ module SPARQL
445
466
  ##
446
467
  # @param [String, Array<Array<String>>] tsv
447
468
  # @return [<RDF::Query::Solutions>]
448
- # @see http://www.w3.org/TR/sparql11-results-csv-tsv/
469
+ # @see https://www.w3.org/TR/sparql11-results-csv-tsv/
449
470
  def self.parse_tsv_bindings(tsv, nodes = {})
450
471
  tsv = tsv.lines.map {|l| l.chomp.split("\t")} unless tsv.is_a?(Array)
451
472
  vars = tsv.shift.map {|h| h.sub(/^\?/, '')}
@@ -474,7 +495,7 @@ module SPARQL
474
495
  ##
475
496
  # @param [String, IO, Nokogiri::XML::Node, REXML::Element] xml
476
497
  # @return [<RDF::Query::Solutions>]
477
- # @see http://www.w3.org/TR/rdf-sparql-json-res/#results
498
+ # @see https://www.w3.org/TR/rdf-sparql-json-res/#results
478
499
  def self.parse_xml_bindings(xml, nodes = {})
479
500
  xml.force_encoding(::Encoding::UTF_8) if xml.respond_to?(:force_encoding)
480
501
 
@@ -519,7 +540,7 @@ module SPARQL
519
540
  ##
520
541
  # @param [Nokogiri::XML::Element, REXML::Element] value
521
542
  # @return [RDF::Value]
522
- # @see http://www.w3.org/TR/rdf-sparql-json-res/#variable-binding-results
543
+ # @see https://www.w3.org/TR/rdf-sparql-json-res/#variable-binding-results
523
544
  def self.parse_xml_value(value, nodes = {})
524
545
  case value.name.to_sym
525
546
  when :bnode
@@ -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, :language => lang, :datatype => datatype)
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 = {:content_type => response.content_type} unless options[:content_type]
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 suitable rdf reader was found."
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 = RDF::Statement.from(pattern).to_triple.each_with_index.map do |v, i|
613
- if i == 1
614
- SPARQL::Client.serialize_predicate(v)
615
- else
616
- SPARQL::Client.serialize_value(v, use_vars)
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,10 +690,16 @@ 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]
671
- # @see http://www.w3.org/TR/sparql11-protocol/#query-operation
701
+ # @raise [IOError] if connection is closed
702
+ # @see https://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
674
705
  headers['Accept'] ||= if (query.respond_to?(:expects_statements?) ?
@@ -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
@@ -714,10 +747,11 @@ module SPARQL
714
747
  # @param [String, #to_s] query
715
748
  # @param [Hash{String => String}] headers
716
749
  # @return [Net::HTTPRequest]
717
- # @see http://www.w3.org/TR/sparql11-protocol/#query-via-get
750
+ # @see https://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(:query => query.to_s)
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
@@ -728,25 +762,71 @@ module SPARQL
728
762
  # @param [String, #to_s] query
729
763
  # @param [Hash{String => String}] headers
730
764
  # @return [Net::HTTPRequest]
731
- # @see http://www.w3.org/TR/sparql11-protocol/#query-via-post-direct
732
- # @see http://www.w3.org/TR/sparql11-protocol/#query-via-post-urlencoded
765
+ # @see https://www.w3.org/TR/sparql11-protocol/#query-via-post-direct
766
+ # @see https://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
- endpoint = url.request_uri
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
- request.set_form_data((@op || :query) => query.to_s)
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