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