sparql-client 2.0.2 → 3.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 1a6ad63410ae80d9c27f0be01b03b76e190ff9d3
4
- data.tar.gz: 8eb1f2318206ca77f8d3de492edd5b39a21544e6
2
+ SHA256:
3
+ metadata.gz: 25fd44467b4b7014096fea7c336164c863b3da501ee747466ed486bdfab2f93d
4
+ data.tar.gz: f44d3e424e8c3fb13b0a323403212134c34e8fa7fb7ebaba562ded69a9d02fd7
5
5
  SHA512:
6
- metadata.gz: 06077bcbae3445a986788c5b0a6486892a13dbcf66c20d21a6fae3af20b119065dcaef2608f734d8f9b2c37574c99a08799293ec95cb93c93e8d872a0b90d895
7
- data.tar.gz: 65a0b4b376331ec5997c34590035f00223391672a092c696129ca51de547082c58178677d49b74ac99e577f62a4b60552fa37d82e5d3c7d08c40a65b07e70ea3
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
- sparql = SPARQL::Client.new("http://dbpedia.org/sparql")
29
+ ```ruby
30
+ require 'sparql/client'
31
+ sparql = SPARQL::Client.new("http://dbpedia.org/sparql")
32
+ ```
31
33
 
32
- ### Querying a `RDF::Repository` instance
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
- require 'rdf/trig'
35
- repository = RDF::Repository.load("http://example/dataset.trig")
37
+ ```ruby
38
+ require 'sparql/client'
39
+ sparql = SPARQL::Client.new("http://dbpedia.org/sparql", headers: {'User-Agent' => 'MyBotName'})
40
+ ```
36
41
 
37
- sparql = SPARQL::Client.new(repository)
42
+ ### Querying a remote SPARQL endpoint with a specified default graph
38
43
 
39
- ### Executing a boolean query and outputting the result
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
- # ASK WHERE { ?s ?p ?o }
42
- result = sparql.ask.whether([:s, :p, :o]).true?
58
+ ### Executing a boolean query and outputting the result
43
59
 
44
- puts result.inspect #=> true or false
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
- # SELECT * WHERE { ?s ?p ?o } OFFSET 100 LIMIT 10
49
- query = sparql.select.where([:s, :p, :o]).offset(100).limit(10)
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
- query.each_solution do |solution|
52
- puts solution.inspect
53
- end
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
- query.each_statement do |statement|
61
- puts statement.inspect
62
- end
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
- result = sparql.query("ASK WHERE { ?s ?p ?o }")
91
+ ```ruby
92
+ result = sparql.query("ASK WHERE { ?s ?p ?o }")
67
93
 
68
- puts result.inspect #=> true or false
94
+ puts result.inspect #=> true or false
95
+ ```
69
96
 
70
97
  ### Inserting data into a graph
71
98
 
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)
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
- # 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)
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
- * {SPARQL::Client}
89
- * {SPARQL::Client::Query}
90
- * {SPARQL::Client::Repository}
91
- * {SPARQL::Client::Update}
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.0)
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) (>= 1.1)
99
- * Soft dependency on [Nokogiri](http://rubygems.org/gems/nokogiri) (>= 1.6)
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
- 2.0.2
1
+ 3.1.0
@@ -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
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("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
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, options.merge(update: true))
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
- 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,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'], :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
@@ -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,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(: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
@@ -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
- 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