sparql 1.0.6 → 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/README.md +11 -4
  2. data/VERSION +1 -1
  3. data/lib/sparql/algebra/extensions.rb +36 -0
  4. data/lib/sparql/algebra/operator.rb +197 -87
  5. data/lib/sparql/algebra/operator/abs.rb +31 -0
  6. data/lib/sparql/algebra/operator/base.rb +1 -0
  7. data/lib/sparql/algebra/operator/bnode.rb +88 -0
  8. data/lib/sparql/algebra/operator/bound.rb +2 -1
  9. data/lib/sparql/algebra/operator/ceil.rb +31 -0
  10. data/lib/sparql/algebra/operator/coalesce.rb +65 -0
  11. data/lib/sparql/algebra/operator/concat.rb +49 -0
  12. data/lib/sparql/algebra/operator/contains.rb +44 -0
  13. data/lib/sparql/algebra/operator/dataset.rb +11 -48
  14. data/lib/sparql/algebra/operator/datatype.rb +4 -2
  15. data/lib/sparql/algebra/operator/day.rb +31 -0
  16. data/lib/sparql/algebra/operator/encode_for_uri.rb +38 -0
  17. data/lib/sparql/algebra/operator/extend.rb +31 -2
  18. data/lib/sparql/algebra/operator/floor.rb +33 -0
  19. data/lib/sparql/algebra/operator/hours.rb +31 -0
  20. data/lib/sparql/algebra/operator/if.rb +55 -0
  21. data/lib/sparql/algebra/operator/in.rb +68 -0
  22. data/lib/sparql/algebra/operator/iri.rb +40 -0
  23. data/lib/sparql/algebra/operator/is_numeric.rb +41 -0
  24. data/lib/sparql/algebra/operator/lang_matches.rb +2 -2
  25. data/lib/sparql/algebra/operator/lcase.rb +31 -0
  26. data/lib/sparql/algebra/operator/md5.rb +34 -0
  27. data/lib/sparql/algebra/operator/minutes.rb +31 -0
  28. data/lib/sparql/algebra/operator/month.rb +31 -0
  29. data/lib/sparql/algebra/operator/not.rb +2 -2
  30. data/lib/sparql/algebra/operator/notin.rb +70 -0
  31. data/lib/sparql/algebra/operator/now.rb +29 -0
  32. data/lib/sparql/algebra/operator/order.rb +9 -13
  33. data/lib/sparql/algebra/operator/rand.rb +24 -0
  34. data/lib/sparql/algebra/operator/replace.rb +81 -0
  35. data/lib/sparql/algebra/operator/round.rb +31 -0
  36. data/lib/sparql/algebra/operator/seconds.rb +31 -0
  37. data/lib/sparql/algebra/operator/sha1.rb +34 -0
  38. data/lib/sparql/algebra/operator/sha256.rb +34 -0
  39. data/lib/sparql/algebra/operator/sha384.rb +34 -0
  40. data/lib/sparql/algebra/operator/sha512.rb +34 -0
  41. data/lib/sparql/algebra/operator/strafter.rb +57 -0
  42. data/lib/sparql/algebra/operator/strbefore.rb +59 -0
  43. data/lib/sparql/algebra/operator/strdt.rb +33 -0
  44. data/lib/sparql/algebra/operator/strends.rb +46 -0
  45. data/lib/sparql/algebra/operator/strlang.rb +34 -0
  46. data/lib/sparql/algebra/operator/strlen.rb +34 -0
  47. data/lib/sparql/algebra/operator/strstarts.rb +46 -0
  48. data/lib/sparql/algebra/operator/struuid.rb +32 -0
  49. data/lib/sparql/algebra/operator/substr.rb +80 -0
  50. data/lib/sparql/algebra/operator/timezone.rb +34 -0
  51. data/lib/sparql/algebra/operator/tz.rb +31 -0
  52. data/lib/sparql/algebra/operator/ucase.rb +31 -0
  53. data/lib/sparql/algebra/operator/uuid.rb +32 -0
  54. data/lib/sparql/algebra/operator/year.rb +31 -0
  55. data/lib/sparql/grammar/parser11.rb +128 -70
  56. data/lib/sparql/grammar/terminals11.rb +4 -5
  57. metadata +62 -7
@@ -0,0 +1,31 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL logical `minutes` operator.
5
+ #
6
+ # @example
7
+ # (prefix ((: <http://example.org/>))
8
+ # (project (?s ?x)
9
+ # (extend ((?x (minutes ?date)))
10
+ # (bgp (triple ?s :date ?date)))))
11
+ #
12
+ # @see http://www.w3.org/TR/sparql11-query/#func-minutes
13
+ class Minutes < Operator::Unary
14
+ include Evaluatable
15
+
16
+ NAME = :minutes
17
+
18
+ ##
19
+ # Returns the minutes part of arg as an integer.
20
+ #
21
+ # @param [RDF::Literal] operand
22
+ # the operand
23
+ # @return [RDF::Literal]
24
+ # @raise [TypeError] if the operand is not a simple literal
25
+ def apply(operand)
26
+ raise TypeError, "expected an RDF::Literal::DateTime, but got #{operand.inspect}" unless operand.is_a?(RDF::Literal::DateTime)
27
+ RDF::Literal(operand.object.minute)
28
+ end
29
+ end # Minutes
30
+ end # Operator
31
+ end; end # SPARQL::Algebra
@@ -0,0 +1,31 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL logical `month` operator.
5
+ #
6
+ # @example
7
+ # (prefix ((: <http://example.org/>))
8
+ # (project (?s ?x)
9
+ # (extend ((?x (month ?date)))
10
+ # (bgp (triple ?s :date ?date)))))
11
+ #
12
+ # @see http://www.w3.org/TR/sparql11-query/#func-month
13
+ class Month < Operator::Unary
14
+ include Evaluatable
15
+
16
+ NAME = :month
17
+
18
+ ##
19
+ # Returns the month part of arg as an integer.
20
+ #
21
+ # @param [RDF::Literal] operand
22
+ # the operand
23
+ # @return [RDF::Literal]
24
+ # @raise [TypeError] if the operand is not a simple literal
25
+ def apply(operand)
26
+ raise TypeError, "expected an RDF::Literal::DateTime, but got #{operand.inspect}" unless operand.is_a?(RDF::Literal::DateTime)
27
+ RDF::Literal(operand.object.month)
28
+ end
29
+ end # Month
30
+ end # Operator
31
+ end; end # SPARQL::Algebra
@@ -4,8 +4,8 @@ module SPARQL; module Algebra
4
4
  # The SPARQL logical `not` operator.
5
5
  #
6
6
  # @example
7
- # (! ?x ?y)
8
- # (not ?x ?y)
7
+ # (! ?x)
8
+ # (not ?x)
9
9
  #
10
10
  # @see http://www.w3.org/TR/xpath-functions/#func-not
11
11
  class Not < Operator::Unary
@@ -0,0 +1,70 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL GraphPattern `in` operator.
5
+ #
6
+ # Used for filters with more than one expression.
7
+ #
8
+ # @example
9
+ # (ask (filter (notin 2) (bgp)))
10
+ #
11
+ # @see http://www.w3.org/TR/sparql11-query/#func-notin
12
+ class NotIn < Operator
13
+ include Evaluatable
14
+
15
+ NAME = :notin
16
+
17
+ ##
18
+ # The NOT IN operator tests whether the RDF term on the left-hand side is not found in the values of list of expressions on the right-hand side. The test is done with "!=" operator, which tests for not the same value, as determined by the operator mapping.
19
+ #
20
+ # A list of zero terms on the right-hand side is legal.
21
+ #
22
+ # Errors in comparisons cause the NOT IN expression to raise an error if the RDF term being tested is not found to be in the list elsewhere in the list of terms.
23
+ #
24
+ # The NOT IN operator is equivalent to the SPARQL expression:
25
+ #
26
+ # (lhs != expression1) && (lhs != expression2) && ...
27
+ #
28
+ # NOT IN (...) is equivalent to !(IN (...)).
29
+ #
30
+ # @example
31
+ #
32
+ # 2 NOT IN (1, 2, 3) false
33
+ # 2 NOT IN () true
34
+ # 2 NOT IN (<http://example/iri>, "str", 2.0) false
35
+ # 2 NOT IN (1/0, 2) false
36
+ # 2 NOT IN (2, 1/0) false
37
+ # 2 NOT IN (3, 1/0) raises an error
38
+ #
39
+ # @param [RDF::Query::Solution, #[]] bindings
40
+ # @return [RDF::Literal::Boolean] `true` or `false`
41
+ # @raise [TypeError] if term is not found and any operand raises an error
42
+ def evaluate(bindings = {})
43
+ lhs = operands.shift.evaluate(bindings)
44
+ error_found = false
45
+ found = operands.any? do |op|
46
+ begin
47
+ lhs == op.evaluate(bindings)
48
+ rescue TypeError
49
+ error_found = true
50
+ end
51
+ end
52
+ case
53
+ when found then RDF::Literal::FALSE
54
+ when error_found then raise TypeError
55
+ else RDF::Literal::TRUE
56
+ end
57
+ end
58
+
59
+ ##
60
+ # Returns an optimized version of this query.
61
+ #
62
+ # Return optimized query
63
+ #
64
+ # @return [Union, RDF::Query] `self`
65
+ def optimize
66
+ operands = operands.map(&:optimize)
67
+ end
68
+ end # Exprlist
69
+ end # Operator
70
+ end; end # SPARQL::Algebra
@@ -0,0 +1,29 @@
1
+ require 'time'
2
+
3
+ module SPARQL; module Algebra
4
+ class Operator
5
+ ##
6
+ # The SPARQL logical `now` operator.
7
+ #
8
+ # @example
9
+ # (prefix ((xsd: <http://www.w3.org/2001/XMLSchema#>))
10
+ # (ask (filter (= (datatype ?n) xsd:dateTime)
11
+ # (extend ((?n (now)))
12
+ # (bgp)))))
13
+ #
14
+ # @see http://www.w3.org/TR/sparql11-query/#func-now
15
+ class Now < Operator::Nullary
16
+ include Evaluatable
17
+
18
+ NAME = :now
19
+
20
+ ##
21
+ # Returns an XSD dateTime value for the current query execution. All calls to this function in any one query execution must return the same value. The exact moment returned is not specified.
22
+ #
23
+ # @return [RDF::Literal::Double] random value
24
+ def apply
25
+ RDF::Literal(DateTime.now)
26
+ end
27
+ end # Now
28
+ end # Operator
29
+ end; end # SPARQL::Algebra
@@ -33,20 +33,16 @@ module SPARQL; module Algebra
33
33
  operand(0).inject(false) do |memo, op|
34
34
  debug(options) {"=> #{op.inspect}"}
35
35
  memo ||= begin
36
- comp = case op
37
- when RDF::Query::Variable
38
- a[op.to_sym] <=> b[op.to_sym]
39
- when Operator, Array
40
- a_eval, b_eval = op.evaluate(a), op.evaluate(b)
41
- if a_eval.nil?
42
- RDF::Literal(-1)
43
- elsif b_eval.nil?
44
- RDF::Literal(1)
45
- else
46
- Operator::Compare.evaluate(a_eval, b_eval)
47
- end
36
+ a_eval = op.evaluate(a) rescue nil
37
+ b_eval = op.evaluate(b) rescue nil
38
+ comp = if a_eval.nil?
39
+ RDF::Literal(-1)
40
+ elsif b_eval.nil?
41
+ RDF::Literal(1)
42
+ elsif op.is_a?(RDF::Query::Variable)
43
+ a_eval <=> b_eval
48
44
  else
49
- raise TypeError, "Unexpected order expression #{op.inspect}"
45
+ Operator::Compare.evaluate(a_eval, b_eval)
50
46
  end
51
47
  comp = -comp if op.is_a?(Operator::Desc)
52
48
  comp == 0 ? false : comp
@@ -0,0 +1,24 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL logical `rand` operator.
5
+ #
6
+ # @example
7
+ # (rand)
8
+ #
9
+ # @see http://www.w3.org/TR/sparql11-query/#idp2130040
10
+ class Rand < Operator::Nullary
11
+ include Evaluatable
12
+
13
+ NAME = :rand
14
+
15
+ ##
16
+ # Returns a pseudo-random number between 0 (inclusive) and 1.0e0 (exclusive). Different numbers can be produced every time this function is invoked. Numbers should be produced with approximately equal probability.
17
+ #
18
+ # @return [RDF::Literal::Double] random value
19
+ def apply
20
+ RDF::Literal::Double.new(Random.rand)
21
+ end
22
+ end # Rand
23
+ end # Operator
24
+ end; end # SPARQL::Algebra
@@ -0,0 +1,81 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL `replace` operator.
5
+ #
6
+ # @example
7
+ # (prefix ((: <http://example.org/>)
8
+ # (xsd: <http://www.w3.org/2001/XMLSchema#>))
9
+ # (project (?s ?new)
10
+ # (extend ((?new (replace ?str "[^a-z0-9]" "-")))
11
+ # (bgp (triple ?s :str ?str)))))
12
+ #
13
+ # @see http://www.w3.org/TR/rdf-sparql-query/#funcex-replace
14
+ # @see http://www.w3.org/TR/xpath-functions/#func-replace
15
+ class Replace < Operator::Quaternary
16
+ include Evaluatable
17
+
18
+ NAME = :replace
19
+
20
+ ##
21
+ # Initializes a new operator instance.
22
+ #
23
+ # @param [RDF::Literal] text
24
+ # @param [RDF::Literal] pattern
25
+ # @param [RDF::Literal] replacement
26
+ # @param [RDF::Literal] flags
27
+ # @param [Hash{Symbol => Object}] options
28
+ # any additional options (see {Operator#initialize})
29
+ # @raise [TypeError] if any operand is invalid
30
+ def initialize(text, pattern, replacement, flags = RDF::Literal(''), options = {})
31
+ super
32
+ end
33
+
34
+ ##
35
+ # Matches `text` against a regular expression `pattern`.
36
+ #
37
+ # @param [RDF::Literal] text a simple literal
38
+ # @param [RDF::Literal] pattern a simple literal
39
+ # @param [RDF::Literal] replacement
40
+ # @param [RDF::Literal] flags
41
+ # a simple literal (defaults to an empty string)
42
+ # @return [RDF::Literal]
43
+ # @raise [TypeError] if any operand is unbound
44
+ # @raise [TypeError] if any operand is not a plain literal
45
+ def apply(text, pattern, replacement, flags = RDF::Literal(''))
46
+ raise TypeError, "expected a plain RDF::Literal, but got #{text.inspect}" unless text.literal? && text.plain?
47
+ # TODO: validate text syntax
48
+
49
+ raise TypeError, "expected a plain RDF::Literal, but got #{pattern.inspect}" unless pattern.literal? && pattern.plain?
50
+ pattern = pattern.to_s
51
+ # TODO: validate pattern syntax
52
+
53
+ raise TypeError, "expected a plain RDF::Literal, but got #{replacement.inspect}" unless replacement.literal? && replacement.plain?
54
+ replacement = replacement.to_s.gsub('$', '\\') # Replace references
55
+ # TODO: validate flag syntax
56
+
57
+ raise TypeError, "expected a plain RDF::Literal, but got #{flags.inspect}" unless flags.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(text.to_s.gsub(Regexp.new(pattern, options), replacement), :datatype => text.datatype, :language => text.language)
67
+ end
68
+
69
+ ##
70
+ # Returns the SPARQL S-Expression (SSE) representation of this expression.
71
+ #
72
+ # Remove the optional argument.
73
+ #
74
+ # @return [Array] `self`
75
+ # @see http://openjena.org/wiki/SSE
76
+ def to_sxp_bin
77
+ [NAME] + operands.reject {|o| o.to_s == ""}
78
+ end
79
+ end # Replace
80
+ end # Operator
81
+ end; end # SPARQL::Algebra
@@ -0,0 +1,31 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL logical `round` operator.
5
+ #
6
+ # @example
7
+ # (round ?x)
8
+ #
9
+ # @see http://www.w3.org/TR/sparql11-query/#func-round
10
+ # @see http://www.w3.org/TR/xpath-functions/#func-round
11
+ class Round < Operator::Unary
12
+ include Evaluatable
13
+
14
+ NAME = [:round]
15
+
16
+ ##
17
+ # Returns the number with no fractional part that is closest to the argument. If there are two such numbers, then the one that is closest to positive infinity is returned. An error is raised if arg is not a numeric value.
18
+ #
19
+ # @param [RDF::Literal] operand
20
+ # the operand
21
+ # @return [RDF::Literal] literal of same type
22
+ # @raise [TypeError] if the operand is not a numeric value
23
+ def apply(operand)
24
+ case operand
25
+ when RDF::Literal::Numeric then operand.round
26
+ else raise TypeError, "expected an RDF::Literal::Numeric, but got #{operand.inspect}"
27
+ end
28
+ end
29
+ end # Round
30
+ end # Operator
31
+ end; end # SPARQL::Algebra
@@ -0,0 +1,31 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+ ##
4
+ # The SPARQL logical `seconds` operator.
5
+ #
6
+ # @example
7
+ # (prefix ((: <http://example.org/>))
8
+ # (project (?s ?x)
9
+ # (extend ((?x (seconds ?date)))
10
+ # (bgp (triple ?s :date ?date)))))
11
+ #
12
+ # @see http://www.w3.org/TR/sparql11-query/#func-seconds
13
+ class Seconds < Operator::Unary
14
+ include Evaluatable
15
+
16
+ NAME = :seconds
17
+
18
+ ##
19
+ # Returns the seconds part of arg as an integer.
20
+ #
21
+ # @param [RDF::Literal] operand
22
+ # the operand
23
+ # @return [RDF::Literal]
24
+ # @raise [TypeError] if the operand is not a simple literal
25
+ def apply(operand)
26
+ raise TypeError, "expected an RDF::Literal::DateTime, but got #{operand.inspect}" unless operand.is_a?(RDF::Literal::DateTime)
27
+ RDF::Literal(operand.object.second)
28
+ end
29
+ end # Seconds
30
+ end # Operator
31
+ end; end # SPARQL::Algebra
@@ -0,0 +1,34 @@
1
+ require 'digest'
2
+
3
+ module SPARQL; module Algebra
4
+ class Operator
5
+ ##
6
+ # The SPARQL logical `sha1` operator.
7
+ #
8
+ # @example
9
+ # (prefix ((: <http://example.org/>))
10
+ # (project (?hash)
11
+ # (extend ((?hash (sha1 ?l)))
12
+ # (bgp (triple :s1 :str ?l)))))
13
+ #
14
+ # @see http://www.w3.org/TR/sparql11-query/#func-sha1
15
+ class SHA1 < Operator::Unary
16
+ include Evaluatable
17
+
18
+ NAME = :sha1
19
+
20
+ ##
21
+ # Returns the SHA1 checksum, as a hex digit string, calculated on the UTF-8 representation of the simple literal or lexical form of the xsd:string. Hex digits should be in lower case.
22
+ #
23
+ # @param [RDF::Literal] operand
24
+ # the operand
25
+ # @return [RDF::Literal]
26
+ # @raise [TypeError] if the operand is not a simple literal
27
+ def apply(operand)
28
+ raise TypeError, "expected an RDF::Literal, but got #{operand.inspect}" unless operand.literal?
29
+ raise TypeError, "expected simple literal or xsd:string, but got #{operand.inspect}" unless (operand.datatype || RDF::XSD.string) == RDF::XSD.string
30
+ RDF::Literal(Digest::SHA1.new.hexdigest(operand.to_s))
31
+ end
32
+ end # SHA1
33
+ end # Operator
34
+ end; end # SPARQL::Algebra
@@ -0,0 +1,34 @@
1
+ require 'digest'
2
+
3
+ module SPARQL; module Algebra
4
+ class Operator
5
+ ##
6
+ # The SPARQL logical `sha256` operator.
7
+ #
8
+ # @example
9
+ # (prefix ((: <http://example.org/>))
10
+ # (project (?hash)
11
+ # (extend ((?hash (sha256 ?l)))
12
+ # (bgp (triple :s1 :str ?l)))))
13
+ #
14
+ # @see http://www.w3.org/TR/sparql11-query/#func-sha256
15
+ class SHA256 < Operator::Unary
16
+ include Evaluatable
17
+
18
+ NAME = :sha256
19
+
20
+ ##
21
+ # Returns the SHA256 checksum, as a hex digit string, calculated on the UTF-8 representation of the simple literal or lexical form of the xsd:string. Hex digits should be in lower case.
22
+ #
23
+ # @param [RDF::Literal] operand
24
+ # the operand
25
+ # @return [RDF::Literal]
26
+ # @raise [TypeError] if the operand is not a simple literal
27
+ def apply(operand)
28
+ raise TypeError, "expected an RDF::Literal, but got #{operand.inspect}" unless operand.literal?
29
+ raise TypeError, "expected simple literal or xsd:string, but got #{operand.inspect}" unless (operand.datatype || RDF::XSD.string) == RDF::XSD.string
30
+ RDF::Literal(Digest::SHA256.new.hexdigest(operand.to_s))
31
+ end
32
+ end # SHA256
33
+ end # Operator
34
+ end; end # SPARQL::Algebra