sparql 3.0.0 → 3.1.3

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.
Files changed (151) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +184 -70
  3. data/UNLICENSE +1 -1
  4. data/VERSION +1 -1
  5. data/bin/sparql +28 -17
  6. data/lib/rack/sparql.rb +1 -1
  7. data/lib/rack/sparql/conneg.rb +3 -3
  8. data/lib/sinatra/sparql.rb +5 -5
  9. data/lib/sparql.rb +14 -10
  10. data/lib/sparql/algebra.rb +15 -23
  11. data/lib/sparql/algebra/aggregate.rb +4 -4
  12. data/lib/sparql/algebra/evaluatable.rb +2 -2
  13. data/lib/sparql/algebra/expression.rb +28 -21
  14. data/lib/sparql/algebra/extensions.rb +142 -16
  15. data/lib/sparql/algebra/operator.rb +37 -16
  16. data/lib/sparql/algebra/operator/abs.rb +2 -2
  17. data/lib/sparql/algebra/operator/add.rb +3 -3
  18. data/lib/sparql/algebra/operator/alt.rb +4 -4
  19. data/lib/sparql/algebra/operator/and.rb +7 -7
  20. data/lib/sparql/algebra/operator/asc.rb +3 -3
  21. data/lib/sparql/algebra/operator/ask.rb +4 -14
  22. data/lib/sparql/algebra/operator/avg.rb +6 -4
  23. data/lib/sparql/algebra/operator/base.rb +10 -10
  24. data/lib/sparql/algebra/operator/bgp.rb +1 -1
  25. data/lib/sparql/algebra/operator/bnode.rb +5 -5
  26. data/lib/sparql/algebra/operator/bound.rb +3 -3
  27. data/lib/sparql/algebra/operator/ceil.rb +2 -2
  28. data/lib/sparql/algebra/operator/clear.rb +3 -3
  29. data/lib/sparql/algebra/operator/coalesce.rb +3 -13
  30. data/lib/sparql/algebra/operator/compare.rb +8 -8
  31. data/lib/sparql/algebra/operator/concat.rb +4 -4
  32. data/lib/sparql/algebra/operator/construct.rb +4 -14
  33. data/lib/sparql/algebra/operator/contains.rb +2 -2
  34. data/lib/sparql/algebra/operator/copy.rb +3 -3
  35. data/lib/sparql/algebra/operator/count.rb +3 -3
  36. data/lib/sparql/algebra/operator/create.rb +3 -3
  37. data/lib/sparql/algebra/operator/dataset.rb +5 -16
  38. data/lib/sparql/algebra/operator/datatype.rb +1 -1
  39. data/lib/sparql/algebra/operator/day.rb +1 -1
  40. data/lib/sparql/algebra/operator/delete.rb +7 -5
  41. data/lib/sparql/algebra/operator/delete_data.rb +3 -3
  42. data/lib/sparql/algebra/operator/delete_where.rb +5 -5
  43. data/lib/sparql/algebra/operator/desc.rb +1 -1
  44. data/lib/sparql/algebra/operator/describe.rb +3 -13
  45. data/lib/sparql/algebra/operator/distinct.rb +4 -14
  46. data/lib/sparql/algebra/operator/divide.rb +1 -1
  47. data/lib/sparql/algebra/operator/drop.rb +3 -3
  48. data/lib/sparql/algebra/operator/encode_for_uri.rb +3 -3
  49. data/lib/sparql/algebra/operator/equal.rb +3 -3
  50. data/lib/sparql/algebra/operator/exists.rb +5 -5
  51. data/lib/sparql/algebra/operator/exprlist.rb +3 -13
  52. data/lib/sparql/algebra/operator/extend.rb +21 -20
  53. data/lib/sparql/algebra/operator/filter.rb +6 -16
  54. data/lib/sparql/algebra/operator/floor.rb +2 -2
  55. data/lib/sparql/algebra/operator/graph.rb +5 -16
  56. data/lib/sparql/algebra/operator/greater_than.rb +5 -5
  57. data/lib/sparql/algebra/operator/greater_than_or_equal.rb +5 -5
  58. data/lib/sparql/algebra/operator/group.rb +25 -25
  59. data/lib/sparql/algebra/operator/group_concat.rb +6 -6
  60. data/lib/sparql/algebra/operator/hours.rb +1 -1
  61. data/lib/sparql/algebra/operator/if.rb +5 -15
  62. data/lib/sparql/algebra/operator/in.rb +4 -14
  63. data/lib/sparql/algebra/operator/insert.rb +6 -4
  64. data/lib/sparql/algebra/operator/insert_data.rb +3 -3
  65. data/lib/sparql/algebra/operator/iri.rb +1 -1
  66. data/lib/sparql/algebra/operator/is_blank.rb +1 -1
  67. data/lib/sparql/algebra/operator/is_iri.rb +1 -1
  68. data/lib/sparql/algebra/operator/is_literal.rb +1 -1
  69. data/lib/sparql/algebra/operator/is_numeric.rb +1 -1
  70. data/lib/sparql/algebra/operator/join.rb +12 -10
  71. data/lib/sparql/algebra/operator/lang.rb +1 -1
  72. data/lib/sparql/algebra/operator/lang_matches.rb +3 -3
  73. data/lib/sparql/algebra/operator/lcase.rb +2 -2
  74. data/lib/sparql/algebra/operator/left_join.rb +15 -12
  75. data/lib/sparql/algebra/operator/less_than.rb +5 -5
  76. data/lib/sparql/algebra/operator/less_than_or_equal.rb +5 -5
  77. data/lib/sparql/algebra/operator/load.rb +3 -3
  78. data/lib/sparql/algebra/operator/max.rb +6 -4
  79. data/lib/sparql/algebra/operator/md5.rb +1 -1
  80. data/lib/sparql/algebra/operator/min.rb +6 -4
  81. data/lib/sparql/algebra/operator/minus.rb +12 -11
  82. data/lib/sparql/algebra/operator/minutes.rb +1 -1
  83. data/lib/sparql/algebra/operator/modify.rb +4 -4
  84. data/lib/sparql/algebra/operator/month.rb +1 -1
  85. data/lib/sparql/algebra/operator/move.rb +3 -3
  86. data/lib/sparql/algebra/operator/multiply.rb +1 -1
  87. data/lib/sparql/algebra/operator/negate.rb +1 -1
  88. data/lib/sparql/algebra/operator/not.rb +1 -1
  89. data/lib/sparql/algebra/operator/not_equal.rb +2 -2
  90. data/lib/sparql/algebra/operator/notexists.rb +4 -4
  91. data/lib/sparql/algebra/operator/notin.rb +4 -14
  92. data/lib/sparql/algebra/operator/notoneof.rb +5 -6
  93. data/lib/sparql/algebra/operator/now.rb +1 -1
  94. data/lib/sparql/algebra/operator/or.rb +7 -7
  95. data/lib/sparql/algebra/operator/order.rb +6 -16
  96. data/lib/sparql/algebra/operator/path.rb +6 -5
  97. data/lib/sparql/algebra/operator/path_opt.rb +16 -16
  98. data/lib/sparql/algebra/operator/path_plus.rb +8 -8
  99. data/lib/sparql/algebra/operator/path_star.rb +4 -4
  100. data/lib/sparql/algebra/operator/plus.rb +3 -3
  101. data/lib/sparql/algebra/operator/prefix.rb +10 -10
  102. data/lib/sparql/algebra/operator/project.rb +4 -14
  103. data/lib/sparql/algebra/operator/rand.rb +1 -1
  104. data/lib/sparql/algebra/operator/reduced.rb +4 -14
  105. data/lib/sparql/algebra/operator/regex.rb +6 -6
  106. data/lib/sparql/algebra/operator/replace.rb +4 -4
  107. data/lib/sparql/algebra/operator/reverse.rb +4 -4
  108. data/lib/sparql/algebra/operator/round.rb +2 -2
  109. data/lib/sparql/algebra/operator/same_term.rb +8 -5
  110. data/lib/sparql/algebra/operator/sample.rb +3 -3
  111. data/lib/sparql/algebra/operator/seconds.rb +1 -1
  112. data/lib/sparql/algebra/operator/seq.rb +5 -6
  113. data/lib/sparql/algebra/operator/sequence.rb +4 -4
  114. data/lib/sparql/algebra/operator/sha1.rb +1 -1
  115. data/lib/sparql/algebra/operator/sha256.rb +1 -1
  116. data/lib/sparql/algebra/operator/sha384.rb +1 -1
  117. data/lib/sparql/algebra/operator/sha512.rb +1 -1
  118. data/lib/sparql/algebra/operator/slice.rb +4 -14
  119. data/lib/sparql/algebra/operator/str.rb +1 -1
  120. data/lib/sparql/algebra/operator/strafter.rb +2 -2
  121. data/lib/sparql/algebra/operator/strbefore.rb +2 -2
  122. data/lib/sparql/algebra/operator/strdt.rb +2 -2
  123. data/lib/sparql/algebra/operator/strends.rb +2 -2
  124. data/lib/sparql/algebra/operator/strlang.rb +2 -2
  125. data/lib/sparql/algebra/operator/strlen.rb +2 -2
  126. data/lib/sparql/algebra/operator/strstarts.rb +2 -2
  127. data/lib/sparql/algebra/operator/struuid.rb +1 -1
  128. data/lib/sparql/algebra/operator/substr.rb +4 -4
  129. data/lib/sparql/algebra/operator/subtract.rb +1 -1
  130. data/lib/sparql/algebra/operator/sum.rb +6 -4
  131. data/lib/sparql/algebra/operator/table.rb +6 -4
  132. data/lib/sparql/algebra/operator/timezone.rb +1 -1
  133. data/lib/sparql/algebra/operator/tz.rb +1 -1
  134. data/lib/sparql/algebra/operator/ucase.rb +2 -2
  135. data/lib/sparql/algebra/operator/union.rb +10 -9
  136. data/lib/sparql/algebra/operator/update.rb +4 -4
  137. data/lib/sparql/algebra/operator/using.rb +4 -4
  138. data/lib/sparql/algebra/operator/uuid.rb +1 -1
  139. data/lib/sparql/algebra/operator/with.rb +6 -6
  140. data/lib/sparql/algebra/operator/year.rb +1 -1
  141. data/lib/sparql/algebra/query.rb +2 -2
  142. data/lib/sparql/algebra/update.rb +2 -2
  143. data/lib/sparql/algebra/version.rb +1 -1
  144. data/lib/sparql/extensions.rb +5 -5
  145. data/lib/sparql/grammar.rb +111 -11
  146. data/lib/sparql/grammar/meta.rb +1372 -333
  147. data/lib/sparql/grammar/parser11.rb +56 -42
  148. data/lib/sparql/grammar/terminals11.rb +1 -0
  149. data/lib/sparql/results.rb +63 -44
  150. data/lib/sparql/version.rb +1 -1
  151. metadata +40 -47
@@ -18,7 +18,7 @@ module Rack
18
18
  # @param [Hash{Symbol => Object}] options
19
19
  # @option options [Boolean] :overwrite (false)
20
20
  # @return [void]
21
- def self.register_mime_types!(options = {})
21
+ def self.register_mime_types!(**options)
22
22
  if defined?(Rack::Mime::MIME_TYPES)
23
23
  RDF::Format.each do |format|
24
24
  if !Rack::Mime::MIME_TYPES.has_key?(file_ext = ".#{format.to_sym}") || options[:overwrite]
@@ -43,7 +43,7 @@ module Rack; module SPARQL
43
43
  #
44
44
  # @param [Hash{String => String}] env
45
45
  # @return [Array(Integer, Hash, #each)]
46
- # @see http://www.rubydoc.info/github/rack/rack/Rack/Runtime#call-instance_method
46
+ # @see https://www.rubydoc.info/github/rack/rack/Rack/Runtime#call-instance_method
47
47
  def call(env)
48
48
  env['ORDERED_CONTENT_TYPES'] = parse_accept_header(env['HTTP_ACCEPT']) if env.has_key?('HTTP_ACCEPT')
49
49
  response = app.call(env)
@@ -71,7 +71,7 @@ module Rack; module SPARQL
71
71
  serialize_options = {}
72
72
  serialize_options[:content_types] = env['ORDERED_CONTENT_TYPES'] if env['ORDERED_CONTENT_TYPES']
73
73
  serialize_options.merge!(@options)
74
- results = ::SPARQL.serialize_results(body, serialize_options)
74
+ results = ::SPARQL.serialize_results(body, **serialize_options)
75
75
  raise RDF::WriterError, "can't serialize results" unless results
76
76
  headers = headers.merge(VARY).merge('Content-Type' => results.content_type) # FIXME: don't overwrite existing Vary headers
77
77
  [status, headers, [results]]
@@ -89,7 +89,7 @@ module Rack; module SPARQL
89
89
  #
90
90
  # @param [String, #to_s] header
91
91
  # @return [Array<String>]
92
- # @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
92
+ # @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
93
93
  def parse_accept_header(header)
94
94
  entries = header.to_s.split(',')
95
95
  entries.map { |e| accept_entry(e) }.sort_by(&:last).map(&:first)
@@ -8,7 +8,7 @@ module Sinatra
8
8
  #
9
9
  # To override negotiation on Content-Type, set :format in `sparql_options` to a RDF Format class, or symbol identifying a format.
10
10
  #
11
- # @see http://www.sinatrarb.com/extensions.html
11
+ # @see https://www.sinatrarb.com/extensions.html
12
12
  module SPARQL
13
13
  ##
14
14
  # Helper methods.
@@ -25,9 +25,9 @@ module Sinatra
25
25
  # URI of the service endpoint, defaults to "/sparql" in the current realm.
26
26
  # @return [RDF::Graph]
27
27
  #
28
- # @see http://www.w3.org/TR/sparql11-service-description
29
- # @see http://www.w3.org/TR/void/
30
- def service_description(options = {})
28
+ # @see https://www.w3.org/TR/sparql11-service-description
29
+ # @see https://www.w3.org/TR/void/
30
+ def service_description(**options)
31
31
  repository = options[:repository]
32
32
 
33
33
  g = RDF::Graph.new
@@ -103,7 +103,7 @@ module Sinatra
103
103
  app.helpers(Sinatra::SPARQL::Helpers)
104
104
  app.send(:include, ::SPARQL)
105
105
  app.send(:include, ::RDF)
106
- app.send(:include, ::LinkedData)
106
+ app.send(:include, ::LinkedData) if defined?(::LinkedData)
107
107
  end
108
108
  end
109
109
  end
@@ -1,16 +1,18 @@
1
+ require 'sxp'
1
2
  require 'sparql/extensions'
3
+ require 'sparql/algebra/sxp_extensions'
2
4
 
3
5
  ##
4
6
  # A SPARQL for RDF.rb.
5
7
  #
6
- # @see http://www.w3.org/TR/sparql11-query
8
+ # @see https://www.w3.org/TR/sparql11-query
7
9
  module SPARQL
8
10
  autoload :Algebra, 'sparql/algebra'
9
11
  autoload :Grammar, 'sparql/grammar'
10
12
  autoload :Results, 'sparql/results'
11
13
  autoload :VERSION, 'sparql/version'
12
14
 
13
- # @see http://rubygems.org/gems/sparql-client
15
+ # @see https://rubygems-client
14
16
  autoload :Client, 'sparql/client'
15
17
 
16
18
  ##
@@ -28,8 +30,8 @@ module SPARQL
28
30
  # a `queryable` object such as an RDF::Graph
29
31
  # or RDF::Repository.
30
32
  # @raise [Parser::Error] on invalid input
31
- def self.parse(query, options = {})
32
- query = Grammar::Parser.new(query, options).parse(options[:update] ? :UpdateUnit : :QueryUnit)
33
+ def self.parse(query, **options)
34
+ query = Grammar::Parser.new(query, **options).parse(options[:update] ? :UpdateUnit : :QueryUnit)
33
35
  end
34
36
 
35
37
  ##
@@ -52,12 +54,13 @@ module SPARQL
52
54
  # results = SPARQL.execute("SELECT * WHERE { ?s ?p ?o }", repository)
53
55
  #
54
56
  # @param [IO, StringIO, String, #to_s] query
57
+ # @param [RDF::Queryable] queryable
55
58
  # @param [Hash{Symbol => Object}] options
56
- # @option options [RDF::Queryable] :queryable
57
- # @option options [RDF::URI, String, Array<RDF::URI, String>] :load_datasets
58
- # One or more URIs used to initialize a new instance of `queryable` in the default graph.
59
+ # @option options [Boolean] :optimize
60
+ # Optimize query before execution.
59
61
  # @option options [RDF::URI, String, Array<RDF::URI, String>] :default_graph_uri
60
- # One or more URIs used to initialize a new instance of `queryable` in the default graph.
62
+ # @option options [RDF::URI, String, Array<RDF::URI, String>] :load_datasets
63
+ # One or more URIs used to initialize a new instance of `queryable` in the default graph. One or more URIs used to initialize a new instance of `queryable` in the default graph.
61
64
  # @option options [RDF::URI, String, Array<RDF::URI, String>] :named_graph_uri
62
65
  # One or more URIs used to initialize the `queryable` as a named graph.
63
66
  # @yield [solution]
@@ -67,8 +70,9 @@ module SPARQL
67
70
  # @return [RDF::Graph, Boolean, RDF::Query::Solutions::Enumerator]
68
71
  # Note, results may be used with {SPARQL.serialize_results} to obtain appropriate output encoding.
69
72
  # @raise [SPARQL::MalformedQuery] on invalid input
70
- def self.execute(query, queryable, options = {}, &block)
71
- query = self.parse(query, options)
73
+ def self.execute(query, queryable, **options, &block)
74
+ query = self.parse(query, **options)
75
+ query = query.optimize(**options) if options[:optimize]
72
76
  queryable = queryable || RDF::Repository.new
73
77
 
74
78
  case options.fetch(:debug, nil)
@@ -1,4 +1,4 @@
1
- require 'rdf' # @see http://rubygems.org/gems/rdf
1
+ require 'rdf' # @see https://rubygems.org/gems/rdf
2
2
  require 'rdf/xsd'
3
3
 
4
4
  module SPARQL
@@ -141,21 +141,21 @@ module SPARQL
141
141
  # ## Constructing operator expressions manually
142
142
  #
143
143
  # Operator(:isBlank).new(RDF::Node(:foobar)).to_sxp #=> "(isBlank _:foobar)"
144
- # Operator(:isIRI).new(RDF::URI('http://rubygems.org/gems/rdf/')).to_sxp #=> "(isIRI <http://rubygems.org/gems/rdf/>)"
145
- # Operator(:isLiteral).new(RDF::Literal(3.1415)).to_sxp #=> "(isLiteral 3.1415)"
146
- # Operator(:str).new(Operator(:datatype).new(RDF::Literal(3.1415))).to_sxp #=> "(str (datatype 3.1415))"
144
+ # Operator(:isIRI).new(RDF::URI('https://rubygems.org/gems/rdf/')).to_sxp #=> "(isIRI <https://rubygems.org/gems/rdf/>)"
145
+ # Operator(:isLiteral).new(RDF::Literal(3.1415)).to_sxp #=> "(isLiteral 3.1415e0)"
146
+ # Operator(:str).new(Operator(:datatype).new(RDF::Literal(3.1415))).to_sxp #=> "(str (datatype 3.1415e0))"
147
147
  #
148
148
  # ## Constructing operator expressions using SSE forms
149
149
  #
150
150
  # SPARQL::Algebra::Expression[:isBlank, RDF::Node(:foobar)].to_sxp #=> "(isBlank _:foobar)"
151
- # SPARQL::Algebra::Expression[:isIRI, RDF::URI('http://rubygems.org/gems/rdf/')].to_sxp #=> "(isIRI <http://rubygems.org/gems/rdf/>)"
152
- # SPARQL::Algebra::Expression[:isLiteral, RDF::Literal(3.1415)].to_sxp #=> "(isLiteral 3.1415)"
153
- # SPARQL::Algebra::Expression[:str, [:datatype, RDF::Literal(3.1415)]].to_sxp #=> "(str (datatype 3.1415))"
151
+ # SPARQL::Algebra::Expression[:isIRI, RDF::URI('https://rubygems.org/gems/rdf/')].to_sxp #=> "(isIRI <https://rubygems.org/gems/rdf/>)"
152
+ # SPARQL::Algebra::Expression[:isLiteral, RDF::Literal(3.1415)].to_sxp #=> "(isLiteral 3.1415e0)"
153
+ # SPARQL::Algebra::Expression[:str, [:datatype, RDF::Literal(3.1415)]].to_sxp #=> "(str (datatype 3.1415e0))"
154
154
  #
155
155
  # ## Constructing operator expressions using SSE strings
156
156
  #
157
157
  # SPARQL::Algebra::Expression.parse('(isBlank _:foobar)')
158
- # SPARQL::Algebra::Expression.parse('(isIRI <http://rubygems.org/gems/rdf/>)')
158
+ # SPARQL::Algebra::Expression.parse('(isIRI <https://rubygems.org/gems/rdf/>)')
159
159
  # SPARQL::Algebra::Expression.parse('(isLiteral 3.1415)')
160
160
  # SPARQL::Algebra::Expression.parse('(str (datatype 3.1415))')
161
161
  #
@@ -165,11 +165,6 @@ module SPARQL
165
165
  # Operator(:isIRI).evaluate(RDF::Vocab::DC.title) #=> RDF::Literal::TRUE
166
166
  # Operator(:isLiteral).evaluate(RDF::Literal(3.1415)) #=> RDF::Literal::TRUE
167
167
  #
168
- # ## Optimizing expressions containing constant subexpressions
169
- #
170
- # SPARQL::Algebra::Expression.parse('(sameTerm ?var ?var)').optimize #=> RDF::Literal::TRUE
171
- # SPARQL::Algebra::Expression.parse('(* -2 (- (* (+ 1 2) (+ 3 4))))').optimize #=> RDF::Literal(42)
172
- #
173
168
  # ## Evaluating expressions on a solution sequence
174
169
  #
175
170
  # # Find all people and their names & e-mail addresses:
@@ -372,8 +367,8 @@ module SPARQL
372
367
  # @param [Hash{Symbol => Object}] options
373
368
  # any additional options (see {Operator#initialize})
374
369
  # @return [SPARQL::Algebra::Operator]
375
- def parse(sse, options = {})
376
- Expression.parse(sse, options)
370
+ def parse(sse, **options)
371
+ Expression.parse(sse, **options)
377
372
  end
378
373
  module_function :parse
379
374
 
@@ -390,8 +385,8 @@ module SPARQL
390
385
  # @yieldparam [SPARQL::Algebra::Expression] expression
391
386
  # @yieldreturn [void] ignored
392
387
  # @return [Expression]
393
- def open(sse, options = {})
394
- Expression.open(sse, options)
388
+ def open(sse, **options)
389
+ Expression.open(sse, **options)
395
390
  end
396
391
  module_function :open
397
392
 
@@ -405,8 +400,7 @@ module SPARQL
405
400
  def Expression(*sse)
406
401
  Expression.for(*sse)
407
402
  end
408
- alias_method :Expr, :Expression
409
- module_function :Expr, :Expression
403
+ module_function :Expression
410
404
 
411
405
  ##
412
406
  # @example
@@ -417,8 +411,7 @@ module SPARQL
417
411
  def Operator(name, arity = nil)
418
412
  Operator.for(name, arity)
419
413
  end
420
- alias_method :Op, :Operator
421
- module_function :Op, :Operator
414
+ module_function :Operator
422
415
 
423
416
  ##
424
417
  # @example
@@ -430,8 +423,7 @@ module SPARQL
430
423
  def Variable(name)
431
424
  Variable.new(name)
432
425
  end
433
- alias_method :Var, :Variable
434
- module_function :Var, :Variable
426
+ module_function :Variable
435
427
 
436
428
  Variable = RDF::Query::Variable
437
429
  end # Algebra
@@ -6,8 +6,8 @@ module SPARQL; module Algebra
6
6
  # or more operands which are `Enumerable` lists of `RDF::Term`
7
7
  # and return a single `RDF::Term` or `TypeError`.
8
8
  #
9
- # @see http://www.w3.org/TR/sparql11-query/#setFunctions
10
- # @see http://www.w3.org/TR/sparql11-query/#aggregates
9
+ # @see https://www.w3.org/TR/sparql11-query/#setFunctions
10
+ # @see https://www.w3.org/TR/sparql11-query/#aggregates
11
11
  #
12
12
  # @abstract
13
13
  module Aggregate
@@ -24,12 +24,12 @@ module SPARQL; module Algebra
24
24
  # @return [RDF::Term]
25
25
  # @raise [TypeError]
26
26
  # @abstract
27
- def aggregate(solutions = [], options = {})
27
+ def aggregate(solutions = [], **options)
28
28
  operands.shift if distinct = (operands.first == :distinct)
29
29
  args_enum = solutions.map do |solution|
30
30
  operands.map do |operand|
31
31
  begin
32
- operand.evaluate(solution, options.merge(depth: options[:depth].to_i + 1))
32
+ operand.evaluate(solution, depth: options[:depth].to_i + 1, **options)
33
33
  rescue TypeError
34
34
  # Ignore errors
35
35
  nil
@@ -13,8 +13,8 @@ module SPARQL; module Algebra
13
13
  # options passed from query
14
14
  # @return [RDF::Term]
15
15
  # @abstract
16
- def evaluate(bindings, options = {})
17
- args = operands.map { |operand| operand.evaluate(bindings, options.merge(depth: options[:depth].to_i + 1)) }
16
+ def evaluate(bindings, **options)
17
+ args = operands.map { |operand| operand.evaluate(bindings, depth: options[:depth].to_i + 1, **options) }
18
18
  options[:memoize] ? memoize(*args) : apply(*args)
19
19
  end
20
20
 
@@ -19,14 +19,7 @@ module SPARQL; module Algebra
19
19
  # @yieldparam [SPARQL::Algebra::Expression] expression
20
20
  # @yieldreturn [void] ignored
21
21
  # @return [Expression]
22
- def self.parse(sse, options = {}, &block)
23
- begin
24
- require 'sxp' # @see http://rubygems.org/gems/sxp
25
- rescue LoadError
26
- abort "SPARQL::Algebra::Expression.parse requires the SXP gem (hint: `gem install sxp')."
27
- end
28
- require 'sparql/algebra/sxp_extensions'
29
-
22
+ def self.parse(sse, **options, &block)
30
23
  sse = sse.encode(Encoding::UTF_8)
31
24
  sxp = SXP::Reader::SPARQL.new(sse) do |reader|
32
25
  # Set base_uri if we have one
@@ -38,7 +31,7 @@ module SPARQL; module Algebra
38
31
  Operator.base_uri = options.delete(:base_uri) if options.has_key?(:base_uri)
39
32
  Operator.prefixes = sxp.prefixes || {}
40
33
 
41
- expression = self.new(sxp_result, options)
34
+ expression = self.new(sxp_result, **options)
42
35
 
43
36
  yield(expression) if block_given?
44
37
  expression
@@ -57,8 +50,8 @@ module SPARQL; module Algebra
57
50
  # @yieldparam [SPARQL::Algebra::Expression] expression
58
51
  # @yieldreturn [void] ignored
59
52
  # @return [Expression]
60
- def self.open(filename, options = {}, &block)
61
- RDF::Util::File.open_file(filename, options) do |file|
53
+ def self.open(filename, **options, &block)
54
+ RDF::Util::File.open_file(filename, **options) do |file|
62
55
  options[:base_uri] ||= filename
63
56
  Expression.parse(file, options, &block)
64
57
  end
@@ -87,7 +80,7 @@ module SPARQL; module Algebra
87
80
  # any additional options (see {Operator#initialize})
88
81
  # @return [Expression]
89
82
  # @raise [TypeError] if any of the operands is invalid
90
- def self.new(sse, options = {})
83
+ def self.new(sse, **options)
91
84
  raise ArgumentError, "invalid SPARQL::Algebra::Expression form: #{sse.inspect}" unless sse.is_a?(Array)
92
85
 
93
86
  operator = Operator.for(sse.first, sse.length - 1)
@@ -95,7 +88,7 @@ module SPARQL; module Algebra
95
88
  return case sse.first
96
89
  when Array
97
90
  debug(options) {"Map array elements #{sse}"}
98
- sse.map {|s| self.new(s, options.merge(depth: options[:depth].to_i + 1))}
91
+ sse.map {|s| self.new(s, depth: options[:depth].to_i + 1, **options)}
99
92
  else
100
93
  debug(options) {"No operator found for #{sse.first}"}
101
94
  sse.map do |s|
@@ -110,7 +103,7 @@ module SPARQL; module Algebra
110
103
  debug(options) {"Operator=#{operator.inspect}, Operand=#{operand.inspect}"}
111
104
  case operand
112
105
  when Array
113
- self.new(operand, options.merge(depth: options[:depth].to_i + 1))
106
+ self.new(operand, depth: options[:depth].to_i + 1, **options)
114
107
  when Operator, Variable, RDF::Term, RDF::Query, Symbol
115
108
  operand
116
109
  when TrueClass, FalseClass, Numeric, String, DateTime, Date, Time
@@ -175,8 +168,8 @@ module SPARQL; module Algebra
175
168
  # @param [RDF::URI] function
176
169
  # @param [Array<RDF::Term>] args splat of args to function
177
170
  # @return [RDF::Term]
178
- # @see http://www.w3.org/TR/sparql11-query/#extensionFunctions
179
- # @see http://www.w3.org/TR/sparql11-query/#FunctionMapping
171
+ # @see https://www.w3.org/TR/sparql11-query/#extensionFunctions
172
+ # @see https://www.w3.org/TR/sparql11-query/#FunctionMapping
180
173
  def self.extension(function, *args)
181
174
  if function.to_s.start_with?(RDF::XSD.to_s)
182
175
  self.cast(function, args.first)
@@ -197,7 +190,7 @@ module SPARQL; module Algebra
197
190
  # Value, which should be a typed literal, where the type must be that specified
198
191
  # @raise [TypeError] if datatype is not a URI or value cannot be cast to datatype
199
192
  # @return [RDF::Term]
200
- # @see http://www.w3.org/TR/sparql11-query/#FunctionMapping
193
+ # @see https://www.w3.org/TR/sparql11-query/#FunctionMapping
201
194
  def self.cast(datatype, value)
202
195
  case datatype
203
196
  when RDF::XSD.dateTime
@@ -280,12 +273,26 @@ module SPARQL; module Algebra
280
273
  ##
281
274
  # Returns an optimized version of this expression.
282
275
  #
283
- # This is the default implementation, which simply returns `self`.
276
+ # This is the default implementation, which simply returns a copy of `self`.
284
277
  # Subclasses can override this method in order to implement something
285
278
  # more useful.
286
279
  #
287
- # @return [Expression] `self`
288
- def optimize
280
+ # @param [Hash{Symbol => Object}] options
281
+ # any additional options for optimization
282
+ # @return [Expression] a copy of `self`
283
+ # @see RDF::Query#optimize
284
+ def optimize(**options)
285
+ self.deep_dup.optimize!(**options)
286
+ end
287
+
288
+ ##
289
+ # Optimizes this query.
290
+ #
291
+ # @param [Hash{Symbol => Object}] options
292
+ # any additional options for optimization
293
+ # @return [self]
294
+ # @see RDF::Query#optimize!
295
+ def optimize!(**options)
289
296
  self
290
297
  end
291
298
 
@@ -313,7 +320,7 @@ module SPARQL; module Algebra
313
320
  # more useful.
314
321
  #
315
322
  # @return [Array] `self`
316
- # @see http://openjena.org/wiki/SSE
323
+ # @see https://openjena.org/wiki/SSE
317
324
  def to_sxp_bin
318
325
  self
319
326
  end
@@ -4,7 +4,7 @@ require 'json'
4
4
  # Extensions for Ruby's `NilClass` class.
5
5
  class NilClass
6
6
 
7
- def evaluate(bindings, options = {})
7
+ def evaluate(bindings, **options)
8
8
  self
9
9
  end
10
10
 
@@ -27,6 +27,22 @@ class Object
27
27
  def to_sse
28
28
  SXP::Generator.string(self.to_sxp_bin)
29
29
  end
30
+
31
+ ##
32
+ # A duplicate of this object.
33
+ #
34
+ # @return [Object] a copy of `self`
35
+ # @see SPARQL::Algebra::Expression#optimize
36
+ def optimize(**options)
37
+ self.deep_dup
38
+ end
39
+
40
+ ##
41
+ # Default for deep_dup is shallow dup
42
+ # @return [Object]
43
+ def deep_dup
44
+ dup
45
+ end
30
46
  end
31
47
 
32
48
  ##
@@ -52,9 +68,9 @@ class Array
52
68
  # @param [Hash{Symbol => Object}] options ({})
53
69
  # options passed from query
54
70
  # @return [RDF::Term]
55
- # @see {SPARQL::Algebra::Expression.evaluate}
56
- def evaluate(bindings, options = {})
57
- SPARQL::Algebra::Expression.extension(*self.map {|o| o.evaluate(bindings, options)})
71
+ # @see SPARQL::Algebra::Expression.evaluate
72
+ def evaluate(bindings, **options)
73
+ SPARQL::Algebra::Expression.extension(*self.map {|o| o.evaluate(bindings, **options)})
58
74
  end
59
75
 
60
76
  ##
@@ -66,11 +82,34 @@ class Array
66
82
  # @param [Hash{Symbol => Object}] options
67
83
  # @raise [NotImplementedError]
68
84
  # If an attempt is made to perform an unsupported operation
69
- # @see http://www.w3.org/TR/sparql11-query/#sparqlAlgebra
70
- def execute(queryable, options = {})
85
+ # @see https://www.w3.org/TR/sparql11-query/#sparqlAlgebra
86
+ def execute(queryable, **options)
71
87
  raise NotImplementedError, "SPARQL::Algebra '#{first}' operator not implemented"
72
88
  end
73
89
 
90
+ ##
91
+ # Return an optimized version of this array.
92
+ #
93
+ # @return [Array] a copy of `self`
94
+ # @see SPARQL::Algebra::Expression#optimize
95
+ def optimize(**options)
96
+ self.map do |op|
97
+ op.optimize(**options) if op.respond_to?(:optimize)
98
+ end
99
+ end
100
+
101
+ ##
102
+ # Binds the pattern to a solution, making it no longer variable if all variables are resolved to bound variables
103
+ #
104
+ # @param [RDF::Query::Solution] solution
105
+ # @return [self]
106
+ def bind(solution)
107
+ map! do |op|
108
+ op.respond_to?(:bind) ? op.bind(solution) : op
109
+ end
110
+ self
111
+ end
112
+
74
113
  ##
75
114
  # Returns `true` if any of the operands are variables, `false`
76
115
  # otherwise.
@@ -78,7 +117,7 @@ class Array
78
117
  # @return [Boolean] `true` or `false`
79
118
  # @see #constant?
80
119
  def variable?
81
- any?(&:variable?)
120
+ any? {|op| op.respond_to?(:variable?) && op.variable?}
82
121
  end
83
122
  def constant?; !(variable?); end
84
123
 
@@ -166,6 +205,12 @@ class Array
166
205
  each {|e| e.validate! if e.respond_to?(:validate!)}
167
206
  self
168
207
  end
208
+
209
+ ##
210
+ # Deep duplicate
211
+ def deep_dup
212
+ map(&:deep_dup)
213
+ end
169
214
  end
170
215
 
171
216
  ##
@@ -179,6 +224,21 @@ class Hash
179
224
  to_a.to_sxp_bin
180
225
  end
181
226
  def to_sxp; to_sxp_bin; end
227
+
228
+ ##
229
+ # A duplicate of this hash.
230
+ #
231
+ # @return [Hash] a copy of `self`
232
+ # @see SPARQL::Algebra::Expression#optimize
233
+ def optimize(**options)
234
+ self.deep_dup
235
+ end
236
+
237
+ ##
238
+ # Deep duplicate
239
+ def deep_dup
240
+ inject({}) {|memo, (k, v)| memo.merge(k => v.deep_dup)}
241
+ end
182
242
  end
183
243
 
184
244
  ##
@@ -191,7 +251,7 @@ module RDF::Term
191
251
  # @param [Hash{Symbol => Object}] options ({})
192
252
  # options passed from query
193
253
  # @return [RDF::Term]
194
- def evaluate(bindings, options = {})
254
+ def evaluate(bindings, **options)
195
255
  self
196
256
  end
197
257
 
@@ -210,6 +270,17 @@ module RDF::Term
210
270
  def vars
211
271
  variable? ? [self] : []
212
272
  end
273
+
274
+ ##
275
+ # A duplicate of this term.
276
+ #
277
+ # @return [RDF::Term] a copy of `self`
278
+ # @see SPARQL::Algebra::Expression#optimize
279
+ def optimize(**options)
280
+ optimized = self.deep_dup
281
+ optimized.lexical = nil if optimized.respond_to?(:lexical=)
282
+ optimized
283
+ end
213
284
  end # RDF::Term
214
285
 
215
286
  # Override RDF::Queryable to execute against SPARQL::Algebra::Query elements as well as RDF::Query and RDF::Pattern
@@ -243,7 +314,7 @@ module RDF::Queryable
243
314
  solutions = if method(:query_execute).arity == 1
244
315
  query_execute(pattern, &block)
245
316
  else
246
- query_execute(pattern, options, &block)
317
+ query_execute(pattern, **options, &block)
247
318
  end
248
319
  after_query(pattern) if respond_to?(:after_query)
249
320
 
@@ -252,13 +323,12 @@ module RDF::Queryable
252
323
  solutions
253
324
  else
254
325
  # Return an enumerator
255
- enum_for(:query, pattern, options)
326
+ enum_for(:query, pattern, **options)
256
327
  end
257
328
  else
258
- query_without_sparql(pattern, options, &block)
329
+ query_without_sparql(pattern, **options, &block)
259
330
  end
260
331
  end
261
-
262
332
  end
263
333
 
264
334
  class RDF::Statement
@@ -271,6 +341,15 @@ class RDF::Statement
271
341
  [:triple, subject, predicate, object]
272
342
  end
273
343
  end
344
+
345
+ ##
346
+ # A duplicate of this Statement.
347
+ #
348
+ # @return [RDF::Statement] a copy of `self`
349
+ # @see SPARQL::Algebra::Expression#optimize
350
+ def optimize(**options)
351
+ self.dup
352
+ end
274
353
  end
275
354
 
276
355
  class RDF::Query
@@ -306,6 +385,16 @@ class RDF::Query
306
385
  end
307
386
  end
308
387
 
388
+ ##
389
+ # Binds the pattern to a solution, making it no longer variable if all variables are resolved to bound variables
390
+ #
391
+ # @param [RDF::Query::Solution] solution
392
+ # @return [self]
393
+ def bind(solution)
394
+ patterns.each {|p| p.bind(solution)}
395
+ self
396
+ end
397
+
309
398
  # Query results in a boolean result (e.g., ASK)
310
399
  # @return [Boolean]
311
400
  def query_yields_boolean?
@@ -338,6 +427,26 @@ class RDF::Query
338
427
  variables.values
339
428
  end
340
429
 
430
+ alias_method :optimize_without_expression!, :optimize!
431
+ ##
432
+ # Optimize the query, removing lexical shortcuts in URIs
433
+ #
434
+ # @return [self]
435
+ # @see SPARQL::Algebra::Expression#optimize!
436
+ def optimize!(**options)
437
+ @patterns = @patterns.map do |pattern|
438
+ components = pattern.to_a.map do |term|
439
+ if term.respond_to?(:lexical=)
440
+ term.dup.instance_eval {@lexical = nil; self}
441
+ else
442
+ term
443
+ end
444
+ end
445
+ RDF::Query::Pattern.from(components, **pattern.options)
446
+ end
447
+ self.optimize_without_expression!(**options)
448
+ end
449
+
341
450
  ##
342
451
  # Returns `true` if this is executable (i.e., contains a graph patterns), `false`
343
452
  # otherwise.
@@ -386,14 +495,18 @@ class RDF::Query::Variable
386
495
  # options passed from query
387
496
  # @return [RDF::Term] the value of this variable
388
497
  # @raise [TypeError] if the variable is not bound
389
- def evaluate(bindings, options = {})
498
+ def evaluate(bindings, **options)
390
499
  raise TypeError if bindings.respond_to?(:bound?) && !bindings.bound?(self)
391
500
  bindings[name.to_sym]
392
501
  end
393
502
 
394
- def to_s
395
- prefix = distinguished? || name.to_s[0,1] == '.' ? '?' : "??"
396
- unbound? ? "#{prefix}#{name}" : "#{prefix}#{name}=#{value}"
503
+ ##
504
+ # Return self
505
+ #
506
+ # @return [RDF::Query::Variable] a copy of `self`
507
+ # @see SPARQL::Algebra::Expression#optimize
508
+ def optimize(**options)
509
+ self
397
510
  end
398
511
  end # RDF::Query::Variable
399
512
 
@@ -424,3 +537,16 @@ class RDF::Query::Solutions
424
537
  end
425
538
  alias_method :filter!, :filter
426
539
  end # RDF::Query::Solutions
540
+
541
+ ##
542
+ # Extensions for `RDF::Query::Solution`.
543
+ class RDF::Query::Solution
544
+ ##
545
+ # Returns the SXP representation of this object, defaults to `self`.
546
+ #
547
+ # @return [String]
548
+ def to_sxp_bin
549
+ to_a.to_sxp_bin
550
+ end
551
+ def to_sxp; to_sxp_bin; end
552
+ end # RDF::Query::Solution