Skip to content

Commit 55af903

Browse files
committed
Finish 3.3.2
2 parents 101fe38 + 8401834 commit 55af903

File tree

120 files changed

+59013
-75074
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

120 files changed

+59013
-75074
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
strategy:
2020
fail-fast: false
2121
matrix:
22-
ruby: ['3.0', 3.1, 3.2, 3.3, ruby-head, jruby]
22+
ruby: ['3.0', 3.1, 3.2, 3.3, 3.4, ruby-head, jruby]
2323
steps:
2424
- name: Clone repository
2525
uses: actions/checkout@v3

.github/workflows/generate-docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
- name: Set up Ruby
1515
uses: ruby/setup-ruby@v1
1616
with:
17-
ruby-version: "3.1"
17+
ruby-version: "3.4"
1818
- name: Install required gem dependencies
1919
run: gem install yard --no-document
2020
- name: Build YARD Ruby Documentation

Gemfile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ group :development do
1414
gem 'json-ld-preloaded',github: 'ruby-rdf/json-ld-preloaded', branch: 'develop'
1515
gem 'ld-patch', github: 'ruby-rdf/ld-patch', branch: 'develop'
1616
gem 'linkeddata', github: 'ruby-rdf/linkeddata', branch: 'develop'
17-
gem 'rdf-hamster-repo', github: 'ruby-rdf/rdf-hamster-repo', branch: 'develop'
17+
gem 'rdf-hamster-repo', github: 'ruby-rdf/rdf-hamster-repo', branch: 'develop'
1818
gem 'rdf-isomorphic', github: 'ruby-rdf/rdf-isomorphic', branch: 'develop'
1919
gem 'rdf-json', github: 'ruby-rdf/rdf-json', branch: 'develop'
2020
gem 'rdf-microdata', github: 'ruby-rdf/rdf-microdata', branch: 'develop'
2121
gem 'rdf-n3', github: 'ruby-rdf/rdf-n3', branch: 'develop'
2222
gem 'rdf-normalize', github: 'ruby-rdf/rdf-normalize', branch: 'develop'
23-
gem 'rdf-ordered-repo', github: 'ruby-rdf/rdf-ordered-repo', branch: 'develop'
23+
gem 'rdf-ordered-repo', github: 'ruby-rdf/rdf-ordered-repo', branch: 'develop'
2424
gem 'rdf-rdfa', github: 'ruby-rdf/rdf-rdfa', branch: 'develop'
2525
gem 'rdf-rdfxml', github: 'ruby-rdf/rdf-rdfxml', branch: 'develop'
2626
gem 'rdf-reasoner', github: 'ruby-rdf/rdf-reasoner', branch: 'develop'
@@ -41,8 +41,8 @@ group :debug do
4141
gem 'shotgun' unless ENV['CI']
4242
gem 'pry'
4343
gem 'pry-byebug', platforms: :mri
44-
gem 'redcarpet', platforms: :ruby
45-
gem 'ruby-prof', platforms: :mri
44+
gem 'redcarpet', platforms: :ruby
45+
gem 'ruby-prof', platforms: :mri
4646
end
4747

4848
group :test do

README.md

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ An implementation of [SPARQL][] for [RDF.rb][].
2727
* Implementation Report: {file:etc/earl.html EARL}
2828
* Compatible with Ruby >= 3.0.
2929
* Supports Unicode query strings both on all versions of Ruby.
30-
* Provisional support for [SPARQL-star][].
30+
* Provisional support for [SPARQL 1.2][].
3131

3232
## Description
3333

@@ -68,17 +68,20 @@ Not supported:
6868
* [Entailment Regimes][SPARQL 1.1 Entailment Regimes], and
6969
* [Graph Store HTTP Protocol][SPARQL 1.1 Graph Store HTTP Protocol] but the closely related [Linked Data Platform][] implemented in [rdf-ldp](https://github.com/ruby-rdf/rdf-ldp) supports these use cases.
7070

71+
### Optimizations
72+
Generally, optimizing a query can lead to improved performance, sometimes dramatically (e.g., `?s rdf:rest*/rdf:first ?o`). Optimization can be done when parsing a query using the `:optimize` option, or the `optimize` method on a parsed query.
73+
7174
### Updates for RDF 1.1
7275
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](https://www.w3.org/TR/rdf11-concepts/) rather than [RDF 1.0](https://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.
7376

7477
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`.
7578

76-
### SPARQL 1.2
77-
The gem supports some of the extensions proposed by the [SPARQL 1.2 Community Group](https://github.com/w3c/sparql-12). In particular, the following extensions are now implemented:
79+
### SPARQL Dev
80+
The gem supports some of the extensions proposed by the [SPARQL Dev Community Group](https://github.com/w3c/sparql-dev). In particular, the following extensions are now implemented:
7881

79-
* [SEP-0002: better support for Durations, Dates, and Times](https://github.com/w3c/sparql-12/blob/main/SEP/SEP-0002/sep-0002.md)
82+
* [SEP-0002: better support for Durations, Dates, and Times](https://github.com/w3c/sparql-dev/blob/main/SEP/SEP-0002/sep-0002.md)
8083
* This includes full support for `xsd:date`, `xsd:time`, `xsd:duration`, `xsd:dayTimeDuration`, and `xsd:yearMonthDuration` along with associated XPath/XQuery functions including a new `ADJUST` builtin. (**Note: This feature is subject to change or elimination as the standards process progresses.**)
81-
* [SEP-0003: Property paths with a min/max hop](https://github.com/w3c/sparql-12/blob/main/SEP/SEP-0003/sep-0003.md)
84+
* [SEP-0003: Property paths with a min/max hop](https://github.com/w3c/sparql-dev/blob/main/SEP/SEP-0003/sep-0003.md)
8285
* This includes support for non-counting path forms such as `rdf:rest{1,3}` to match the union of paths `rdf:rest`, `rdf:rest/rdf:rest`, and `rdf:rest/rdf:rest/rdf:rest`. (**Note: This feature is subject to change or elimination as the standards process progresses.**)
8386

8487
### SPARQL Extension Functions
@@ -107,9 +110,9 @@ See {SPARQL::Algebra::Expression.register_extension} for details.
107110

108111
A call to execute a parsed query can include pre-bound variables, which cause queries to be executed with matching variables bound as defined. Variable pre-binding can be done using a Hash structure, or a Query Solution. See [Query with Binding example](#query-with-binding) and {SPARQL::Algebra::Query#execute}.
109112

110-
### SPARQLStar (SPARQL-star)
113+
### SPARQL 1.2
111114

112-
The gem supports [SPARQL-star][] where patterns may include sub-patterns recursively, for a kind of Reification.
115+
The gem supports [SPARQL 1.2][] where patterns may include sub-patterns recursively, for a kind of Reification.
113116

114117
For example, the following Turtle* file uses a statement as the subject of another statement:
115118

@@ -170,7 +173,7 @@ As well as a `CONSTRUCT`:
170173
<<?bob foaf:age ?age>> ?b ?c .
171174
}
172175

173-
Note that results can be serialized only when the format supports [RDF-star][].
176+
Note that results can be serialized only when the format supports [SPARQL 1,2][].
174177

175178
#### SPARQL results
176179

@@ -462,8 +465,6 @@ see <https://unlicense.org/> or the accompanying {file:UNLICENSE}.
462465

463466
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](https://www.w3.org/Consortium/Legal/2002/copyright-documents-20021231).
464467

465-
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.
466-
467468
[Ruby]: https://ruby-lang.org/
468469
[RDF]: https://www.w3.org/RDF/
469470
[RDF::DO]: https://rubygems.org/gems/rdf-do
@@ -474,20 +475,17 @@ A copy of the [SPARQL 1.0 tests][] and [SPARQL 1.1 tests][] are also included in
474475
[PDD]: https://unlicense.org/#unlicensing-contributions
475476
[SPARQL]: https://en.wikipedia.org/wiki/SPARQL
476477
[SPARQL 1.0]: https://www.w3.org/TR/sparql11-query/
477-
[SPARQL 1.0 tests]:https://www.w3.org/2001/sw/DataAccess/tests/
478-
[SPARQL 1.1 tests]: https://www.w3.org/2009/sparql/docs/tests/
479478
[SSE]: https://jena.apache.org/documentation/notes/sse.html
480479
[SXP]: https://dryruby.github.io/sxp
481480
[grammar]: https://www.w3.org/TR/sparql11-query/#grammar
482481
[RDF 1.1]: https://www.w3.org/TR/rdf11-concepts
483482
[RDF.rb]: https://ruby-rdf.github.io/rdf
484-
[RDF-star]: https://w3c.github.io/rdf-star/rdf-star-cg-spec.html
485-
[SPARQL-star]: https://w3c.github.io/rdf-star/rdf-star-cg-spec.html#sparql-query-language
483+
[SPARQL 1.2]: https://www.w3.org/TR/sparql12-query
486484
[Linked Data]: https://rubygems.org/gems/linkeddata
487485
[SPARQL doc]: https://ruby-rdf.github.io/sparql/frames
488486
[SPARQL XML]: https://www.w3.org/TR/rdf-sparql-XMLres/
489487
[SPARQL JSON]: https://www.w3.org/TR/rdf-sparql-json-res/
490-
[SPARQL EBNF]: https://www.w3.org/TR/sparql11-query/#sparqlGrammar
488+
[SPARQL EBNF]: https://www.w3.org/TR/sparql12-query/#sparqlGrammar
491489

492490
[SSD]: https://www.w3.org/TR/sparql11-service-description/
493491
[Rack]: https://rack.github.io

Rakefile

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ namespace :spec do
3434
require 'suite_helper'
3535

3636
puts "load 1.0 tests"
37-
SPARQL::Spec.sparql1_0_tests(true)
37+
SPARQL::Spec.sparql_11_tests(true)
3838
puts "load 1.0 syntax tests"
39-
SPARQL::Spec.sparql1_0_syntax_tests(true)
39+
SPARQL::Spec.sparql_11_syntax_tests(true)
4040
puts "load 1.1 tests"
41-
SPARQL::Spec.sparql1_1_tests(true)
41+
SPARQL::Spec.sparql_11_tests(true)
4242
end
4343
end
4444

@@ -59,8 +59,7 @@ file "etc/manifest-cache.nt" do
5959
graph = RDF::Graph.new do |g|
6060
{
6161
"http://w3c.github.io/rdf-tests/sparql/" => "../w3c-rdf-tests/sparql/",
62-
"https://w3c.github.io/rdf-star/tests/sparql/" => "../w3c-rdf-star/tests/sparql/",
63-
"https://w3c.github.io/sparql-12/tests/" => "spec/w3c-sparql-12/tests/"
62+
"https://w3c.github.io/sparql-dev/tests/" => "../w3c-sparql-dev/tests/"
6463
}.each do |base, path|
6564
Dir.glob("#{path}**/manifest.ttl").each do |man|
6665
puts "load #{man}"
@@ -73,41 +72,42 @@ file "etc/manifest-cache.nt" do
7372
end
7473

7574
desc 'Create versions of ebnf files in etc'
76-
task etc: %w{etc/sparql11.sxp etc/sparql11.html etc/sparql11.ll1.sxp}
75+
task etc: %w{etc/sparql12.sxp etc/sparql12.html etc/sparql12.peg.sxp}
7776

7877
desc 'Build first, follow and branch tables'
7978
task meta: "lib/sparql/grammar/meta.rb"
8079

81-
file "lib/sparql/grammar/meta.rb" => "etc/sparql11.bnf" do |t|
80+
file "lib/sparql/grammar/meta.rb" => "etc/sparql12.bnf" do |t|
8281
sh %{
83-
ebnf --ll1 QueryUnit --ll1 UpdateUnit --format rb \
82+
ebnf --peg --format rb \
8483
--mod-name SPARQL::Grammar::Meta \
8584
--output lib/sparql/grammar/meta.rb \
86-
etc/sparql11.bnf
85+
etc/sparql12.bnf
8786
}
8887
end
8988

90-
file "etc/sparql11.ll1.sxp" => "etc/sparql11.bnf" do |t|
89+
file "etc/sparql12.sxp" => "etc/sparql12.bnf" do |t|
9190
sh %{
92-
ebnf --ll1 QueryUnit --ll1 UpdateUnit --format sxp \
93-
--output etc/sparql11.ll1.sxp \
94-
etc/sparql11.bnf
91+
ebnf --bnf --format sxp \
92+
--output etc/sparql12.sxp \
93+
etc/sparql12.bnf
9594
}
9695
end
9796

98-
file "etc/sparql11.sxp" => "etc/sparql11.bnf" do |t|
97+
file "etc/sparql12.peg.sxp" => "etc/sparql12.bnf" do |t|
9998
sh %{
100-
ebnf --bnf --format sxp \
101-
--output etc/sparql11.sxp \
102-
etc/sparql11.bnf
99+
ebnf --peg --format sxp \
100+
--output etc/sparql12.peg.sxp \
101+
etc/sparql12.bnf
103102
}
104103
end
105104

106-
file "etc/sparql11.html" => "etc/sparql11.bnf" do |t|
105+
file "etc/sparql12.html" => "etc/sparql12.bnf" do |t|
107106
sh %{
108107
ebnf --format html \
109-
--output etc/sparql11.html \
110-
etc/sparql11.bnf
108+
--output etc/sparql12.html \
109+
--renumber \
110+
etc/sparql12.bnf
111111
}
112112
end
113113

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.3.1
1+
3.3.2

bin/sparql

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ require 'rubygems'
33
$:.unshift("../../lib", __FILE__)
44
require 'logger'
55
require 'sparql'
6+
require 'rack'
7+
require 'rackup'
68
begin
79
require 'linkeddata'
810
rescue LoadError
@@ -45,6 +47,8 @@ def run(input, **options)
4547
SPARQL::Grammar.parse(input, **options)
4648
end
4749

50+
query = query.optimize if options[:optimize]
51+
4852
puts ("\nSSE:\n" + query.to_sse) if options[:debug]
4953

5054
if options[:parse_only]
@@ -64,42 +68,46 @@ end
6468

6569
def server(options)
6670
app = SPARQL::Server.application(**options)
67-
Rack::Server.start(app: app, Port: options.fetch(:port, 9292))
71+
Rackup::Server.start(app: app, Port: options.fetch(:port, 9292))
6872
rescue LoadError
69-
$stderr.puts "Running SPARQL server requires Rack and Sinatra to be in environment: #{$!.message}"
73+
$stderr.puts "Running SPARQL server requires Rack, Rackup, and Sinatra to be in environment: #{$!.message}"
7074
end
7175

76+
cmd, input = ARGV.shift, nil
77+
78+
OPT_ARGS = [
79+
["--dataset", GetoptLong::REQUIRED_ARGUMENT, "File containing RDF graph or dataset"],
80+
["--debug", GetoptLong::NO_ARGUMENT, "Debugging output"],
81+
["--execute", "-e", GetoptLong::REQUIRED_ARGUMENT, "Run against source in argument"],
82+
["--format", GetoptLong::REQUIRED_ARGUMENT, "Output format for results (json, xml, csv, tsv, html, sparql, sse, or another RDF format)"],
83+
["--help", "-?", GetoptLong::NO_ARGUMENT, "print this message"],
84+
["--optimize", GetoptLong::NO_ARGUMENT, "Perform query optimizations"],
85+
["--port", "-p", GetoptLong::REQUIRED_ARGUMENT, "Port on which to run server; defaults to 9292"],
86+
["--sse", GetoptLong::NO_ARGUMENT, "Query input is in SSE format"],
87+
["--update", GetoptLong::NO_ARGUMENT, "Process query as a SPARQL Update"],
88+
["--verbose", GetoptLong::NO_ARGUMENT, "Verbose output"],
89+
]
90+
7291
def usage
7392
puts "Usage: #{File.basename($0)} execute [options] query-file Execute a query against the specified dataset"
7493
puts " #{File.basename($0)} parse [options] query-file Parse a query into SPARQL S-Expressions (SSE)"
7594
puts " #{File.basename($0)} query [options] end-point query-file Run the query against a remote end-point"
7695
puts " #{File.basename($0)} server [options] dataset-file Start a server initialized from the specified dataset"
7796
puts "Options:"
78-
puts " --dataset: File containing RDF graph or dataset"
79-
puts " --debug: Display detailed debug output"
80-
puts " --execute,-e: Use option argument as the SPARQL input if no query-file given"
81-
puts " --format: Output format for results (json, xml, csv, tsv, html, sparql, sse, or another RDF format)"
82-
puts " --port,-p Port on which to run server; defaults to 9292"
83-
puts " --sse: Query input is in SSE format"
84-
puts " --update: Process query as a SPARQL Update"
85-
puts " --verbose: Display details of processing"
86-
puts " --help,-?: This message"
97+
width = OPT_ARGS.map do |o|
98+
l = o.first.length
99+
l += o[1].length + 2 if o[1].is_a?(String)
100+
l
101+
end.max
102+
OPT_ARGS.each do |o|
103+
s = " %-*s " % [width, (o[1].is_a?(String) ? "#{o[0,2].join(', ')}" : o[0])]
104+
s += o.last
105+
puts s
106+
end
87107
exit(0)
88108
end
89109

90-
cmd, input = ARGV.shift, nil
91-
92-
opts = GetoptLong.new(
93-
["--dataset", GetoptLong::REQUIRED_ARGUMENT],
94-
["--debug", GetoptLong::NO_ARGUMENT],
95-
["--execute", "-e", GetoptLong::REQUIRED_ARGUMENT],
96-
["--format", GetoptLong::REQUIRED_ARGUMENT],
97-
["--port", "-p", GetoptLong::REQUIRED_ARGUMENT],
98-
["--sse", GetoptLong::NO_ARGUMENT],
99-
["--update", GetoptLong::NO_ARGUMENT],
100-
["--verbose", GetoptLong::NO_ARGUMENT],
101-
["--help", "-?", GetoptLong::NO_ARGUMENT]
102-
)
110+
opts = GetoptLong.new(*OPT_ARGS.map {|o| o[0..-2]})
103111

104112
logger = Logger.new(STDERR)
105113
logger.level = Logger::WARN
@@ -116,6 +124,7 @@ opts.each do |opt, arg|
116124
when '--debug' then options[:debug] = true ; logger.level = Logger::DEBUG
117125
when '--execute' then input = arg
118126
when '--format' then options[:format] = arg.to_sym
127+
when '--optimize' then options[:optimize] = true
119128
when '--port' then options[:port] = arg.to_i
120129
when '--sse' then options[:sse] = true
121130
when '--update' then options[:update] = true

0 commit comments

Comments
 (0)