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,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