sparql 0.0.1 → 0.0.2
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.
- data/AUTHORS +3 -0
- data/CREDITS +0 -0
- data/README.markdown +103 -53
- data/UNLICENSE +24 -0
- data/VERSION +1 -0
- data/bin/sparql +87 -0
- data/lib/sparql.rb +105 -22
- data/lib/sparql/algebra.rb +369 -0
- data/lib/sparql/algebra/evaluatable.rb +37 -0
- data/lib/sparql/algebra/expression.rb +284 -0
- data/lib/sparql/algebra/extensions.rb +159 -0
- data/lib/sparql/algebra/operator.rb +492 -0
- data/lib/sparql/algebra/operator/add.rb +34 -0
- data/lib/sparql/algebra/operator/and.rb +65 -0
- data/lib/sparql/algebra/operator/asc.rb +29 -0
- data/lib/sparql/algebra/operator/ask.rb +46 -0
- data/lib/sparql/algebra/operator/base.rb +46 -0
- data/lib/sparql/algebra/operator/bgp.rb +26 -0
- data/lib/sparql/algebra/operator/bound.rb +48 -0
- data/lib/sparql/algebra/operator/compare.rb +84 -0
- data/lib/sparql/algebra/operator/construct.rb +85 -0
- data/lib/sparql/algebra/operator/dataset.rb +77 -0
- data/lib/sparql/algebra/operator/datatype.rb +42 -0
- data/lib/sparql/algebra/operator/desc.rb +17 -0
- data/lib/sparql/algebra/operator/describe.rb +71 -0
- data/lib/sparql/algebra/operator/distinct.rb +50 -0
- data/lib/sparql/algebra/operator/divide.rb +43 -0
- data/lib/sparql/algebra/operator/equal.rb +32 -0
- data/lib/sparql/algebra/operator/exprlist.rb +52 -0
- data/lib/sparql/algebra/operator/filter.rb +71 -0
- data/lib/sparql/algebra/operator/graph.rb +28 -0
- data/lib/sparql/algebra/operator/greater_than.rb +32 -0
- data/lib/sparql/algebra/operator/greater_than_or_equal.rb +33 -0
- data/lib/sparql/algebra/operator/is_blank.rb +35 -0
- data/lib/sparql/algebra/operator/is_iri.rb +37 -0
- data/lib/sparql/algebra/operator/is_literal.rb +36 -0
- data/lib/sparql/algebra/operator/join.rb +67 -0
- data/lib/sparql/algebra/operator/lang.rb +29 -0
- data/lib/sparql/algebra/operator/lang_matches.rb +53 -0
- data/lib/sparql/algebra/operator/left_join.rb +95 -0
- data/lib/sparql/algebra/operator/less_than.rb +32 -0
- data/lib/sparql/algebra/operator/less_than_or_equal.rb +32 -0
- data/lib/sparql/algebra/operator/minus.rb +31 -0
- data/lib/sparql/algebra/operator/multiply.rb +34 -0
- data/lib/sparql/algebra/operator/not.rb +35 -0
- data/lib/sparql/algebra/operator/not_equal.rb +26 -0
- data/lib/sparql/algebra/operator/or.rb +65 -0
- data/lib/sparql/algebra/operator/order.rb +69 -0
- data/lib/sparql/algebra/operator/plus.rb +31 -0
- data/lib/sparql/algebra/operator/prefix.rb +45 -0
- data/lib/sparql/algebra/operator/project.rb +46 -0
- data/lib/sparql/algebra/operator/reduced.rb +47 -0
- data/lib/sparql/algebra/operator/regex.rb +70 -0
- data/lib/sparql/algebra/operator/same_term.rb +46 -0
- data/lib/sparql/algebra/operator/slice.rb +60 -0
- data/lib/sparql/algebra/operator/str.rb +35 -0
- data/lib/sparql/algebra/operator/subtract.rb +32 -0
- data/lib/sparql/algebra/operator/union.rb +55 -0
- data/lib/sparql/algebra/query.rb +99 -0
- data/lib/sparql/algebra/sxp_extensions.rb +35 -0
- data/lib/sparql/algebra/version.rb +20 -0
- data/lib/sparql/extensions.rb +102 -0
- data/lib/sparql/grammar.rb +298 -0
- data/lib/sparql/grammar/lexer.rb +609 -0
- data/lib/sparql/grammar/parser.rb +1383 -0
- data/lib/sparql/grammar/parser/meta.rb +1801 -0
- data/lib/sparql/results.rb +220 -0
- data/lib/sparql/version.rb +20 -0
- metadata +232 -62
- data/Rakefile +0 -22
- data/coverage/index.html +0 -252
- data/coverage/lib-sparql-execute_sparql_rb.html +0 -621
- data/coverage/lib-sparql_rb.html +0 -622
- data/lib/sparql/execute_sparql.rb +0 -27
- data/lib/sparql/sparql.treetop +0 -159
- data/sparql.gemspec +0 -16
- data/spec/spec.opts +0 -2
- data/spec/spec_helper.rb +0 -24
- data/spec/unit/graph_parsing_spec.rb +0 -76
- data/spec/unit/iri_parsing_spec.rb +0 -46
- data/spec/unit/prefixed_names_parsing_spec.rb +0 -40
- data/spec/unit/primitives_parsing_spec.rb +0 -26
- data/spec/unit/sparql_parsing_spec.rb +0 -72
- data/spec/unit/variables_parsing_spec.rb +0 -36
@@ -0,0 +1,35 @@
|
|
1
|
+
##
|
2
|
+
# Extensions for Ruby's `NilClass` class.
|
3
|
+
class NilClass
|
4
|
+
##
|
5
|
+
# Returns the SXP representation of this object.
|
6
|
+
#
|
7
|
+
# @return [String]
|
8
|
+
def to_sxp
|
9
|
+
RDF.nil.to_s
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
##
|
14
|
+
# Extensions for Ruby's `FalseClass` class.
|
15
|
+
class FalseClass
|
16
|
+
##
|
17
|
+
# Returns the SXP representation of this object.
|
18
|
+
#
|
19
|
+
# @return [String]
|
20
|
+
def to_sxp
|
21
|
+
'false'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Extensions for Ruby's `TrueClass` class.
|
27
|
+
class TrueClass
|
28
|
+
##
|
29
|
+
# Returns the SXP representation of this object.
|
30
|
+
#
|
31
|
+
# @return [String]
|
32
|
+
def to_sxp
|
33
|
+
'true'
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
module VERSION
|
3
|
+
VERSION_FILE = File.join(File.expand_path(File.dirname(__FILE__)), "..", "..", "..", "VERSION")
|
4
|
+
MAJOR, MINOR, TINY, EXTRA = File.read(VERSION_FILE).chop.split(".")
|
5
|
+
|
6
|
+
STRING = [MAJOR, MINOR, TINY, EXTRA].compact.join('.')
|
7
|
+
|
8
|
+
##
|
9
|
+
# @return [String]
|
10
|
+
def self.to_s() STRING end
|
11
|
+
|
12
|
+
##
|
13
|
+
# @return [String]
|
14
|
+
def self.to_str() STRING end
|
15
|
+
|
16
|
+
##
|
17
|
+
# @return [Array(Integer, Integer, Integer)]
|
18
|
+
def self.to_a() [MAJOR, MINOR, TINY] end
|
19
|
+
end
|
20
|
+
end; end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'rdf'
|
2
|
+
require 'sparql/results'
|
3
|
+
|
4
|
+
##
|
5
|
+
# Extensions for `RDF::Queryable`
|
6
|
+
module RDF::Queryable
|
7
|
+
##
|
8
|
+
# Concise Bounded Description
|
9
|
+
#
|
10
|
+
# Given a particular node (the starting node) in a particular RDF graph (the source graph), a subgraph of
|
11
|
+
# that particular graph, taken to comprise a concise bounded description of the resource denoted by the
|
12
|
+
# starting node, can be identified as follows:
|
13
|
+
#
|
14
|
+
# 1. Include in the subgraph all statements in the source graph where the subject of the statement is the
|
15
|
+
# starting node;
|
16
|
+
# 2. Recursively, for all statements identified in the subgraph thus far having a blank node object,
|
17
|
+
# include in the subgraph all statements in the source graph where the subject of the statement is the
|
18
|
+
# blank node in question and which are not already included in the subgraph.
|
19
|
+
# 3. Recursively, for all statements included in the subgraph thus far, for all reifications of each
|
20
|
+
# statement in the source graph, include the concise bounded description beginning from the
|
21
|
+
# rdf:Statement node of each reification. (we skip this step)
|
22
|
+
#
|
23
|
+
# This results in a subgraph where the object nodes are either URI references, literals, or blank nodes not
|
24
|
+
# serving as the subject of any statement in the graph.
|
25
|
+
#
|
26
|
+
# Used to implement the SPARQL `describe` operator.
|
27
|
+
#
|
28
|
+
# @param [Array<RDF::Term>] *terms
|
29
|
+
# List of terms to include in the results.
|
30
|
+
# @param [Hash{Symbol => Object}] options
|
31
|
+
# @option options [Boolean] :non_subjects (true)
|
32
|
+
# If `term` is not a `subject` within `self`
|
33
|
+
# then add all `subject`s referencing the term as a `predicate` or `object`.
|
34
|
+
# @option options [RDF::Graph] graph
|
35
|
+
# Graph containing statements already considered.
|
36
|
+
# @yield [statement]
|
37
|
+
# @yieldparam [RDF::Statement] statement
|
38
|
+
# @yieldreturn [void] ignored
|
39
|
+
# @return [RDF::Graph]
|
40
|
+
#
|
41
|
+
# @see http://www.w3.org/Submission/CBD/
|
42
|
+
def concise_bounded_description(*terms, &block)
|
43
|
+
options = terms.last.is_a?(Hash) ? terms.pop.dup : {}
|
44
|
+
options[:non_subjects] = true unless options.has_key?(:non_subjects)
|
45
|
+
|
46
|
+
graph = options[:graph] || RDF::Graph.new
|
47
|
+
|
48
|
+
if options[:non_subjects]
|
49
|
+
query_terms = terms.dup
|
50
|
+
|
51
|
+
# Find terms not in self as a subject and recurse with their subjects
|
52
|
+
terms.reject {|term| self.first(:subject => term)}.each do |term|
|
53
|
+
self.query(:predicate => term) do |statement|
|
54
|
+
query_terms << statement.subject
|
55
|
+
end
|
56
|
+
|
57
|
+
self.query(:object => term) do |statement|
|
58
|
+
query_terms << statement.subject
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
terms = query_terms.uniq
|
63
|
+
end
|
64
|
+
|
65
|
+
# Don't consider term if already in graph
|
66
|
+
terms.reject {|term| graph.first(:subject => term)}.each do |term|
|
67
|
+
# Find statements from queryiable with term as a subject
|
68
|
+
self.query(:subject => term) do |statement|
|
69
|
+
yield(statement) if block_given?
|
70
|
+
graph << statement
|
71
|
+
|
72
|
+
# Include reifications of this statement
|
73
|
+
RDF::Query.new({
|
74
|
+
:s => {
|
75
|
+
RDF.type => RDF["Statement"],
|
76
|
+
RDF.subject => statement.subject,
|
77
|
+
RDF.predicate => statement.predicate,
|
78
|
+
RDF.object => statement.object,
|
79
|
+
}
|
80
|
+
}).execute(self).each do |solution|
|
81
|
+
# Recurse to include this subject
|
82
|
+
recurse_opts = options.merge(:non_subjects => false, :graph => graph)
|
83
|
+
self.concise_bounded_description(solution[:s], recurse_opts, &block)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Recurse if object is a BNode and it is not already in subjects
|
87
|
+
if statement.object.node?
|
88
|
+
recurse_opts = options.merge(:non_subjects => false, :graph => graph)
|
89
|
+
self.concise_bounded_description(statement.object, recurse_opts, &block)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
graph
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
##
|
99
|
+
# Extensions for `RDF::Query::Solutions`.
|
100
|
+
class RDF::Query::Solutions
|
101
|
+
include SPARQL::Results
|
102
|
+
end
|
@@ -0,0 +1,298 @@
|
|
1
|
+
require 'rdf' # @see http://rubygems.org/gems/rdf
|
2
|
+
require 'sparql/algebra'
|
3
|
+
require 'json'
|
4
|
+
require 'sxp'
|
5
|
+
|
6
|
+
module SPARQL
|
7
|
+
##
|
8
|
+
# A SPARQL grammar for RDF.rb.
|
9
|
+
#
|
10
|
+
# ## Representation
|
11
|
+
# The parser natively generates native SPARQL S-Expressions (SSE),
|
12
|
+
# a hierarch of `SPARQL::Algebra::Operator` instances
|
13
|
+
# which can be executed against a queryable object, such as a Repository identically
|
14
|
+
# to `RDF::Query`.
|
15
|
+
#
|
16
|
+
# Other elements within the hierarchy
|
17
|
+
# are generated using RDF objects, such as `RDF::URI`, `RDF::Node`, `RDF::Literal`, and `RDF::Query`.
|
18
|
+
#
|
19
|
+
# See {SPARQL::Grammar::Parser} for a full listing
|
20
|
+
# of algebra operations and RDF objects generated by the parser.
|
21
|
+
#
|
22
|
+
# The native SSE representation may be serialized to a textual representation of SSE as
|
23
|
+
# serialized general S-Expressions (SXP).
|
24
|
+
# The SXP generated closely follows that of [OpenJena ARQ](http://openjena.org/wiki/SSE), which is intended principally for
|
25
|
+
# running the SPARQL rules. Additionally, SSE is generated for CONSTRUCT, ASK, DESCRIBE and FROM operators.
|
26
|
+
#
|
27
|
+
# SXP is generated by serializing the parser result as follows:
|
28
|
+
#
|
29
|
+
# sse = SPARQL::Grammar.parse("SELECT * WHERE { ?s ?p ?o }")
|
30
|
+
# sxp = sse.to_sxp
|
31
|
+
#
|
32
|
+
# The following examples illustrate SPARQL transformations:
|
33
|
+
#
|
34
|
+
# SPARQL:
|
35
|
+
# SELECT * WHERE { ?a ?b ?c }
|
36
|
+
#
|
37
|
+
# SSE:
|
38
|
+
# RDF::Query.new {
|
39
|
+
# pattern [RDF::Query::Variable.new("a"), RDF::Query::Variable.new("b"), RDF::Query::Variable.new("c")]
|
40
|
+
# }
|
41
|
+
#
|
42
|
+
# SXP:
|
43
|
+
# (bgp (triple ?a ?b ?c))
|
44
|
+
#
|
45
|
+
# SPARQL:
|
46
|
+
# SELECT * FROM <a> WHERE { ?a ?b ?c }
|
47
|
+
#
|
48
|
+
# SSE:
|
49
|
+
# SPARQL::Algebra::Operator::Dataset.new(
|
50
|
+
# [RDF::URI("a")],
|
51
|
+
# RDF::Query.new {
|
52
|
+
# pattern [RDF::Query::Variable.new("a"), RDF::Query::Variable.new("b"), RDF::Query::Variable.new("c")]
|
53
|
+
# }
|
54
|
+
# )
|
55
|
+
#
|
56
|
+
# SXP:
|
57
|
+
# (dataset (<a>) (bgp (triple ?a ?b ?c)))
|
58
|
+
#
|
59
|
+
# SPARQL:
|
60
|
+
# SELECT * FROM NAMED <a> WHERE { ?a ?b ?c }
|
61
|
+
#
|
62
|
+
# SSE:
|
63
|
+
# SPARQL::Algebra::Operator::Dataset.new(
|
64
|
+
# [[:named, RDF::URI("a")]],
|
65
|
+
# RDF::Query.new {
|
66
|
+
# pattern [RDF::Query::Variable.new("a"), RDF::Query::Variable.new("b"), RDF::Query::Variable.new("c")]
|
67
|
+
# }
|
68
|
+
# )
|
69
|
+
#
|
70
|
+
# SXP:
|
71
|
+
# (dataset ((named <a>)) (bgp (triple ?a ?b ?c)))
|
72
|
+
#
|
73
|
+
# SPARQL:
|
74
|
+
# SELECT DISTINCT * WHERE {?a ?b ?c}
|
75
|
+
#
|
76
|
+
# SSE:
|
77
|
+
# SPARQL::Algebra::Operator::Distinct.new(
|
78
|
+
# RDF::Query.new {
|
79
|
+
# pattern [RDF::Query::Variable.new("a"), RDF::Query::Variable.new("b"), RDF::Query::Variable.new("c")]
|
80
|
+
# }
|
81
|
+
# )
|
82
|
+
#
|
83
|
+
# SXP:
|
84
|
+
# (distinct (bgp (triple ?a ?b ?c)))
|
85
|
+
#
|
86
|
+
# SPARQL:
|
87
|
+
# SELECT ?a ?b WHERE {?a ?b ?c}
|
88
|
+
#
|
89
|
+
# SSE:
|
90
|
+
# SPARQL::Algebra::Operator::Project.new(
|
91
|
+
# [RDF::Query::Variable.new("a"), RDF::Query::Variable.new("b")],
|
92
|
+
# RDF::Query.new {
|
93
|
+
# pattern [RDF::Query::Variable.new("a"), RDF::Query::Variable.new("b"), RDF::Query::Variable.new("c")]
|
94
|
+
# }
|
95
|
+
# )
|
96
|
+
#
|
97
|
+
# SXP:
|
98
|
+
# (project (?a ?b) (bgp (triple ?a ?b ?c)))
|
99
|
+
#
|
100
|
+
# SPARQL:
|
101
|
+
# CONSTRUCT {?a ?b ?c} WHERE {?a ?b ?c FILTER (?a)}
|
102
|
+
#
|
103
|
+
# SSE:
|
104
|
+
# SPARQL::Algebra::Operator::Construct.new(
|
105
|
+
# [RDF::Query::Pattern.new(RDF::Query::Variable.new("a"), RDF::Query::Variable.new("b"), RDF::Query::Variable.new("c"))],
|
106
|
+
# SPARQL::Algebra::Operator::Filter.new(
|
107
|
+
# RDF::Query::Variable.new("a"),
|
108
|
+
# RDF::Query.new {
|
109
|
+
# pattern [RDF::Query::Variable.new("a"), RDF::Query::Variable.new("b"), RDF::Query::Variable.new("c")]
|
110
|
+
# }
|
111
|
+
# )
|
112
|
+
# )
|
113
|
+
#
|
114
|
+
# SXP:
|
115
|
+
# (construct ((triple ?a ?b ?c)) (filter ?a (bgp (triple ?a ?b ?c))))
|
116
|
+
#
|
117
|
+
# SPARQL:
|
118
|
+
# SELECT * WHERE {<a> <b> <c> OPTIONAL {<d> <e> <f>}}
|
119
|
+
#
|
120
|
+
# SSE:
|
121
|
+
# SPARQL::Algebra::Operator::LeftJoin.new(
|
122
|
+
# RDF::Query.new {
|
123
|
+
# pattern [RDF::URI("a"), RDF::URI("b"), RDF::URI("c")]
|
124
|
+
# },
|
125
|
+
# RDF::Query.new {
|
126
|
+
# pattern [RDF::URI("d"), RDF::URI("e"), RDF::URI("f")]
|
127
|
+
# }
|
128
|
+
# )
|
129
|
+
#
|
130
|
+
# SXP:
|
131
|
+
# (leftjoin (bgp (triple <a> <b> <c>)) (bgp (triple <d> <e> <f>)))
|
132
|
+
#
|
133
|
+
# SPARQL:
|
134
|
+
# SELECT * WHERE {<a> <b> <c> {<d> <e> <f>}}
|
135
|
+
#
|
136
|
+
# SSE:
|
137
|
+
# SPARQL::Algebra::Operator::Join.new(
|
138
|
+
# RDF::Query.new {
|
139
|
+
# pattern [RDF::URI("a"), RDF::URI("b"), RDF::URI("c")]
|
140
|
+
# },
|
141
|
+
# RDF::Query.new {
|
142
|
+
# pattern [RDF::URI("d"), RDF::URI("e"), RDF::URI("f")]
|
143
|
+
# }
|
144
|
+
# )
|
145
|
+
#
|
146
|
+
# SXP:
|
147
|
+
# (join (bgp (triple <a> <b> <c>)) (bgp (triple <d> <e> <f>)))
|
148
|
+
#
|
149
|
+
# SPARQL:
|
150
|
+
# PREFIX : <http://example/>
|
151
|
+
#
|
152
|
+
# SELECT *
|
153
|
+
# {
|
154
|
+
# { ?s ?p ?o }
|
155
|
+
# UNION
|
156
|
+
# { GRAPH ?g { ?s ?p ?o } }
|
157
|
+
# }
|
158
|
+
#
|
159
|
+
# SSE:
|
160
|
+
# SPARQL::Algebra::Operator::Prefix.new(
|
161
|
+
# [[:":", RDF::URI("http://example/")]],
|
162
|
+
# SPARQL::Algebra::Operator::Union.new(
|
163
|
+
# RDF::Query.new {
|
164
|
+
# pattern [RDF::Query::Variable.new("s"), RDF::Query::Variable.new("p"), RDF::Query::Variable.new("o")]
|
165
|
+
# },
|
166
|
+
# RDF::Query.new(:context => RDF::Query::Variable.new("g")) {
|
167
|
+
# pattern [RDF::Query::Variable.new("s"), RDF::Query::Variable.new("p"), RDF::Query::Variable.new("o")]
|
168
|
+
# }
|
169
|
+
# )
|
170
|
+
# )
|
171
|
+
#
|
172
|
+
# SXP:
|
173
|
+
# (prefix ((: <http://example/>))
|
174
|
+
# (union
|
175
|
+
# (bgp (triple ?s ?p ?o))
|
176
|
+
# (graph ?g
|
177
|
+
# (bgp (triple ?s ?p ?o)))))
|
178
|
+
#
|
179
|
+
# ## Implementation Notes
|
180
|
+
# The parser is driven through a rules table contained in lib/sparql/grammar/parser/meta.rb. This includes
|
181
|
+
# branch rules to indicate productions to be taken based on a current production.
|
182
|
+
#
|
183
|
+
# The meta.rb file is generated from etc/sparql-selectors.n3 which is the result of parsing
|
184
|
+
# http://www.w3.org/2000/10/swap/grammar/sparql.n3 (along with bnf-token-rules.n3) using cwm using the following command sequence:
|
185
|
+
#
|
186
|
+
# cwm ../grammar/sparql.n3 bnf-token-rules.n3 --think --purge --data > sparql-selectors.n3
|
187
|
+
#
|
188
|
+
# sparql-selectors.n3 is itself used to generate lib/sparql/grammar/parser/meta.rb using script/build_meta.
|
189
|
+
#
|
190
|
+
# Note that The SWAP version of sparql.n3 is an older version of the grammar with the newest in http://www.w3.org/2001/sw/DataAccess/rq23/parsers/sparql.ttl,
|
191
|
+
# which uses the EBNF form. Sparql.n3 file has been updated by hand to be consistent with the etc/sparql.ttl version.
|
192
|
+
# A future direction will be to generate rules from etc/sparql.ttl to generate branch tables similar to those
|
193
|
+
# expressed in meta.rb, but this requires rules not currently available.
|
194
|
+
#
|
195
|
+
# ## Next Steps for Parsing EBNF
|
196
|
+
# A more modern approach is to use the EBNF grammar (e.g., etc/sparql.bnf) to generate a Turtle/N3 representation of the grammar, transform
|
197
|
+
# this to and LL1 representation and use this to create meta.rb.
|
198
|
+
#
|
199
|
+
# Using SWAP utilities, this would seemingly be done as follows:
|
200
|
+
#
|
201
|
+
# python http://www.w3.org/2000/10/swap/grammar/ebnf2turtle.py \
|
202
|
+
# http://www.w3.org/2001/sw/DataAccess/rq23/parsers/sparql.bnf \
|
203
|
+
# en \
|
204
|
+
# 'http://www.w3.org/2001/sw/DataAccess/parsers/sparql#' > etc/sparql.ttl
|
205
|
+
#
|
206
|
+
# python http://www.w3.org/2000/10/swap/cwm.py etc/sparql.ttl \
|
207
|
+
# http://www.w3.org/2000/10/swap/grammar/ebnf2bnf.n3 \
|
208
|
+
# http://www.w3.org/2000/10/swap/grammar/first_follow.n3 \
|
209
|
+
# --think --data > etc/sparql-ll1.n3
|
210
|
+
#
|
211
|
+
# At this point, a variation of script/build_meta should be able to extract first/follow information to re-create the meta branch tables.
|
212
|
+
#
|
213
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#grammar
|
214
|
+
module Grammar
|
215
|
+
autoload :Lexer, 'sparql/grammar/lexer'
|
216
|
+
autoload :Parser, 'sparql/grammar/parser'
|
217
|
+
autoload :Meta, 'sparql/grammar/parser/meta'
|
218
|
+
autoload :VERSION, 'sparql/grammar/version'
|
219
|
+
|
220
|
+
METHODS = %w(SELECT CONSTRUCT DESCRIBE ASK).map(&:to_sym)
|
221
|
+
KEYWORDS = %w(BASE PREFIX LIMIT OFFSET DISTINCT REDUCED
|
222
|
+
ORDER BY ASC DESC FROM NAMED WHERE GRAPH
|
223
|
+
OPTIONAL UNION FILTER).map(&:to_sym).unshift(*METHODS)
|
224
|
+
FUNCTIONS = %w(STR LANGMATCHES LANG DATATYPE BOUND sameTerm
|
225
|
+
isIRI isURI isBLANK isLITERAL REGEX).map(&:to_sym)
|
226
|
+
|
227
|
+
# Make all defined non-autoloaded constants immutable:
|
228
|
+
constants.each { |name| const_get(name).freeze unless autoload?(name) }
|
229
|
+
|
230
|
+
##
|
231
|
+
# Parse the given SPARQL `query` string.
|
232
|
+
#
|
233
|
+
# @example
|
234
|
+
# result = SPARQL::Grammar.parse("SELECT * WHERE { ?s ?p ?o }")
|
235
|
+
#
|
236
|
+
# @param [IO, StringIO, Lexer, Array, String, #to_s] query
|
237
|
+
# Query may be an array of lexed tokens, a lexer, or a
|
238
|
+
# string or open file.
|
239
|
+
# @param [Hash{Symbol => Object}] options
|
240
|
+
# @return [Parser]
|
241
|
+
# @raise [Parser::Error] on invalid input
|
242
|
+
def self.parse(query, options = {}, &block)
|
243
|
+
Parser.new(query, options).parse
|
244
|
+
end
|
245
|
+
|
246
|
+
##
|
247
|
+
# Parses input from the given file name or URL.
|
248
|
+
#
|
249
|
+
# @param [String, #to_s] filename
|
250
|
+
# @param [Hash{Symbol => Object}] options
|
251
|
+
# any additional options (see `RDF::Reader#initialize` and `RDF::Format.for`)
|
252
|
+
# @option options [Symbol] :format (:ntriples)
|
253
|
+
# @yield [reader]
|
254
|
+
# @yieldparam [RDF::Reader] reader
|
255
|
+
# @yieldreturn [void] ignored
|
256
|
+
# @raise [RDF::FormatError] if no reader found for the specified format
|
257
|
+
def self.open(filename, options = {}, &block)
|
258
|
+
RDF::Util::File.open_file(filename, options) do |file|
|
259
|
+
self.parse(file, options, &block)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
##
|
264
|
+
# Returns `true` if the given SPARQL `query` string is valid.
|
265
|
+
#
|
266
|
+
# @example
|
267
|
+
# SPARQL::Grammar.valid?("SELECT ?s WHERE { ?s ?p ?o }") #=> true
|
268
|
+
# SPARQL::Grammar.valid?("SELECT s WHERE { ?s ?p ?o }") #=> false
|
269
|
+
#
|
270
|
+
# @param [String, #to_s] query
|
271
|
+
# @param [Hash{Symbol => Object}] options
|
272
|
+
# @return [Boolean]
|
273
|
+
def self.valid?(query, options = {})
|
274
|
+
Parser.new(query, options).valid?
|
275
|
+
end
|
276
|
+
|
277
|
+
##
|
278
|
+
# Tokenizes the given SPARQL `query` string.
|
279
|
+
#
|
280
|
+
# @example
|
281
|
+
# lexer = SPARQL::Grammar.tokenize("SELECT * WHERE { ?s ?p ?o }")
|
282
|
+
# lexer.each_token do |token|
|
283
|
+
# puts token.inspect
|
284
|
+
# end
|
285
|
+
#
|
286
|
+
# @param [String, #to_s] query
|
287
|
+
# @param [Hash{Symbol => Object}] options
|
288
|
+
# @yield [lexer]
|
289
|
+
# @yieldparam [Lexer] lexer
|
290
|
+
# @return [Lexer]
|
291
|
+
# @raise [Lexer::Error] on invalid input
|
292
|
+
def self.tokenize(query, options = {}, &block)
|
293
|
+
Lexer.tokenize(query, options, &block)
|
294
|
+
end
|
295
|
+
|
296
|
+
class SPARQL_GRAMMAR < RDF::Vocabulary("http://www.w3.org/2000/10/swap/grammar/sparql#"); end
|
297
|
+
end # Grammar
|
298
|
+
end # SPARQL
|