sparql 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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,34 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ include Evaluatable
4
+
5
+ ##
6
+ # The SPARQL numeric `add` operator.
7
+ #
8
+ # @example
9
+ # (+ 1 ?x)
10
+ # (add 1 ?x)
11
+ #
12
+ # @see http://www.w3.org/TR/xpath-functions/#func-numeric-add
13
+ class Add < Operator::Binary
14
+ NAME = [:+, :add]
15
+
16
+ ##
17
+ # Returns the arithmetic sum of the operands.
18
+ #
19
+ # @param [RDF::Literal::Numeric] left
20
+ # a numeric literal
21
+ # @param [RDF::Literal::Numeric] right
22
+ # a numeric literal
23
+ # @return [RDF::Literal::Numeric]
24
+ # @raise [TypeError] if either operand is not a numeric literal
25
+ def apply(left, right)
26
+ case
27
+ when left.is_a?(RDF::Literal::Numeric) && right.is_a?(RDF::Literal::Numeric)
28
+ left + right
29
+ else raise TypeError, "expected two RDF::Literal::Numeric operands, but got #{left.inspect} and #{right.inspect}"
30
+ end
31
+ end
32
+ end # Add
33
+ end # Operator
34
+ end; end # SPARQL::Algebra
@@ -0,0 +1,65 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL logical `and` operator.
5
+ #
6
+ # @example
7
+ # (&& ?x ?y)
8
+ # (and ?x ?y)
9
+ #
10
+ # @see http://www.w3.org/TR/rdf-sparql-query/#func-logical-and
11
+ # @see http://www.w3.org/TR/rdf-sparql-query/#evaluation
12
+ class And < Operator::Binary
13
+ include Evaluatable
14
+
15
+ NAME = [:and, :'&&']
16
+
17
+ ##
18
+ # Initializes a new operator instance.
19
+ #
20
+ # @param [RDF::Literal::Boolean] left
21
+ # the left operand
22
+ # @param [RDF::Literal::Boolean] right
23
+ # the right operand
24
+ # @param [Hash{Symbol => Object}] options
25
+ # any additional options (see {Operator#initialize})
26
+ # @raise [TypeError] if any operand is invalid
27
+ def initialize(left, right, options = {})
28
+ super
29
+ end
30
+
31
+ ##
32
+ # Returns the logical `AND` of the left operand and the right operand.
33
+ #
34
+ # Note that this operator operates on the effective boolean value
35
+ # (EBV) of its operands.
36
+ #
37
+ # @param [RDF::Query::Solution, #[]] bindings
38
+ # @return [RDF::Literal::Boolean] `true` or `false`
39
+ # @raise [TypeError] if the operands could not be coerced to boolean literals
40
+ def evaluate(bindings = {})
41
+ begin
42
+ left = boolean(operand(0).evaluate(bindings)).true?
43
+ rescue TypeError
44
+ left = nil
45
+ end
46
+
47
+ begin
48
+ right = boolean(operand(1).evaluate(bindings)).true?
49
+ rescue TypeError
50
+ right = nil
51
+ end
52
+
53
+ # From http://www.w3.org/TR/rdf-sparql-query/#evaluation
54
+ # A logical-and that encounters an error on only one branch will return an error if the other branch is
55
+ # TRUE and FALSE if the other branch is FALSE.
56
+ case
57
+ when left.nil? && right.nil? then raise(TypeError)
58
+ when left.nil? then right ? raise(TypeError) : RDF::Literal::FALSE
59
+ when right.nil? then left ? raise(TypeError) : RDF::Literal::FALSE
60
+ else RDF::Literal(left && right)
61
+ end
62
+ end
63
+ end # And
64
+ end # Operator
65
+ end; end # SPARQL::Algebra
@@ -0,0 +1,29 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL ascending sort operator.
5
+ #
6
+ # @example
7
+ # (prefix ((foaf: <http://xmlns.com/foaf/0.1/>))
8
+ # (project (?name)
9
+ # (order ((asc ?name))
10
+ # (bgp (triple ?x foaf:name ?name)))))
11
+ #
12
+ # @see http://www.w3.org/TR/rdf-sparql-query/#func-isLiteral
13
+ class Asc < Operator::Unary
14
+ include Evaluatable
15
+
16
+ NAME = :asc
17
+
18
+ ##
19
+ # Returns the evaluation of it's operand. Default comparison is in
20
+ # ascending order. Ordering is applied in {Order}.
21
+ #
22
+ # @param [RDF::Query::Solution, #[]] bindings
23
+ # @return [RDF::Term]
24
+ def evaluate(bindings = {})
25
+ operand(0).evaluate(bindings)
26
+ end
27
+ end # Asc
28
+ end # Operator
29
+ end; end # SPARQL::Algebra
@@ -0,0 +1,46 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL GraphPattern `ask` operator.
5
+ #
6
+ # @example
7
+ # (prefix ((: <http://example/>))
8
+ # (ask
9
+ # (bgp (triple :x :p ?x))))
10
+ #
11
+ # @see http://www.w3.org/TR/rdf-sparql-query/#ask
12
+ class Ask < Operator::Unary
13
+ include Query
14
+
15
+ NAME = [:ask]
16
+
17
+ ##
18
+ # Executes this query on the given `queryable` graph or repository.
19
+ # Returns true if any solutions are found, false otherwise.
20
+ #
21
+ # @param [RDF::Queryable] queryable
22
+ # the graph or repository to query
23
+ # @param [Hash{Symbol => Object}] options
24
+ # any additional keyword options
25
+ # @return [RDF::Literal::Boolean]
26
+ # the resulting solution sequence
27
+ # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
28
+ def execute(queryable, options = {})
29
+ debug(options) {"Ask #{operands.first}"}
30
+ boolean(!operands.last.
31
+ execute(queryable, options.merge(:depth => options[:depth].to_i + 1)).
32
+ empty?)
33
+ end
34
+
35
+ ##
36
+ # Returns an optimized version of this query.
37
+ #
38
+ # Return optimized query
39
+ #
40
+ # @return [Union, RDF::Query] `self`
41
+ def optimize
42
+ operands = operands.map(&:optimize)
43
+ end
44
+ end # Ask
45
+ end # Operator
46
+ end; end # SPARQL::Algebra
@@ -0,0 +1,46 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL GraphPattern `base` operator.
5
+ #
6
+ # @example
7
+ # (base <http://example.org/>
8
+ # (bgp (triple <a> <b> 123.0)))
9
+ #
10
+ # @see http://www.w3.org/TR/rdf-sparql-query/#QSynIRI
11
+ class Base < Binary
12
+ include Query
13
+
14
+ NAME = [:base]
15
+
16
+ ##
17
+ # Executes this query on the given `queryable` graph or repository.
18
+ # Really a pass-through, as this is a syntactic object used for providing
19
+ # context for relative URIs.
20
+ #
21
+ # @param [RDF::Queryable] queryable
22
+ # the graph or repository to query
23
+ # @param [Hash{Symbol => Object}] options
24
+ # any additional keyword options
25
+ # @return [RDF::Query::Solutions]
26
+ # the resulting solution sequence
27
+ # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
28
+ def execute(queryable, options = {})
29
+ debug(options) {"Base #{operands.first}"}
30
+ @solutions = operands.last.execute(queryable, options.merge(:depth => options[:depth].to_i + 1))
31
+ debug(options) {"=> #{@solutions.inspect}"}
32
+ @solutions
33
+ end
34
+
35
+ ##
36
+ # Returns an optimized version of this query.
37
+ #
38
+ # Return optimized query
39
+ #
40
+ # @return [Union, RDF::Query] `self`
41
+ def optimize
42
+ operands.last.optimize
43
+ end
44
+ end # Base
45
+ end # Operator
46
+ end; end # SPARQL::Algebra
@@ -0,0 +1,26 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL GraphPattern `bgp` operator.
5
+ #
6
+ # Query with `context` set to false.
7
+ #
8
+ # @example
9
+ # (prefix ((: <http://example/>))
10
+ # (bgp (triple ?s ?p ?o)))
11
+ #
12
+ # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
13
+ class BGP < Operator
14
+ NAME = [:bgp]
15
+ ##
16
+ # A `graph` is an RDF::Query with a context.
17
+ #
18
+ # @param [RDF::URI, RDF::Query::Variable] context
19
+ # @param [RDF::Query] bgp
20
+ # @return [RDF::Query]
21
+ def self.new(*patterns)
22
+ RDF::Query.new(*(patterns + [{:context => false}]))
23
+ end
24
+ end # BGP
25
+ end # Operator
26
+ end; end # SPARQL::Algebra
@@ -0,0 +1,48 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL `bound` operator.
5
+ #
6
+ # @example
7
+ # (prefix ((: <http://example.org/ns#>))
8
+ # (project (?a ?c)
9
+ # (filter (! (bound ?e))
10
+ # (leftjoin
11
+ # (bgp (triple ?a :b ?c))
12
+ # (bgp (triple ?c :d ?e))))))
13
+ #
14
+ # @see http://www.w3.org/TR/rdf-sparql-query/#func-bound
15
+ class Bound < Operator::Unary
16
+ include Evaluatable
17
+
18
+ NAME = :bound
19
+
20
+ ##
21
+ # Initializes a new operator instance.
22
+ #
23
+ # @param [RDF::Query::Variable] var
24
+ # a variable
25
+ # @param [Hash{Symbol => Object}] options
26
+ # any additional options (see {Operator#initialize})
27
+ # @raise [TypeError] if any operand is invalid
28
+ def initialize(var, options = {})
29
+ super
30
+ end
31
+
32
+ ##
33
+ # Returns `true` if the operand is a variable that is bound to a
34
+ # value in the given `bindings`, `false` otherwise.
35
+ #
36
+ # @param [RDF::Query::Solution, #[]] bindings
37
+ # @return [RDF::Literal::Boolean] `true` or `false`
38
+ # @raise [TypeError] if the operand is not a variable
39
+ def evaluate(bindings = {})
40
+ case var = operand
41
+ when Variable
42
+ operand.evaluate(bindings) ? RDF::Literal::TRUE : RDF::Literal::FALSE
43
+ else raise TypeError, "expected an RDF::Query::Variable, but got #{var.inspect}"
44
+ end
45
+ end
46
+ end # Bound
47
+ end # Operator
48
+ end; end # SPARQL::Algebra
@@ -0,0 +1,84 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # A SPARQL relational `<=>` 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/xpath-functions/#func-compare
11
+ class Compare < Operator::Binary
12
+ include Evaluatable
13
+
14
+ NAME = :<=>
15
+
16
+ ##
17
+ # Returns -1, 0, or 1, depending on whether the first operand is
18
+ # respectively less than, equal to, or greater than the second
19
+ # operand.
20
+ #
21
+ # SPARQL also fixes an order between some kinds of RDF terms that would not otherwise be ordered:
22
+ #
23
+ # (Lowest) no value assigned to the variable or expression in this solution.
24
+ # Blank nodes
25
+ # IRIs
26
+ # RDF literals
27
+ #
28
+ # @param [RDF::Literal] left
29
+ # a literal
30
+ # @param [RDF::Literal] right
31
+ # a literal
32
+ # @return [RDF::Literal::Integer] `-1`, `0`, or `1`
33
+ # @raise [TypeError] if either operand is not a literal
34
+ def apply(left, right)
35
+ case
36
+ # @see http://www.w3.org/TR/rdf-sparql-query/#OperatorMapping
37
+ # @see http://www.w3.org/TR/rdf-sparql-query/#modOrderBy
38
+ when left.is_a?(RDF::Literal) && right.is_a?(RDF::Literal)
39
+ case
40
+ # @see http://www.w3.org/TR/xpath-functions/#string-compare
41
+ # @see http://www.w3.org/TR/xpath-functions/#comp.numeric
42
+ # @see http://www.w3.org/TR/xpath-functions/#op.boolean
43
+ # @see http://www.w3.org/TR/xpath-functions/#comp.duration.datetime
44
+ when (left.simple? && right.simple?) ||
45
+ (left.is_a?(RDF::Literal::Numeric) && right.is_a?(RDF::Literal::Numeric)) ||
46
+ (left.datatype == right.datatype && left.language == right.language)
47
+ RDF::Literal(left.send(self.class.const_get(:NAME), right))
48
+
49
+ # A plain literal is lower than an RDF literal with type xsd:string of the same lexical form.
50
+ when left.simple? && right.datatype == RDF::XSD.string && left.value == right.value
51
+ RDF::Literal(-1)
52
+ when right.simple? && left.datatype == RDF::XSD.string && right.value == left.value
53
+ RDF::Literal(-1)
54
+
55
+ else raise TypeError, "unable to compare #{left.inspect} and #{right.inspect}"
56
+ end
57
+
58
+ when left.is_a?(RDF::URI) && right.is_a?(RDF::URI)
59
+ # Pairs of IRIs are ordered by comparing them as simple literals.
60
+ RDF::Literal(RDF::Literal(left.to_s).send(self.class.const_get(:NAME), RDF::Literal(right.to_s)))
61
+ when left.is_a?(RDF::Node) && right.is_a?(RDF::Node)
62
+ # BNode comparison is undefined.
63
+ RDF::Literal(0)
64
+ when left.nil? && right.nil?
65
+ RDF::Literal(0)
66
+
67
+ # SPARQL also fixes an order between some kinds of RDF terms that would not otherwise be ordered:
68
+ # 2. Blank nodes
69
+ when left.is_a?(RDF::Node) && right.is_a?(RDF::Term)
70
+ RDF::Literal(-1)
71
+ when right.is_a?(RDF::Node) && left.is_a?(RDF::Term)
72
+ RDF::Literal(1)
73
+
74
+ # 3. IRIs
75
+ when left.is_a?(RDF::URI) && right.is_a?(RDF::Term)
76
+ RDF::Literal(-1)
77
+ when right.is_a?(RDF::URI) && left.is_a?(RDF::Term)
78
+ RDF::Literal(1)
79
+ else raise TypeError, "expected two RDF::Term operands, but got #{left.inspect} and #{right.inspect}"
80
+ end
81
+ end
82
+ end # Compare
83
+ end # Operator
84
+ end; end # SPARQL::Algebra
@@ -0,0 +1,85 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL GraphPattern `construct` operator.
5
+ #
6
+ # @example
7
+ # (prefix ((rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>)
8
+ # (foaf: <http://xmlns.com/foaf/0.1/>))
9
+ # (construct ((triple ?s ?p ?o))
10
+ # (project (?s ?p ?o)
11
+ # (bgp (triple ?s ?p ?o)))))
12
+ #
13
+ # @see http://www.w3.org/TR/rdf-sparql-query/#ask
14
+ class Construct < Operator::Binary
15
+ include Query
16
+
17
+ NAME = [:construct]
18
+
19
+ ##
20
+ # Executes this query on the given {RDF::Queryable} object.
21
+ # Binds variables to the array of patterns in the first operand and returns the resulting RDF::Graph object
22
+ #
23
+ # If any such instantiation produces a triple containing an unbound variable or an illegal RDF construct,
24
+ # such as an RDF::Literal in _subject_ or _predicate_ position, then that triple is not included in the output RDF
25
+ # graph. The graph template can contain triples with no variables (known as ground or explicit triples),
26
+ # and these also appear in the output RDF graph returned by the CONSTRUCT query form.
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/#construct
35
+ def execute(queryable, options = {})
36
+ debug(options) {"Construct #{operands.first}, #{options.inspect}"}
37
+ graph = RDF::Graph.new
38
+ patterns = operands.first
39
+ query = operands.last
40
+
41
+ query.execute(queryable, options.merge(:depth => options[:depth].to_i + 1)).each do |solution|
42
+ debug(options) {"=> Apply #{solution.inspect} to BGP"}
43
+
44
+ # Create a mapping from BNodes within the pattern list to newly constructed BNodes
45
+ nodes = {}
46
+ patterns.each do |pattern|
47
+ terms = {}
48
+ [:subject, :predicate, :object].each do |r|
49
+ terms[r] = case o = pattern.send(r)
50
+ when RDF::Node then nodes[o] ||= RDF::Node.new
51
+ when RDF::Query::Variable then solution[o]
52
+ else o
53
+ end
54
+ end
55
+
56
+ statement = RDF::Statement.from(terms)
57
+
58
+ # Sanity checking on statement
59
+ if statement.subject.nil? || statement.predicate.nil? || statement.object.nil? ||
60
+ statement.subject.literal? || statement.predicate.literal?
61
+ debug(options) {"==> skip #{statement.inspect}"}
62
+ next
63
+ end
64
+
65
+ debug(options) {"==> add #{statement.inspect}"}
66
+ graph << statement
67
+ end
68
+ end
69
+
70
+ debug(options) {"=>\n#{graph.dump(:ttl, :standard_prefixes => true)}"}
71
+ graph
72
+ end
73
+
74
+ ##
75
+ # Returns an optimized version of this query.
76
+ #
77
+ # Return optimized query
78
+ #
79
+ # @return [Union, RDF::Query] `self`
80
+ def optimize
81
+ operands = operands.map(&:optimize)
82
+ end
83
+ end # Construct
84
+ end # Operator
85
+ end; end # SPARQL::Algebra