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.
Files changed (84) hide show
  1. data/AUTHORS +3 -0
  2. data/CREDITS +0 -0
  3. data/README.markdown +103 -53
  4. data/UNLICENSE +24 -0
  5. data/VERSION +1 -0
  6. data/bin/sparql +87 -0
  7. data/lib/sparql.rb +105 -22
  8. data/lib/sparql/algebra.rb +369 -0
  9. data/lib/sparql/algebra/evaluatable.rb +37 -0
  10. data/lib/sparql/algebra/expression.rb +284 -0
  11. data/lib/sparql/algebra/extensions.rb +159 -0
  12. data/lib/sparql/algebra/operator.rb +492 -0
  13. data/lib/sparql/algebra/operator/add.rb +34 -0
  14. data/lib/sparql/algebra/operator/and.rb +65 -0
  15. data/lib/sparql/algebra/operator/asc.rb +29 -0
  16. data/lib/sparql/algebra/operator/ask.rb +46 -0
  17. data/lib/sparql/algebra/operator/base.rb +46 -0
  18. data/lib/sparql/algebra/operator/bgp.rb +26 -0
  19. data/lib/sparql/algebra/operator/bound.rb +48 -0
  20. data/lib/sparql/algebra/operator/compare.rb +84 -0
  21. data/lib/sparql/algebra/operator/construct.rb +85 -0
  22. data/lib/sparql/algebra/operator/dataset.rb +77 -0
  23. data/lib/sparql/algebra/operator/datatype.rb +42 -0
  24. data/lib/sparql/algebra/operator/desc.rb +17 -0
  25. data/lib/sparql/algebra/operator/describe.rb +71 -0
  26. data/lib/sparql/algebra/operator/distinct.rb +50 -0
  27. data/lib/sparql/algebra/operator/divide.rb +43 -0
  28. data/lib/sparql/algebra/operator/equal.rb +32 -0
  29. data/lib/sparql/algebra/operator/exprlist.rb +52 -0
  30. data/lib/sparql/algebra/operator/filter.rb +71 -0
  31. data/lib/sparql/algebra/operator/graph.rb +28 -0
  32. data/lib/sparql/algebra/operator/greater_than.rb +32 -0
  33. data/lib/sparql/algebra/operator/greater_than_or_equal.rb +33 -0
  34. data/lib/sparql/algebra/operator/is_blank.rb +35 -0
  35. data/lib/sparql/algebra/operator/is_iri.rb +37 -0
  36. data/lib/sparql/algebra/operator/is_literal.rb +36 -0
  37. data/lib/sparql/algebra/operator/join.rb +67 -0
  38. data/lib/sparql/algebra/operator/lang.rb +29 -0
  39. data/lib/sparql/algebra/operator/lang_matches.rb +53 -0
  40. data/lib/sparql/algebra/operator/left_join.rb +95 -0
  41. data/lib/sparql/algebra/operator/less_than.rb +32 -0
  42. data/lib/sparql/algebra/operator/less_than_or_equal.rb +32 -0
  43. data/lib/sparql/algebra/operator/minus.rb +31 -0
  44. data/lib/sparql/algebra/operator/multiply.rb +34 -0
  45. data/lib/sparql/algebra/operator/not.rb +35 -0
  46. data/lib/sparql/algebra/operator/not_equal.rb +26 -0
  47. data/lib/sparql/algebra/operator/or.rb +65 -0
  48. data/lib/sparql/algebra/operator/order.rb +69 -0
  49. data/lib/sparql/algebra/operator/plus.rb +31 -0
  50. data/lib/sparql/algebra/operator/prefix.rb +45 -0
  51. data/lib/sparql/algebra/operator/project.rb +46 -0
  52. data/lib/sparql/algebra/operator/reduced.rb +47 -0
  53. data/lib/sparql/algebra/operator/regex.rb +70 -0
  54. data/lib/sparql/algebra/operator/same_term.rb +46 -0
  55. data/lib/sparql/algebra/operator/slice.rb +60 -0
  56. data/lib/sparql/algebra/operator/str.rb +35 -0
  57. data/lib/sparql/algebra/operator/subtract.rb +32 -0
  58. data/lib/sparql/algebra/operator/union.rb +55 -0
  59. data/lib/sparql/algebra/query.rb +99 -0
  60. data/lib/sparql/algebra/sxp_extensions.rb +35 -0
  61. data/lib/sparql/algebra/version.rb +20 -0
  62. data/lib/sparql/extensions.rb +102 -0
  63. data/lib/sparql/grammar.rb +298 -0
  64. data/lib/sparql/grammar/lexer.rb +609 -0
  65. data/lib/sparql/grammar/parser.rb +1383 -0
  66. data/lib/sparql/grammar/parser/meta.rb +1801 -0
  67. data/lib/sparql/results.rb +220 -0
  68. data/lib/sparql/version.rb +20 -0
  69. metadata +232 -62
  70. data/Rakefile +0 -22
  71. data/coverage/index.html +0 -252
  72. data/coverage/lib-sparql-execute_sparql_rb.html +0 -621
  73. data/coverage/lib-sparql_rb.html +0 -622
  74. data/lib/sparql/execute_sparql.rb +0 -27
  75. data/lib/sparql/sparql.treetop +0 -159
  76. data/sparql.gemspec +0 -16
  77. data/spec/spec.opts +0 -2
  78. data/spec/spec_helper.rb +0 -24
  79. data/spec/unit/graph_parsing_spec.rb +0 -76
  80. data/spec/unit/iri_parsing_spec.rb +0 -46
  81. data/spec/unit/prefixed_names_parsing_spec.rb +0 -40
  82. data/spec/unit/primitives_parsing_spec.rb +0 -26
  83. data/spec/unit/sparql_parsing_spec.rb +0 -72
  84. 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