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,47 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL GraphPattern `reduced` operator.
5
+ #
6
+ # @example
7
+ # (prefix ((xsd: <http://www.w3.org/2001/XMLSchema#>)
8
+ # (: <http://example/>))
9
+ # (reduced
10
+ # (project (?v)
11
+ # (bgp (triple ?x ?p ?v)))))
12
+ #
13
+ # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
14
+ class Reduced < Operator::Unary
15
+ include Query
16
+
17
+ NAME = [:reduced]
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
+ @solutions = operands.last.
32
+ execute(queryable, options.merge(:depth => options[:depth].to_i + 1)).
33
+ reduced
34
+ end
35
+
36
+ ##
37
+ # Returns an optimized version of this query.
38
+ #
39
+ # Return optimized query
40
+ #
41
+ # @return [Union, RDF::Query] `self`
42
+ def optimize
43
+ operands = operands.map(&:optimize)
44
+ end
45
+ end # Reduced
46
+ end # Operator
47
+ end; end # SPARQL::Algebra
@@ -0,0 +1,70 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL `regex` operator.
5
+ #
6
+ # @example
7
+ # (prefix ((ex: <http://example.com/#>)
8
+ # (rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>))
9
+ # (project (?val)
10
+ # (filter (regex ?val "GHI")
11
+ # (bgp (triple ex:foo rdf:value ?val)))))
12
+ #
13
+ # @see http://www.w3.org/TR/rdf-sparql-query/#funcex-regex
14
+ # @see http://www.w3.org/TR/xpath-functions/#func-matches
15
+ class Regex < Operator::Ternary
16
+ include Evaluatable
17
+
18
+ NAME = :regex
19
+
20
+ ##
21
+ # Initializes a new operator instance.
22
+ #
23
+ # @param [RDF::Term] text
24
+ # @param [RDF::Term] pattern
25
+ # @param [RDF::Term] flags
26
+ # @param [Hash{Symbol => Object}] options
27
+ # any additional options (see {Operator#initialize})
28
+ # @raise [TypeError] if any operand is invalid
29
+ def initialize(text, pattern, flags = RDF::Literal(''), options = {})
30
+ super
31
+ end
32
+
33
+ ##
34
+ # Matches `text` against a regular expression `pattern`.
35
+ #
36
+ # @param [RDF::Literal] text
37
+ # a simple literal
38
+ # @param [RDF::Literal] pattern
39
+ # a simple literal
40
+ # @param [RDF::Literal] flags
41
+ # a simple literal (defaults to an empty string)
42
+ # @return [RDF::Literal::Boolean] `true` or `false`
43
+ # @raise [TypeError] if any operand is unbound
44
+ # @raise [TypeError] if any operand is not a simple literal
45
+ def apply(text, pattern, flags = RDF::Literal(''))
46
+ # @see http://www.w3.org/TR/xpath-functions/#regex-syntax
47
+ raise TypeError, "expected a plain RDF::Literal, but got #{text.inspect}" unless text.is_a?(RDF::Literal) && text.plain?
48
+ text = text.to_s
49
+ # TODO: validate text syntax
50
+
51
+ # @see http://www.w3.org/TR/xpath-functions/#regex-syntax
52
+ raise TypeError, "expected a plain RDF::Literal, but got #{pattern.inspect}" unless pattern.is_a?(RDF::Literal) && pattern.plain?
53
+ pattern = pattern.to_s
54
+ # TODO: validate pattern syntax
55
+
56
+ # @see http://www.w3.org/TR/xpath-functions/#flags
57
+ raise TypeError, "expected a plain RDF::Literal, but got #{flags.inspect}" unless flags.is_a?(RDF::Literal) && flags.plain?
58
+ flags = flags.to_s
59
+ # TODO: validate flag syntax
60
+
61
+ options = 0
62
+ raise NotImplementedError, "unsupported regular expression flag: /s" if flags.include?(?s) # FIXME
63
+ options |= Regexp::MULTILINE if flags.include?(?m)
64
+ options |= Regexp::IGNORECASE if flags.include?(?i)
65
+ options |= Regexp::EXTENDED if flags.include?(?x)
66
+ RDF::Literal(Regexp.new(pattern, options) === text)
67
+ end
68
+ end # Regex
69
+ end # Operator
70
+ end; end # SPARQL::Algebra
@@ -0,0 +1,46 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL `sameTerm` operator.
5
+ #
6
+ # @example
7
+ # (prefix ((xsd: <http://www.w3.org/2001/XMLSchema#>)
8
+ # (: <http://example.org/things#>))
9
+ # (project (?x ?v)
10
+ # (filter (sameTerm ?v)
11
+ # (bgp (triple ?x :p ?v)))))
12
+ #
13
+ # @see http://www.w3.org/TR/rdf-sparql-query/#func-sameTerm
14
+ class SameTerm < Operator::Binary
15
+ include Evaluatable
16
+
17
+ NAME = :sameTerm
18
+
19
+ ##
20
+ # Returns `true` if the operands are the same RDF term; returns
21
+ # `false` otherwise.
22
+ #
23
+ # @param [RDF::Term] term1
24
+ # an RDF term
25
+ # @param [RDF::Term] term2
26
+ # an RDF term
27
+ # @return [RDF::Literal::Boolean] `true` or `false`
28
+ # @raise [TypeError] if either operand is unbound
29
+ def apply(term1, term2)
30
+ RDF::Literal(term1.eql?(term2))
31
+ end
32
+
33
+ ##
34
+ # Returns an optimized version of this expression.
35
+ #
36
+ # @return [SPARQL::Algebra::Expression]
37
+ def optimize
38
+ if operand(0).is_a?(Variable) && operand(0).eql?(operand(1))
39
+ RDF::Literal::TRUE
40
+ else
41
+ super # @see Operator#optimize
42
+ end
43
+ end
44
+ end # SameTerm
45
+ end # Operator
46
+ end; end # SPARQL::Algebra
@@ -0,0 +1,60 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL GraphPattern `slice` operator.
5
+ #
6
+ # @example
7
+ # (prefix ((: <http://example.org/ns#>))
8
+ # (slice 1 1
9
+ # (project (?v)
10
+ # (order (?v)
11
+ # (bgp (triple ??0 :num ?v))))))
12
+ #
13
+ # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
14
+ class Slice < Operator::Ternary
15
+ include Query
16
+
17
+ NAME = [:slice]
18
+
19
+ ##
20
+ # Executes this query on the given `queryable` graph or repository.
21
+ # Returns a subset of the solutions resulting from executing
22
+ # the third operand, an RDF::Queryable object by indexing in to the
23
+ # result set by the amount specified in the first operand and limiting
24
+ # the total number of solutions returned by the amount specified in the
25
+ # second operand.
26
+ #
27
+ # If either the first or second operands are `:_`, they are not considered.
28
+ #
29
+ # @example
30
+ #
31
+ # (slice 1 2 (bgp (triple ?s ?p ?o))) # Returns at most two solutions starting with the second solution.
32
+ # (slice _ 2 (bgp (triple ?s ?p ?o))) # Returns at most two solutions starting with the first solution.
33
+ # (slice 1 _ (bgp (triple ?s ?p ?o))) # Returns all solution after the first.
34
+ #
35
+ # @param [RDF::Queryable] queryable
36
+ # the graph or repository to query
37
+ # @param [Hash{Symbol => Object}] options
38
+ # any additional keyword options
39
+ # @return [RDF::Query::Solutions]
40
+ # the resulting solution sequence
41
+ # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
42
+ def execute(queryable, options = {})
43
+ @solutions = operands.last. execute(queryable, options.merge(:depth => options[:depth].to_i + 1))
44
+ @solutions.offset(operands[0]) unless operands[0] == :_
45
+ @solutions.limit(operands[1]) unless operands[1] == :_
46
+ @solutions
47
+ end
48
+
49
+ ##
50
+ # Returns an optimized version of this query.
51
+ #
52
+ # Return optimized query
53
+ #
54
+ # @return [Union, RDF::Query] `self`
55
+ def optimize
56
+ operands = operands.map(&:optimize)
57
+ end
58
+ end # Slice
59
+ end # Operator
60
+ end; end # SPARQL::Algebra
@@ -0,0 +1,35 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL `str` operator.
5
+ #
6
+ # @example
7
+ # (prefix ((xsd: <http://www.w3.org/2001/XMLSchema#>)
8
+ # (: <http://example.org/things#>))
9
+ # (project (?x ?v)
10
+ # (filter (= (str ?v) "1")
11
+ # (bgp (triple ?x :p ?v)))))
12
+ #
13
+ # @see http://www.w3.org/TR/rdf-sparql-query/#func-str
14
+ class Str < Operator::Unary
15
+ include Evaluatable
16
+
17
+ NAME = :str
18
+
19
+ ##
20
+ # Returns the string form of the operand.
21
+ #
22
+ # @param [RDF::Literal, RDF::URI] term
23
+ # a literal or IRI
24
+ # @return [RDF::Literal] a simple literal
25
+ # @raise [TypeError] if the operand is not a literal or IRI
26
+ def apply(term)
27
+ case term
28
+ when RDF::Literal then RDF::Literal(term.value)
29
+ when RDF::URI then RDF::Literal(term.to_s)
30
+ else raise TypeError, "expected an RDF::Literal or RDF::URI, but got #{term.inspect}"
31
+ end
32
+ end
33
+ end # Str
34
+ end # Operator
35
+ end; end # SPARQL::Algebra
@@ -0,0 +1,32 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL numeric `subtract` operator.
5
+ # (- ?x ?y)
6
+ # (subtract ?x ?y)
7
+ #
8
+ # @see http://www.w3.org/TR/xpath-functions/#func-numeric-subtract
9
+ class Subtract < Operator::Binary
10
+ include Evaluatable
11
+
12
+ NAME = [:-, :subtract]
13
+
14
+ ##
15
+ # Returns the arithmetic difference of the operands.
16
+ #
17
+ # @param [RDF::Literal::Numeric] left
18
+ # a numeric literal
19
+ # @param [RDF::Literal::Numeric] right
20
+ # a numeric literal
21
+ # @return [RDF::Literal::Numeric]
22
+ # @raise [TypeError] if either operand is not a numeric literal
23
+ def apply(left, right)
24
+ case
25
+ when left.is_a?(RDF::Literal::Numeric) && right.is_a?(RDF::Literal::Numeric)
26
+ left - right
27
+ else raise TypeError, "expected two RDF::Literal::Numeric operands, but got #{left.inspect} and #{right.inspect}"
28
+ end
29
+ end
30
+ end # Subtract
31
+ end # Operator
32
+ end; end # SPARQL::Algebra
@@ -0,0 +1,55 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL GraphPattern `union` operator.
5
+ #
6
+ # @example
7
+ # (prefix ((: <http://example/>))
8
+ # (union
9
+ # (bgp (triple ?s ?p ?o))
10
+ # (graph ?g
11
+ # (bgp (triple ?s ?p ?o)))))
12
+ #
13
+ # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
14
+ class Union < Operator::Binary
15
+ include Query
16
+
17
+ NAME = [:union]
18
+
19
+ ##
20
+ # Executes each operand with `queryable` and performs the `union` operation
21
+ # by creating a new solution set consiting of all solutions from both operands.
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) {"Union"}
32
+ solutions1 = operand(0).execute(queryable, options.merge(:depth => options[:depth].to_i + 1))
33
+ debug(options) {"=>(left) #{solutions1.inspect}"}
34
+ solutions2 = operand(1).execute(queryable, options.merge(:depth => options[:depth].to_i + 1))
35
+ debug(options) {"=>(right) #{solutions2.inspect}"}
36
+ @solutions = RDF::Query::Solutions.new(solutions1 + solutions2)
37
+ debug(options) {"=> #{@solutions.inspect}"}
38
+ @solutions
39
+ end
40
+
41
+ ##
42
+ # Returns an optimized version of this query.
43
+ #
44
+ # If optimize operands, and if the first two operands are both Queries, replace
45
+ # with the unique sum of the query elements
46
+ #
47
+ # @return [Union, RDF::Query] `self`
48
+ def optimize
49
+ ops = operands.map {|o| o.optimize }.select {|o| o.respond_to?(:empty?) && !o.empty?}
50
+ @operands = ops
51
+ self
52
+ end
53
+ end # Union
54
+ end # Operator
55
+ end; end # SPARQL::Algebra
@@ -0,0 +1,99 @@
1
+ module SPARQL; module Algebra
2
+ ##
3
+ # A SPARQL algebra query, may be duck-typed as RDF::Query.
4
+ #
5
+ # Mixin with SPARQL::Algebra::Operator to provide query-like operations on graphs and filters
6
+ #
7
+ # @abstract
8
+ module Query
9
+ ##
10
+ # Prepends an operator.
11
+ #
12
+ # @param [RDF::Query] query
13
+ # a query
14
+ # @return [void] self
15
+ def unshift(query)
16
+ @operands.unshift(query)
17
+ self
18
+ end
19
+
20
+ ##
21
+ # The variables used in this query.
22
+ #
23
+ # @return [Hash{Symbol => RDF::Query::Variable}]
24
+ def variables
25
+ operands.inject({}) {|hash, o| o.executable? ? hash.merge!(o.variables) : hash}
26
+ end
27
+
28
+ ##
29
+ # The solution sequence for this query.
30
+ #
31
+ # @return [RDF::Query::Solutions]
32
+ attr_reader :solutions
33
+
34
+ ##
35
+ # Executes this query on the given `queryable` graph or repository.
36
+ #
37
+ # @param [RDF::Queryable] queryable
38
+ # the graph or repository to query
39
+ # @param [Hash{Symbol => Object}] options
40
+ # any additional keyword options
41
+ # @option options [Boolean] debug
42
+ # Query execution debugging
43
+ # @return [RDF::Query::Solutions]
44
+ # the resulting solution sequence
45
+ # @raise [TypeError]
46
+ # TypeError raised if any operands are invalid
47
+ # @raise [NotImplementedError]
48
+ # If an attempt is made to perform an unsupported operation
49
+ # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
50
+ def execute(queryable, options = {})
51
+ raise NotImplementedError, "#{self.class}#execute(#{queryable})"
52
+ end
53
+
54
+ # Add context to sub-items, unless they already have a context
55
+ # @param [RDF::URI, RDF::Query::Variable] value
56
+ # @return [RDF::URI, RDF::Query::Variable]
57
+ def context=(value)
58
+ operands.each do |operand|
59
+ operand.context = value if operand.respond_to?(:context) && operand.context != false
60
+ end
61
+ value
62
+ end
63
+
64
+ ##
65
+ # Returns `true` if this query did not match when last executed.
66
+ #
67
+ # When the solution sequence is empty, this method can be used to
68
+ # determine whether the query failed to match or not.
69
+ #
70
+ # @return [Boolean]
71
+ # @see #matched?
72
+ def failed?
73
+ solutions.empty?
74
+ end
75
+
76
+ ##
77
+ # Returns `true` if this query matched when last executed.
78
+ #
79
+ # When the solution sequence is empty, this method can be used to
80
+ # determine whether the query matched successfully or not.
81
+ #
82
+ # @return [Boolean]
83
+ # @see #failed?
84
+ def matched?
85
+ !failed?
86
+ end
87
+
88
+ ##
89
+ # Enumerates over each matching query solution.
90
+ #
91
+ # @yield [solution]
92
+ # @yieldparam [RDF::Query::Solution] solution
93
+ # @return [Enumerator]
94
+ def each_solution(&block)
95
+ solutions.each(&block)
96
+ end
97
+ alias_method :each, :each_solution
98
+ end # Query
99
+ end; end # SPARQL::Algebra