sparql 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +23 -4
  3. data/VERSION +1 -1
  4. data/lib/rack/sparql/conneg.rb +5 -2
  5. data/lib/sinatra/sparql.rb +9 -16
  6. data/lib/sinatra/sparql/extensions.rb +0 -2
  7. data/lib/sparql.rb +8 -5
  8. data/lib/sparql/algebra/expression.rb +1 -1
  9. data/lib/sparql/algebra/extensions.rb +34 -6
  10. data/lib/sparql/algebra/operator/ask.rb +13 -5
  11. data/lib/sparql/algebra/operator/base.rb +19 -5
  12. data/lib/sparql/algebra/operator/bgp.rb +6 -2
  13. data/lib/sparql/algebra/operator/construct.rb +19 -8
  14. data/lib/sparql/algebra/operator/dataset.rb +8 -4
  15. data/lib/sparql/algebra/operator/datatype.rb +1 -7
  16. data/lib/sparql/algebra/operator/describe.rb +16 -6
  17. data/lib/sparql/algebra/operator/distinct.rb +7 -6
  18. data/lib/sparql/algebra/operator/exists.rb +3 -6
  19. data/lib/sparql/algebra/operator/extend.rb +11 -1
  20. data/lib/sparql/algebra/operator/filter.rb +12 -17
  21. data/lib/sparql/algebra/operator/graph.rb +6 -4
  22. data/lib/sparql/algebra/operator/group.rb +10 -5
  23. data/lib/sparql/algebra/operator/join.rb +16 -9
  24. data/lib/sparql/algebra/operator/left_join.rb +15 -11
  25. data/lib/sparql/algebra/operator/minus.rb +11 -7
  26. data/lib/sparql/algebra/operator/notexists.rb +1 -1
  27. data/lib/sparql/algebra/operator/order.rb +9 -3
  28. data/lib/sparql/algebra/operator/prefix.rb +19 -2
  29. data/lib/sparql/algebra/operator/project.rb +9 -4
  30. data/lib/sparql/algebra/operator/reduced.rb +8 -3
  31. data/lib/sparql/algebra/operator/slice.rb +8 -1
  32. data/lib/sparql/algebra/operator/table.rb +7 -2
  33. data/lib/sparql/algebra/operator/union.rb +7 -2
  34. data/lib/sparql/algebra/query.rb +26 -6
  35. data/lib/sparql/extensions.rb +0 -8
  36. data/lib/sparql/grammar/parser11.rb +1 -1
  37. data/lib/sparql/results.rb +6 -4
  38. metadata +25 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 83b4375ca13302d7cdc8a6c81d7b6543cea34481
4
- data.tar.gz: 26e31f363b9b86f7786ab848ff9c655c7441260e
3
+ metadata.gz: ec306ea47d79b90b84acd927ef5169c6a745875b
4
+ data.tar.gz: 6e5860abfd989c5751c778c4212fdc3eb47368aa
5
5
  SHA512:
6
- metadata.gz: 47e5858870bc37a4a6be21ec9b117e1d53e75d1a384cdc1e89636b7a7ad9943382c972daea03fe6bc1ad5dc93e76678889a048ad351ad1ea56530edb6fabcb7b
7
- data.tar.gz: aaa54ca0274fcecec14f8720c0ab1fa27449a825988c34badbde60908975c2aae3c6a78951d8fa31ceb7ef954d61edda246a524e32cc4db34dab724bf3f945a3
6
+ metadata.gz: b5f110a1767a95d2e2c194b2b903fd4f4db9cf470ad14529525a3ae64cc3b2b785bf25d9c95e760475a519a53c01a33ef2b0de3cfb06bee5a39e6c0c72a6337d
7
+ data.tar.gz: bf1dd65ca43bfe141f152de212ca6d9c7b2b1e11487fc8bbcaac03dabd241da86f58320926225fc784b398a5b0af4c6142636d909375e92426727fe91452b5ef
data/README.md CHANGED
@@ -69,6 +69,11 @@ will be in later release along with:
69
69
 
70
70
  either in this, or related gems.
71
71
 
72
+ ### Updates for RDF 1.1
73
+ Starting with version 1.1.2, the SPARQL gem uses the 1.1 version of the [RDF.rb][], which adheres to [RDF 1.1 Concepts](http://www.w3.org/TR/rdf11-concepts/) rather than [RDF 1.0](http://www.w3.org/TR/rdf-concepts/). The main difference is that there is now no difference between a _Simple Literal_ (a literal with no datatype or language) and a Literal with datatype _xsd:string_; this causes some minor differences in the way in which queries are understood, and when expecting different results.
74
+
75
+ Additionally, queries now take a block, or return an `Enumerator`; this is in keeping with much of the behavior of [RDF.rb][] methods, including `Queryable#query`, and with version 1.1 or [RDF.rb][], Query#execute. As a consequence, all queries which used to be of the form `query.execute(repository)` may equally be called as `repository.query(query)`. Previously, results were returned as a concrete class implementing `RDF::Queryable` or `RDF::Query::Solutions`, these are now `Enumerators`.
76
+
72
77
  ### SPARQL Extension Functions
73
78
  Extension functions may be defined, which will be invoked during query evaluation. For example:
74
79
 
@@ -94,8 +99,8 @@ See {SPARQL::Algebra::Expression.register_extension} for details.
94
99
  ### Middleware
95
100
 
96
101
  {Rack::SPARQL} is a superset of [Rack::LinkedData][] to allow content negotiated results
97
- to be returned any `RDF::Enumerable` or `RDF::Query::Solutions` compatible results.
98
- You would typically return an instance of `RDF::Graph`, `RDF::Repository` or `RDF::Query::Solutions`
102
+ to be returned any `RDF::Enumerable` or an enumerator extended with `RDF::Query::Solutions` compatible results.
103
+ You would typically return an instance of `RDF::Graph`, `RDF::Repository` or an enumerator extended with `RDF::Query::Solutions`
99
104
  from your Rack application, and let the `Rack::SPARQL::ContentNegotiation` middleware
100
105
  take care of serializing your response into whatever format the HTTP
101
106
  client requested and understands.
@@ -133,11 +138,21 @@ a full set of RDF formats.
133
138
  require 'rubygems'
134
139
  require 'sparql'
135
140
 
141
+ ### Querying a repository with a SPARQL query
142
+
143
+ queryable = RDF::Repository.load("etc/doap.ttl")
144
+ sse = SPARQL.parse("SELECT * WHERE { ?s ?p ?o }")
145
+ queryable.query(sse) do |result|
146
+ result.inspect
147
+ end
148
+
136
149
  ### Executing a SPARQL query against a repository
137
150
 
138
151
  queryable = RDF::Repository.load("etc/doap.ttl")
139
152
  sse = SPARQL.parse("SELECT * WHERE { ?s ?p ?o }")
140
- sse.execute(queryable)
153
+ sse.execute(queryable) do |result|
154
+ result.inspect
155
+ end
141
156
 
142
157
  ### Rendering solutions as JSON, XML, CSV, TSV or HTML
143
158
  queryable = RDF::Repository.load("etc/doap.ttl")
@@ -272,6 +287,7 @@ To get a local working copy of the development repository, do:
272
287
  * [Pius Uzamere](http://github.com/pius) - <http://pius.me/>
273
288
 
274
289
  ## Contributing
290
+ 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.
275
291
 
276
292
  * Do your best to adhere to the existing coding conventions and idioms.
277
293
  * Don't use hard tabs, and don't leave trailing whitespace on any line.
@@ -290,7 +306,9 @@ To get a local working copy of the development repository, do:
290
306
  This is free and unencumbered public domain software. For more information,
291
307
  see <http://unlicense.org/> or the accompanying {file:UNLICENSE} file.
292
308
 
293
- A copy of the [SPARQL 1.0 tests][] and [SPARQL 1.1 tests][] are included in the repository, which are not covered under the UNLICENSE; see the references for test copyright information.
309
+ A copy of the [SPARQL EBNF][] and derived parser files are included in the repository, which are not covered under the UNLICENSE. These files are covered via the [W3C Document License](http://www.w3.org/Consortium/Legal/2002/copyright-documents-20021231).
310
+
311
+ A copy of the [SPARQL 1.0 tests][] and [SPARQL 1.1 tests][] are also included in the repository, which are not covered under the UNLICENSE; see the references for test copyright information.
294
312
 
295
313
  [Ruby]: http://ruby-lang.org/
296
314
  [RDF]: http://www.w3.org/RDF/
@@ -314,6 +332,7 @@ A copy of the [SPARQL 1.0 tests][] and [SPARQL 1.1 tests][] are included in the
314
332
  [SPARQL doc]: http://rubydoc.info/github/ruby-rdf/sparql/frames
315
333
  [SPARQL XML]: http://www.w3.org/TR/rdf-sparql-XMLres/
316
334
  [SPARQL JSON]: http://www.w3.org/TR/rdf-sparql-json-res/
335
+ [SPARQL EBNF]: http://www.w3.org/TR/sparql11-query/#sparqlGrammar
317
336
  [Property Paths]: http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#propertypaths
318
337
 
319
338
  [SSD]: http://www.w3.org/TR/sparql11-service-description/
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.1
1
+ 1.1.2
@@ -34,15 +34,18 @@ module Rack; module SPARQL
34
34
  end
35
35
 
36
36
  ##
37
- # Handles a Rack protocol request.
37
+ # Handles a Rack protocol request. Parses Accept header to find appropriate mime-type and sets content_type accordingly.
38
38
  #
39
39
  # If result is `RDF::Literal::Boolean`, `RDF::Query::Results`, or `RDF::Enumerable`
40
40
  # The result is serialized using {SPARQL::Results}
41
41
  #
42
+ # Inserts ordered content types into the environment as `ORDERED_CONTENT_TYPES` if an Accept header is present
43
+ #
42
44
  # @param [Hash{String => String}] env
43
45
  # @return [Array(Integer, Hash, #each)]
44
46
  # @see http://rack.rubyforge.org/doc/SPEC.html
45
47
  def call(env)
48
+ env['ORDERED_CONTENT_TYPES'] = parse_accept_header(env['HTTP_ACCEPT']) if env.has_key?('HTTP_ACCEPT')
46
49
  response = app.call(env)
47
50
  body = response[2].respond_to?(:body) ? response[2].body : response[2]
48
51
  case body
@@ -66,7 +69,7 @@ module Rack; module SPARQL
66
69
  def serialize(env, status, headers, body)
67
70
  begin
68
71
  serialize_options = {}
69
- serialize_options[:content_types] = parse_accept_header(env['HTTP_ACCEPT']) if env.has_key?('HTTP_ACCEPT')
72
+ serialize_options[:content_types] = env['ORDERED_CONTENT_TYPES'] if env['ORDERED_CONTENT_TYPES']
70
73
  serialize_options.merge!(@options)
71
74
  results = ::SPARQL.serialize_results(body, serialize_options)
72
75
  raise RDF::WriterError, "can't serialize results" unless results
@@ -4,28 +4,23 @@ require 'rack/sparql'
4
4
 
5
5
  module Sinatra
6
6
  ##
7
- # The Sinatra::SPARQL module adds Rack::SPARQL} middleware support for responding to
8
- # SPARQL requests. It is the responsibility of the application to manage
9
- # the SPARQL endpoint and perform the query. The query results are then sent
10
- # as the response body. {Rack::SPARQL} middleware uses content negotiation
11
- # to format the results appropriately.
7
+ # The Sinatra::SPARQL module adds {Rack::SPARQL} middleware support for responding to SPARQL requests. It is the responsibility of the application to manage the SPARQL endpoint and perform the query. The query results are then sent as the response body. {Rack::SPARQL} middleware uses content negotiation to format the results appropriately.
8
+ #
9
+ # To override negotiation on Content-Type, set :format in `sparql_options` to a RDF Format class, or symbol identifying a format.
10
+ #
12
11
  # @see http://www.sinatrarb.com/extensions.html
13
12
  module SPARQL
14
13
  ##
15
14
  # Helper methods.
16
15
  module Helpers
17
16
  ##
18
- # This is useful when a GET request is performed against a SPARQL endpoint and
19
- # no query is performed. Provide a set of datasets, including a default dataset
20
- # along with optional triple count, dump location, and description of the dataset.
17
+ # This is useful when a GET request is performed against a SPARQL endpoint and no query is performed. Provide a set of datasets, including a default dataset along with optional triple count, dump location, and description of the dataset.
21
18
  #
22
- # The results are serialized using content negotiation. For text/html, authors
23
- # should generate RDFa for the serivce description directly.
19
+ # The results are serialized using content negotiation. For text/html, authors should generate RDFa for the serivce description directly.
24
20
  #
25
21
  # @param [Hash{Symbol => Object}] options
26
22
  # @option options [RDF::Enumerable] :repository
27
- # An enumerable, typically a type of `RDF::Repository` containing the dataset used for
28
- # queries against the service.
23
+ # An enumerable, typically a type of `RDF::Repository` containing the dataset used for queries against the service.
29
24
  # @option options [RDF::URI, #to_s] :endpoint
30
25
  # URI of the service endpoint, defaults to "/sparql" in the current realm.
31
26
  # @return [RDF::Graph]
@@ -94,12 +89,10 @@ module Sinatra
94
89
  end
95
90
 
96
91
  ##
97
- # * Registers Rack::SPARQL::ContentNegotiation
92
+ # * Registers {Rack::SPARQL::ContentNegotiation}
98
93
  # * adds helpers
99
94
  # * includes SPARQL, RDF and LinkedData
100
- # * defines `sparql_options`, which are passed to the Rack middleware
101
- # available as `settings.sparql_options` and as options within
102
- # the {Rack::SPARQL} middleware.
95
+ # * defines `sparql_options`, which are passed to the Rack middleware available as `settings.sparql_options` and as options within the {Rack::SPARQL} middleware.
103
96
  #
104
97
  # @param [Sinatra::Base] app
105
98
  # @return [void]
@@ -7,8 +7,6 @@ class Sinatra::Response
7
7
  headers.delete "Content-Type"
8
8
  elsif RDF::Query::Solutions === body
9
9
  # Don't calculate content-length here
10
- elsif Array === body and not [204, 304].include?(status.to_i)
11
- headers["Content-Length"] = body.inject(0) { |l, p| l + Rack::Utils.bytesize(p) }.to_s
12
10
  end
13
11
 
14
12
  # Rack::Response#finish sometimes returns self as response body. We don't want that.
data/lib/sparql.rb CHANGED
@@ -58,11 +58,14 @@ module SPARQL
58
58
  # One or more URIs used to initialize a new instance of `queryable` in the default context.
59
59
  # @option options [RDF::URI, String, Array<RDF::URI, String>] :named_graph_uri
60
60
  # One or more URIs used to initialize the `queryable` as a named context.
61
- # @return [RDF::Graph, RDF::Query::Solutions, Boolean]
62
- # Note, results may be used with {SPARQL.serialize_results} to obtain appropriate
63
- # output encoding.
61
+ # @yield [solution]
62
+ # each matching solution, statement or boolean
63
+ # @yieldparam [RDF::Statement, RDF::Query::Solution, Boolean] solution
64
+ # @yieldreturn [void] ignored
65
+ # @return [RDF::Graph, Boolean, RDF::Query::Solutions::Enumerator]
66
+ # Note, results may be used with {SPARQL.serialize_results} to obtain appropriate output encoding.
64
67
  # @raise [SPARQL::MalformedQuery] on invalid input
65
- def self.execute(query, queryable, options = {})
68
+ def self.execute(query, queryable, options = {}, &block)
66
69
  query = self.parse(query, options)
67
70
  queryable = queryable || RDF::Repository.new
68
71
 
@@ -82,7 +85,7 @@ module SPARQL
82
85
  queryable.load(uri, :context => uri)
83
86
  end
84
87
  end
85
- solutions = query.execute(queryable)
88
+ query.execute(queryable, &block)
86
89
  rescue SPARQL::Grammar::Parser::Error => e
87
90
  raise MalformedQuery, e.message
88
91
  rescue TypeError => e
@@ -27,7 +27,7 @@ module SPARQL; module Algebra
27
27
  end
28
28
  require 'sparql/algebra/sxp_extensions'
29
29
 
30
- sse = sse.dup.force_encoding(Encoding::UTF_8)
30
+ sse = sse.encode(Encoding::UTF_8)
31
31
  sxp = SXP::Reader::SPARQL.new(sse) do |reader|
32
32
  # Set base_uri if we have one
33
33
  reader.base_uri = options[:base_uri] if options[:base_uri]
@@ -175,7 +175,7 @@ module RDF::Term
175
175
  def compatible?(other)
176
176
  return false unless literal? && other.literal? && plain? && other.plain?
177
177
 
178
- dtr = RDF::VERSION.to_s >= "1.1" ? other.datatype : (other.has_language? ? RDF.langString : RDF::XSD.string)
178
+ dtr = other.datatype
179
179
 
180
180
  # * The arguments are simple literals or literals typed as xsd:string
181
181
  # * The arguments are plain literals with identical language tags
@@ -209,16 +209,27 @@ module RDF::Queryable
209
209
  # @yieldreturn [void] ignored
210
210
  # @return [Enumerator]
211
211
  # @see RDF::Queryable#query_pattern
212
- def query(pattern, &block)
213
- raise TypeError, "#{self} is not readable" if respond_to?(:readable?) && !readable?
212
+ def query(pattern, options = {}, &block)
213
+ raise TypeError, "#{self} is not queryable" if respond_to?(:queryable?) && !queryable?
214
214
 
215
215
  if pattern.is_a?(SPARQL::Algebra::Operator) && pattern.respond_to?(:execute)
216
216
  before_query(pattern) if respond_to?(:before_query)
217
- query_execute(pattern, &block)
217
+ solutions = if method(:query_execute).arity == 1
218
+ query_execute(pattern, &block)
219
+ else
220
+ query_execute(pattern, options, &block)
221
+ end
218
222
  after_query(pattern) if respond_to?(:after_query)
219
- enum_for(:query_execute, pattern)
223
+
224
+ if !pattern.respond_to?(:query_yeilds_solutions?) || pattern.query_yields_solutions?
225
+ # Just return solutions
226
+ solutions
227
+ else
228
+ # Return an enumerator
229
+ enum_for(:query, pattern, options)
230
+ end
220
231
  else
221
- query_without_sparql(pattern, &block)
232
+ query_without_sparql(pattern, options, &block)
222
233
  end
223
234
  end
224
235
 
@@ -249,6 +260,23 @@ class RDF::Query
249
260
  res = [:bgp] + patterns.map(&:to_sxp_bin)
250
261
  (context ? [:graph, context, res] : res)
251
262
  end
263
+ # Query results in a boolean result (e.g., ASK)
264
+ # @return [Boolean]
265
+ def query_yields_boolean?
266
+ false
267
+ end
268
+
269
+ # Query results statements (e.g., CONSTRUCT, DESCRIBE, CREATE)
270
+ # @return [Boolean]
271
+ def query_yields_statements?
272
+ false
273
+ end
274
+
275
+ # Query results solutions (e.g., SELECT)
276
+ # @return [Boolean]
277
+ def query_yields_solutions?
278
+ true
279
+ end
252
280
  end
253
281
 
254
282
  class RDF::Query::Pattern
@@ -22,14 +22,16 @@ module SPARQL; module Algebra
22
22
  # the graph or repository to query
23
23
  # @param [Hash{Symbol => Object}] options
24
24
  # any additional keyword options
25
- # @return [RDF::Literal::Boolean]
26
- # the resulting solution sequence
25
+ # @yield [RDF::Literal::Boolean]
26
+ # @yieldparam [RDF::Query::Solution] solution
27
+ # @yieldreturn [void] ignored
28
+ # @return [RDF::Literal::Boolean]\
27
29
  # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
28
30
  def execute(queryable, options = {})
29
31
  debug(options) {"Ask #{operands.first}"}
30
- boolean(!operands.last.
31
- execute(queryable, options.merge(:depth => options[:depth].to_i + 1)).
32
- empty?)
32
+ res = boolean(!queryable.query(operands.last, options.merge(:depth => options[:depth].to_i + 1)).empty?)
33
+ yield res if block_given?
34
+ res
33
35
  end
34
36
 
35
37
  ##
@@ -41,6 +43,12 @@ module SPARQL; module Algebra
41
43
  def optimize
42
44
  operands = operands.map(&:optimize)
43
45
  end
46
+
47
+ # Query results in a boolean result (e.g., ASK)
48
+ # @return [Boolean]
49
+ def query_yields_boolean?
50
+ true
51
+ end
44
52
  end # Ask
45
53
  end # Operator
46
54
  end; end # SPARQL::Algebra
@@ -22,15 +22,17 @@ module SPARQL; module Algebra
22
22
  # the graph or repository to query
23
23
  # @param [Hash{Symbol => Object}] options
24
24
  # any additional keyword options
25
- # @return [RDF::Query::Solutions]
25
+ # @yield [solution]
26
+ # each matching solution, statement or boolean
27
+ # @yieldparam [RDF::Statement, RDF::Query::Solution, Boolean] solution
28
+ # @yieldreturn [void] ignored
29
+ # @return [RDF::Queryable, RDF::Query::Solutions]
26
30
  # the resulting solution sequence
27
31
  # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
28
- def execute(queryable, options = {})
32
+ def execute(queryable, options = {}, &block)
29
33
  debug(options) {"Base #{operands.first}"}
30
34
  Operator.base_uri = operands.first
31
- @solutions = operands.last.execute(queryable, options.merge(:depth => options[:depth].to_i + 1))
32
- debug(options) {"=> #{@solutions.inspect}"}
33
- @solutions
35
+ queryable.query(operands.last, options.merge(:depth => options[:depth].to_i + 1), &block)
34
36
  end
35
37
 
36
38
  ##
@@ -42,6 +44,18 @@ module SPARQL; module Algebra
42
44
  def optimize
43
45
  operands.last.optimize
44
46
  end
47
+
48
+ # Query results in a boolean result (e.g., ASK)
49
+ # @return [Boolean]
50
+ def query_yields_boolean?
51
+ operands.last.query_yields_boolean?
52
+ end
53
+
54
+ # Query results statements (e.g., CONSTRUCT, DESCRIBE, CREATE)
55
+ # @return [Boolean]
56
+ def query_yields_statements?
57
+ operands.last.query_yields_statements?
58
+ end
45
59
  end # Base
46
60
  end # Operator
47
61
  end; end # SPARQL::Algebra
@@ -17,9 +17,13 @@ module SPARQL; module Algebra
17
17
  #
18
18
  # @overload self.new(*patterns)
19
19
  # @param [Array<RDF::Query::Pattern>] patterns
20
+ # @yield [solution]
21
+ # each matching solution
22
+ # @yieldparam [RDF::Query::Solution] solution
23
+ # @yieldreturn [void] ignored
20
24
  # @return [RDF::Query]
21
- def self.new(*patterns)
22
- RDF::Query.new(*(patterns + [{:context => false}]))
25
+ def self.new(*patterns, &block)
26
+ RDF::Query.new(*(patterns + [{:context => false}]), &block)
23
27
  end
24
28
  end # BGP
25
29
  end # Operator
@@ -29,17 +29,21 @@ module SPARQL; module Algebra
29
29
  # the graph or repository to query
30
30
  # @param [Hash{Symbol => Object}] options
31
31
  # any additional keyword options
32
- # @return [RDF::Query::Solutions]
33
- # the resulting solution sequence
32
+ # @yield [statement]
33
+ # each matching statement
34
+ # @yieldparam [RDF::Statement] solution
35
+ # @yieldreturn [void] ignored
36
+ # @return [RDF::Queryable]
37
+ # A Queryable with constructed triples
34
38
  # @see http://www.w3.org/TR/rdf-sparql-query/#construct
35
- def execute(queryable, options = {})
39
+ def execute(queryable, options = {}, &block)
36
40
  debug(options) {"Construct #{operands.first}, #{options.inspect}"}
37
41
  graph = RDF::Graph.new
38
42
  patterns = operands.first
39
43
  query = operands.last
40
44
 
41
- query.execute(queryable, options.merge(:depth => options[:depth].to_i + 1)).each do |solution|
42
- debug(options) {"=> Apply #{solution.inspect} to BGP"}
45
+ queryable.query(query, options.merge(:depth => options[:depth].to_i + 1)).each do |solution|
46
+ debug(options) {"(construct apply) #{solution.inspect} to BGP"}
43
47
 
44
48
  # Create a mapping from BNodes within the pattern list to newly constructed BNodes
45
49
  nodes = {}
@@ -58,16 +62,17 @@ module SPARQL; module Algebra
58
62
  # Sanity checking on statement
59
63
  if statement.subject.nil? || statement.predicate.nil? || statement.object.nil? ||
60
64
  statement.subject.literal? || statement.predicate.literal?
61
- debug(options) {"==> skip #{statement.inspect}"}
65
+ debug(options) {"(construct skip) #{statement.inspect}"}
62
66
  next
63
67
  end
64
68
 
65
- debug(options) {"==> add #{statement.inspect}"}
69
+ debug(options) {"(construct add) #{statement.inspect}"}
66
70
  graph << statement
67
71
  end
68
72
  end
69
-
73
+
70
74
  debug(options) {"=>\n#{graph.dump(:ttl, :standard_prefixes => true)}"}
75
+ graph.each(&block) if block_given?
71
76
  graph
72
77
  end
73
78
 
@@ -80,6 +85,12 @@ module SPARQL; module Algebra
80
85
  def optimize
81
86
  operands = operands.map(&:optimize)
82
87
  end
88
+
89
+ # Query results statements (e.g., CONSTRUCT, DESCRIBE, CREATE)
90
+ # @return [Boolean]
91
+ def query_yields_statements?
92
+ true
93
+ end
83
94
  end # Construct
84
95
  end # Operator
85
96
  end; end # SPARQL::Algebra
@@ -109,7 +109,8 @@ module SPARQL; module Algebra
109
109
  NAME = [:dataset]
110
110
  # Selected accept headers, from those available
111
111
  ACCEPTS = (%w(
112
- text/turtle
112
+ application/turtle
113
+ text/turtle;q=0.9
113
114
  application/rdf+xml;q=0.8
114
115
  application/n-triples;q=0.4
115
116
  text/plain;q=0.1
@@ -130,10 +131,14 @@ module SPARQL; module Algebra
130
131
  # the graph or repository to query
131
132
  # @param [Hash{Symbol => Object}] options
132
133
  # any additional keyword options
134
+ # @yield [solution]
135
+ # each matching solution
136
+ # @yieldparam [RDF::Query::Solution] solution
137
+ # @yieldreturn [void] ignored
133
138
  # @return [RDF::Query::Solutions]
134
139
  # the resulting solution sequence
135
140
  # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
136
- def execute(queryable, options = {})
141
+ def execute(queryable, options = {}, &base)
137
142
  debug(options) {"Dataset"}
138
143
  default_datasets = []
139
144
  named_datasets = []
@@ -176,8 +181,7 @@ module SPARQL; module Algebra
176
181
  aggregate = RDF::AggregateRepo.new(queryable)
177
182
  named_datasets.each {|name| aggregate.named(name) if queryable.has_context?(name)}
178
183
  aggregate.default(*default_datasets.select {|name| queryable.has_context?(name)})
179
- executable = operands.last
180
- @solutions = executable.execute(aggregate, options.merge(:depth => options[:depth].to_i + 1))
184
+ aggregate.query(operands.last, options.merge(:depth => options[:depth].to_i + 1), &base)
181
185
  end
182
186
 
183
187
  ##