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,77 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL GraphPattern `dataset` operator.
5
+ #
6
+ # Instintiated with two operands, the first being an array of data source URIs,
7
+ # either bare, indicating a default dataset, or expressed as an array [:named, <uri>],
8
+ # indicating that it represents a named data source.
9
+ #
10
+ # @example
11
+ # (prefix ((: <http://example/>))
12
+ # (dataset (<data-g1.ttl> (named <data-g2.ttl>))
13
+ # (bgp (triple ?s ?p ?o))))
14
+ #
15
+ # @see http://www.w3.org/TR/rdf-sparql-query/#specifyingDataset
16
+ class Dataset < Binary
17
+ include Query
18
+
19
+ NAME = [:dataset]
20
+
21
+ ##
22
+ # Executes this query on the given `queryable` graph or repository.
23
+ # Reads specified data sources into queryable. Named data sources
24
+ # are added using a _context_ of the data source URI.
25
+ #
26
+ # Datasets are specified in operand(1), which is an array of default or named graph URIs.
27
+ #
28
+ # @param [RDF::Queryable] queryable
29
+ # the graph or repository to query
30
+ # @param [Hash{Symbol => Object}] options
31
+ # any additional keyword options
32
+ # @return [RDF::Query::Solutions]
33
+ # the resulting solution sequence
34
+ # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
35
+ def execute(queryable, options = {})
36
+ debug(options) {"Dataset"}
37
+ operand(0).each do |ds|
38
+ load_opts = {}
39
+ case ds
40
+ when Array
41
+ # Format is (named <uri>), only need the URI part
42
+ uri = if self.base_uri
43
+ u = self.base_uri.join(ds.last)
44
+ u.lexical = "<#{ds.last}>" unless u.to_s == ds.last.to_s
45
+ u
46
+ else
47
+ ds.last
48
+ end
49
+ uri = self.base_uri ? self.base_uri.join(ds.last) : ds.last
50
+ uri.lexical = ds.last
51
+ load_opts[:context] = uri
52
+ debug(options) {"=> read named data source #{uri}"}
53
+ else
54
+ debug(options) {"=> array: join #{self.base_uri.inspect} to #{ds.inspect}"}
55
+ uri = self.base_uri ? self.base_uri.join(ds) : ds
56
+ debug(options) {"=> read default data source #{uri}"}
57
+ end
58
+ load_opts[:base_uri] = uri
59
+ queryable.load(uri.to_s, load_opts)
60
+ end
61
+
62
+ @solutions = operands.last.execute(queryable, options.merge(:depth => options[:depth].to_i + 1))
63
+ end
64
+
65
+ ##
66
+ # Returns an optimized version of this query.
67
+ #
68
+ # If optimize operands, and if the first two operands are both Queries, replace
69
+ # with the unique sum of the query elements
70
+ #
71
+ # @return [Union, RDF::Query] `self`
72
+ def optimize
73
+ operands.last.optimize
74
+ end
75
+ end # Dataset
76
+ end # Operator
77
+ end; end # SPARQL::Algebra
@@ -0,0 +1,42 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL `datatype` operator.
5
+ #
6
+ # @example
7
+ # (prefix ((xsd: <http://www.w3.org/2001/XMLSchema#>)
8
+ # (rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>)
9
+ # (: <http://example.org/>))
10
+ # (project (?s)
11
+ # (filter (= (datatype (xsd:double ?v)) xsd:double)
12
+ # (bgp (triple ?s :p ?v)))))
13
+ #
14
+ # @see http://www.w3.org/TR/rdf-sparql-query/#func-datatype
15
+ class Datatype < Operator::Unary
16
+ include Evaluatable
17
+
18
+ NAME = :datatype
19
+
20
+ ##
21
+ # Returns the datatype IRI of the operand.
22
+ #
23
+ # If the operand is a simple literal, returns a datatype of
24
+ # `xsd:string`.
25
+ #
26
+ # @param [RDF::Literal] literal
27
+ # a typed or simple literal
28
+ # @return [RDF::URI] the datatype IRI, or `xsd:string` for simple literals
29
+ # @raise [TypeError] if the operand is not a typed or simple literal
30
+ def apply(literal)
31
+ case literal
32
+ when RDF::Literal then case
33
+ when literal.typed? then RDF::URI(literal.datatype)
34
+ when literal.simple? then RDF::XSD.string
35
+ else raise TypeError, "expected a typed or simple RDF::Literal, but got #{literal.inspect}"
36
+ end
37
+ else raise TypeError, "expected an RDF::Literal, but got #{literal.inspect}"
38
+ end
39
+ end
40
+ end # Datatype
41
+ end # Operator
42
+ end; end # SPARQL::Algebra
@@ -0,0 +1,17 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL descending sort operator.
5
+ #
6
+ # @example
7
+ # (prefix ((foaf: <http://xmlns.com/foaf/0.1/>))
8
+ # (project (?name)
9
+ # (order ((desc ?name))
10
+ # (bgp (triple ?x foaf:name ?name)))))
11
+ #
12
+ # @see http://www.w3.org/TR/rdf-sparql-query/#func-isLiteral
13
+ class Desc < Operator::Asc
14
+ NAME = :desc
15
+ end # Desc
16
+ end # Operator
17
+ end; end # SPARQL::Algebra
@@ -0,0 +1,71 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL GraphPattern `describe` operator.
5
+ #
6
+ # Generages a graph across specified terms using {RDF::Queryable}`#concise_bounded_description`.
7
+ #
8
+ # @example
9
+ # (prefix ((exOrg: <http://org.example.com/employees#>))
10
+ # (describe (?x)
11
+ # (bgp (triple ?x exOrg:employeeId "1234"))))
12
+ #
13
+ # @see http://www.w3.org/TR/rdf-sparql-query/#describe
14
+ class Describe < Operator::Binary
15
+ include Query
16
+
17
+ NAME = [:describe]
18
+
19
+ ##
20
+ # Executes this query on the given {RDF::Queryable} object.
21
+ # Generates a graph containing the Concise Bounded Description
22
+ # variables and URIs listed in the first operand.
23
+ #
24
+ # @example
25
+ # (describe (<http://example/>))
26
+ #
27
+ # @example
28
+ # (prefix ((foaf: <http://xmlns.com/foaf/0.1/>))
29
+ # (describe (?x)
30
+ # (bgp (triple ?x foaf:mbox <mailto:alice@org>))))
31
+ #
32
+ # @param [RDF::Queryable] queryable
33
+ # the graph or repository to query
34
+ # @param [Hash{Symbol => Object}] options
35
+ # any additional keyword options
36
+ # @return [RDF::Query::Solutions]
37
+ # the resulting solution sequence
38
+ # @see http://www.w3.org/TR/rdf-sparql-query/#describe
39
+ def execute(queryable, options = {})
40
+ debug(options) {"Describe #{operands.first}, #{options.inspect}"}
41
+
42
+ # Describe any constand URIs
43
+ to_describe = operands.first.select {|t| t.uri?}
44
+
45
+ to_describe.each {|t| debug(options) {"=> describe #{t}"}}
46
+
47
+ operands.last.execute(queryable).each do |solution|
48
+ solution.each_variable do |v|
49
+ if operands.first.any? {|bound| v.eql?(bound)}
50
+ debug(options) {"=> describe #{v}"}
51
+ to_describe << v.value
52
+ end
53
+ end
54
+ end
55
+
56
+ # Return Concise Bounded Description
57
+ queryable.concise_bounded_description(*to_describe)
58
+ end
59
+
60
+ ##
61
+ # Returns an optimized version of this query.
62
+ #
63
+ # Return optimized query
64
+ #
65
+ # @return [Union, RDF::Query] `self`
66
+ def optimize
67
+ operands = operands.map(&:optimize)
68
+ end
69
+ end # Construct
70
+ end # Operator
71
+ end; end # SPARQL::Algebra
@@ -0,0 +1,50 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL GraphPattern `distinct` operator.
5
+ #
6
+ # @example
7
+ # (prefix ((xsd: <http://www.w3.org/2001/XMLSchema#>)
8
+ # (: <http://example/>))
9
+ # (distinct
10
+ # (project (?v)
11
+ # (bgp (triple ?x ?p ?v)))))
12
+ #
13
+ # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
14
+ class Distinct < Operator::Unary
15
+ include Query
16
+
17
+ NAME = [:distinct]
18
+
19
+ ##
20
+ # Executes this query on the given `queryable` graph or repository.
21
+ # Removes duplicate solutions from the solution set.
22
+ #
23
+ # @param [RDF::Queryable] queryable
24
+ # the graph or repository to query
25
+ # @param [Hash{Symbol => Object}] options
26
+ # any additional keyword options
27
+ # @return [RDF::Query::Solutions]
28
+ # the resulting solution sequence
29
+ # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
30
+ def execute(queryable, options = {})
31
+ debug(options) {"Distinct"}
32
+ @solutions = operands.last.execute(queryable, options.merge(:depth => options[:depth].to_i + 1))
33
+ debug(options) {"=>(before) #{@solutions.inspect}"}
34
+ @solutions = @solutions.distinct
35
+ debug(options) {"=>(after) #{@solutions.inspect}"}
36
+ @solutions
37
+ end
38
+
39
+ ##
40
+ # Returns an optimized version of this query.
41
+ #
42
+ # Return optimized query
43
+ #
44
+ # @return [Union, RDF::Query] `self`
45
+ def optimize
46
+ operands = operands.map(&:optimize)
47
+ end
48
+ end # Distinct
49
+ end # Operator
50
+ end; end # SPARQL::Algebra
@@ -0,0 +1,43 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL numeric `divide` operator.
5
+ #
6
+ # @example
7
+ # (/ 4 2)
8
+ #
9
+ # @see http://www.w3.org/TR/xpath-functions/#func-numeric-divide
10
+ class Divide < Operator::Binary
11
+ include Evaluatable
12
+
13
+ NAME = [:'/', :divide]
14
+
15
+ ##
16
+ # Returns the arithmetic quotient of the operands.
17
+ #
18
+ # @param [RDF::Literal::Numeric] left
19
+ # a numeric literal
20
+ # @param [RDF::Literal::Numeric] right
21
+ # a numeric literal
22
+ # @return [RDF::Literal::Numeric]
23
+ # @raise [TypeError] if either operand is not a numeric literal
24
+ def apply(left, right)
25
+ case
26
+ when left.is_a?(RDF::Literal::Numeric) && right.is_a?(RDF::Literal::Numeric)
27
+ # For xsd:decimal and xsd:integer operands, if the divisor is
28
+ # (positive or negative) zero, an error is raised.
29
+ raise ZeroDivisionError, "divided by #{right}" if left.is_a?(RDF::Literal::Decimal) && right.zero?
30
+
31
+ # As a special case, if the types of both operands are
32
+ # xsd:integer, then the return type is xsd:decimal.
33
+ if left.is_a?(RDF::Literal::Integer) && right.is_a?(RDF::Literal::Integer)
34
+ RDF::Literal(left.to_d / right.to_d)
35
+ else
36
+ left / right
37
+ end
38
+ else raise TypeError, "expected two RDF::Literal::Numeric operands, but got #{left.inspect} and #{right.inspect}"
39
+ end
40
+ end
41
+ end # Divide
42
+ end # Operator
43
+ end; end # SPARQL::Algebra
@@ -0,0 +1,32 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL relational `=` (equal) comparison operator.
5
+ #
6
+ # @example
7
+ # (= ?x ?y)
8
+ #
9
+ # @see http://www.w3.org/TR/rdf-sparql-query/#OperatorMapping
10
+ # @see http://www.w3.org/TR/rdf-sparql-query/#func-RDFterm-equal
11
+ class Equal < Compare
12
+ NAME = :'='
13
+
14
+ ##
15
+ # Returns `true` if the operands are equal; returns `false` otherwise.
16
+ #
17
+ # @param [RDF::Term] term1
18
+ # an RDF term
19
+ # @param [RDF::Term] term2
20
+ # an RDF term
21
+ # @return [RDF::Literal::Boolean] `true` or `false`
22
+ # @raise [TypeError] if either operand is not an RDF term or operands are not comperable
23
+ #
24
+ # @see {RDF::Term#==}
25
+ def apply(term1, term2)
26
+ term1 = term1.dup.extend(RDF::TypeCheck)
27
+ term2 = term2.dup.extend(RDF::TypeCheck)
28
+ RDF::Literal(term1 == term2)
29
+ end
30
+ end # Equal
31
+ end # Operator
32
+ end; end # SPARQL::Algebra
@@ -0,0 +1,52 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL GraphPattern `exprlist` operator.
5
+ #
6
+ # Used for filters with more than one expression.
7
+ #
8
+ # @example
9
+ # (prefix ((: <http://example/>))
10
+ # (project (?v ?w)
11
+ # (filter (exprlist (= ?v 2) (= ?w 3))
12
+ # (bgp
13
+ # (triple ?s :p ?v)
14
+ # (triple ?s :q ?w)
15
+ # ))))
16
+ #
17
+ # @see http://www.w3.org/TR/rdf-sparql-query/#evaluation
18
+ class Exprlist < Operator
19
+ include Evaluatable
20
+
21
+ NAME = [:exprlist]
22
+
23
+ ##
24
+ # Returns `true` if all operands evaluate to `true`.
25
+ #
26
+ # Note that this operator operates on the effective boolean value
27
+ # (EBV) of its operands.
28
+ #
29
+ # @example
30
+ #
31
+ # (exprlist (= 1 1) (!= 1 0))
32
+ #
33
+ # @param [RDF::Query::Solution, #[]] bindings
34
+ # @return [RDF::Literal::Boolean] `true` or `false`
35
+ # @raise [TypeError] if the operands could not be coerced to a boolean literal
36
+ def evaluate(bindings = {})
37
+ res = operands.all? {|op| boolean(op.evaluate(bindings)).true? }
38
+ RDF::Literal(res) # FIXME: error handling
39
+ end
40
+
41
+ ##
42
+ # Returns an optimized version of this query.
43
+ #
44
+ # Return optimized query
45
+ #
46
+ # @return [Union, RDF::Query] `self`
47
+ def optimize
48
+ operands = operands.map(&:optimize)
49
+ end
50
+ end # Exprlist
51
+ end # Operator
52
+ end; end # SPARQL::Algebra
@@ -0,0 +1,71 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL GraphPattern `filter` operator.
5
+ #
6
+ # @example
7
+ # (select (?v)
8
+ # (project (?v)
9
+ # (filter (= ?v 2)
10
+ # (bgp (triple ?s <http://example/p> ?v)))))
11
+ #
12
+ # @see http://www.w3.org/TR/rdf-sparql-query/#evaluation
13
+ class Filter < Operator::Binary
14
+ include Query
15
+
16
+ NAME = [:filter]
17
+
18
+ ##
19
+ # Executes this query on the given `queryable` graph or repository.
20
+ # Then it passes each solution through one or more filters and removes
21
+ # those that evaluate to false or generate a _TypeError_.
22
+ #
23
+ # Note that the last operand returns a solution set, while the first
24
+ # is an expression. This may be a variable, simple expression,
25
+ # or exprlist.
26
+ #
27
+ # @param [RDF::Queryable] queryable
28
+ # the graph or repository to query
29
+ # @param [Hash{Symbol => Object}] options
30
+ # any additional keyword options
31
+ # @return [RDF::Query::Solutions]
32
+ # the resulting solution sequence
33
+ # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
34
+ # @see http://www.w3.org/TR/rdf-sparql-query/#ebv
35
+ def execute(queryable, options = {})
36
+ debug(options) {"Filter #{operands.first}"}
37
+ @solutions = operands.last.execute(queryable, options.merge(:depth => options[:depth].to_i + 1))
38
+ debug(options) {"=>(before) #{@solutions.map(&:to_hash).inspect}"}
39
+ @solutions = @solutions.filter do |solution|
40
+ # Evaluate the solution, which will return true or false
41
+ #debug(options) {"===>(evaluate) #{operands.first.inspect} against #{solution.to_hash.inspect}"}
42
+
43
+ # From http://www.w3.org/TR/rdf-sparql-query/#tests
44
+ # FILTERs eliminate any solutions that, when substituted into the expression, either
45
+ # result in an effective boolean value of false or produce an error.
46
+ begin
47
+ res = boolean(operands.first.evaluate(solution)).true?
48
+ debug(options) {"===>#{res} #{solution.to_hash.inspect}"}
49
+ res
50
+ rescue
51
+ debug(options) {"rescue(#{$!}): #{solution.to_hash.inspect}"}
52
+ false
53
+ end
54
+ end
55
+ @solutions = RDF::Query::Solutions.new(@solutions)
56
+ debug(options) {"=>(after) #{@solutions.map(&:to_hash).inspect}"}
57
+ @solutions
58
+ end
59
+
60
+ ##
61
+ # Returns an optimized version of this query.
62
+ #
63
+ # Return optimized query
64
+ #
65
+ # @return [Union, RDF::Query] `self`
66
+ def optimize
67
+ operands = operands.map(&:optimize)
68
+ end
69
+ end # Filter
70
+ end # Operator
71
+ end; end # SPARQL::Algebra