rdf-n3 3.0.1 → 3.2.0

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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +198 -76
  3. data/UNLICENSE +1 -1
  4. data/VERSION +1 -1
  5. data/lib/rdf/n3/algebra/builtin.rb +79 -0
  6. data/lib/rdf/n3/algebra/formula.rb +446 -0
  7. data/lib/rdf/n3/algebra/list/append.rb +42 -0
  8. data/lib/rdf/n3/algebra/list/first.rb +24 -0
  9. data/lib/rdf/n3/algebra/list/in.rb +48 -0
  10. data/lib/rdf/n3/algebra/list/iterate.rb +96 -0
  11. data/lib/rdf/n3/algebra/list/last.rb +24 -0
  12. data/lib/rdf/n3/algebra/list/length.rb +24 -0
  13. data/lib/rdf/n3/algebra/list/member.rb +44 -0
  14. data/lib/rdf/n3/algebra/list_operator.rb +96 -0
  15. data/lib/rdf/n3/algebra/log/conclusion.rb +65 -0
  16. data/lib/rdf/n3/algebra/log/conjunction.rb +36 -0
  17. data/lib/rdf/n3/algebra/log/content.rb +34 -0
  18. data/lib/rdf/n3/algebra/log/dtlit.rb +41 -0
  19. data/lib/rdf/n3/algebra/log/equal_to.rb +34 -0
  20. data/lib/rdf/n3/algebra/log/implies.rb +102 -0
  21. data/lib/rdf/n3/algebra/log/includes.rb +70 -0
  22. data/lib/rdf/n3/algebra/log/langlit.rb +41 -0
  23. data/lib/rdf/n3/algebra/log/n3_string.rb +34 -0
  24. data/lib/rdf/n3/algebra/log/not_equal_to.rb +23 -0
  25. data/lib/rdf/n3/algebra/log/not_includes.rb +27 -0
  26. data/lib/rdf/n3/algebra/log/output_string.rb +40 -0
  27. data/lib/rdf/n3/algebra/log/parsed_as_n3.rb +36 -0
  28. data/lib/rdf/n3/algebra/log/semantics.rb +40 -0
  29. data/lib/rdf/n3/algebra/math/absolute_value.rb +36 -0
  30. data/lib/rdf/n3/algebra/math/acos.rb +26 -0
  31. data/lib/rdf/n3/algebra/math/acosh.rb +26 -0
  32. data/lib/rdf/n3/algebra/math/asin.rb +26 -0
  33. data/lib/rdf/n3/algebra/math/asinh.rb +26 -0
  34. data/lib/rdf/n3/algebra/math/atan.rb +26 -0
  35. data/lib/rdf/n3/algebra/math/atanh.rb +26 -0
  36. data/lib/rdf/n3/algebra/math/ceiling.rb +28 -0
  37. data/lib/rdf/n3/algebra/math/cos.rb +40 -0
  38. data/lib/rdf/n3/algebra/math/cosh.rb +38 -0
  39. data/lib/rdf/n3/algebra/math/difference.rb +40 -0
  40. data/lib/rdf/n3/algebra/math/equal_to.rb +54 -0
  41. data/lib/rdf/n3/algebra/math/exponentiation.rb +35 -0
  42. data/lib/rdf/n3/algebra/math/floor.rb +28 -0
  43. data/lib/rdf/n3/algebra/math/greater_than.rb +41 -0
  44. data/lib/rdf/n3/algebra/math/less_than.rb +41 -0
  45. data/lib/rdf/n3/algebra/math/negation.rb +38 -0
  46. data/lib/rdf/n3/algebra/math/not_equal_to.rb +25 -0
  47. data/lib/rdf/n3/algebra/math/not_greater_than.rb +25 -0
  48. data/lib/rdf/n3/algebra/math/not_less_than.rb +25 -0
  49. data/lib/rdf/n3/algebra/math/product.rb +20 -0
  50. data/lib/rdf/n3/algebra/math/quotient.rb +36 -0
  51. data/lib/rdf/n3/algebra/math/remainder.rb +35 -0
  52. data/lib/rdf/n3/algebra/math/rounded.rb +26 -0
  53. data/lib/rdf/n3/algebra/math/sin.rb +40 -0
  54. data/lib/rdf/n3/algebra/math/sinh.rb +38 -0
  55. data/lib/rdf/n3/algebra/math/sum.rb +40 -0
  56. data/lib/rdf/n3/algebra/math/tan.rb +40 -0
  57. data/lib/rdf/n3/algebra/math/tanh.rb +38 -0
  58. data/lib/rdf/n3/algebra/not_implemented.rb +13 -0
  59. data/lib/rdf/n3/algebra/resource_operator.rb +122 -0
  60. data/lib/rdf/n3/algebra/str/concatenation.rb +27 -0
  61. data/lib/rdf/n3/algebra/str/contains.rb +33 -0
  62. data/lib/rdf/n3/algebra/str/contains_ignoring_case.rb +33 -0
  63. data/lib/rdf/n3/algebra/str/ends_with.rb +33 -0
  64. data/lib/rdf/n3/algebra/str/equal_ignoring_case.rb +34 -0
  65. data/lib/rdf/n3/algebra/str/format.rb +17 -0
  66. data/lib/rdf/n3/algebra/str/greater_than.rb +38 -0
  67. data/lib/rdf/n3/algebra/str/less_than.rb +33 -0
  68. data/lib/rdf/n3/algebra/str/matches.rb +37 -0
  69. data/lib/rdf/n3/algebra/str/not_equal_ignoring_case.rb +17 -0
  70. data/lib/rdf/n3/algebra/str/not_greater_than.rb +17 -0
  71. data/lib/rdf/n3/algebra/str/not_less_than.rb +17 -0
  72. data/lib/rdf/n3/algebra/str/not_matches.rb +18 -0
  73. data/lib/rdf/n3/algebra/str/replace.rb +35 -0
  74. data/lib/rdf/n3/algebra/str/scrape.rb +35 -0
  75. data/lib/rdf/n3/algebra/str/starts_with.rb +33 -0
  76. data/lib/rdf/n3/algebra/time/day.rb +35 -0
  77. data/lib/rdf/n3/algebra/time/day_of_week.rb +27 -0
  78. data/lib/rdf/n3/algebra/time/gm_time.rb +29 -0
  79. data/lib/rdf/n3/algebra/time/hour.rb +35 -0
  80. data/lib/rdf/n3/algebra/time/in_seconds.rb +59 -0
  81. data/lib/rdf/n3/algebra/time/local_time.rb +29 -0
  82. data/lib/rdf/n3/algebra/time/minute.rb +35 -0
  83. data/lib/rdf/n3/algebra/time/month.rb +35 -0
  84. data/lib/rdf/n3/algebra/time/second.rb +35 -0
  85. data/lib/rdf/n3/algebra/time/timezone.rb +36 -0
  86. data/lib/rdf/n3/algebra/time/year.rb +29 -0
  87. data/lib/rdf/n3/algebra.rb +210 -0
  88. data/lib/rdf/n3/extensions.rb +221 -0
  89. data/lib/rdf/n3/format.rb +66 -1
  90. data/lib/rdf/n3/list.rb +630 -0
  91. data/lib/rdf/n3/reader.rb +774 -497
  92. data/lib/rdf/n3/reasoner.rb +282 -0
  93. data/lib/rdf/n3/refinements.rb +178 -0
  94. data/lib/rdf/n3/repository.rb +332 -0
  95. data/lib/rdf/n3/terminals.rb +78 -0
  96. data/lib/rdf/n3/vocab.rb +36 -3
  97. data/lib/rdf/n3/writer.rb +461 -250
  98. data/lib/rdf/n3.rb +11 -8
  99. metadata +177 -49
  100. data/AUTHORS +0 -1
  101. data/History.markdown +0 -99
  102. data/lib/rdf/n3/patches/array_hacks.rb +0 -53
  103. data/lib/rdf/n3/reader/meta.rb +0 -641
  104. data/lib/rdf/n3/reader/parser.rb +0 -237
@@ -0,0 +1,38 @@
1
+ module RDF::N3::Algebra::Math
2
+ ##
3
+ # The subject or object is calculated to be the negation of the other.
4
+ #
5
+ # @see https://www.w3.org/TR/xpath-functions/#func-numeric-unary-minus
6
+ class Negation < RDF::N3::Algebra::ResourceOperator
7
+ include RDF::N3::Algebra::Builtin
8
+
9
+ NAME = :mathNegation
10
+ URI = RDF::N3::Math.negation
11
+
12
+ ##
13
+ # The math:negation operator takes may have either a bound subject or object.
14
+ #
15
+ # @param [RDF::Term] resource
16
+ # @param [:subject, :object] position
17
+ # @return [RDF::Term]
18
+ # @see RDF::N3::ResourceOperator#evaluate
19
+ def resolve(resource, position:)
20
+ case resource
21
+ when RDF::Query::Variable
22
+ resource
23
+ when RDF::Literal
24
+ as_literal(-resource.as_number)
25
+ else
26
+ nil
27
+ end
28
+ end
29
+
30
+ ##
31
+ # Input is either the subject or object
32
+ #
33
+ # @return [RDF::Term]
34
+ def input_operand
35
+ RDF::N3::List.new(values: operands)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,25 @@
1
+ module RDF::N3::Algebra::Math
2
+ ##
3
+ # True iff the subject is a string representation of a number which is NOT EQUAL to a number of which the object is a string representation.
4
+ #
5
+ # @see https://www.w3.org/TR/xpath-functions/#func-numeric-equal
6
+ class NotEqualTo < EqualTo
7
+ NAME = :mathNotEqualTo
8
+ URI = RDF::N3::Math.notEqualTo
9
+
10
+ ##
11
+ # The math:notEqualTo operator takes a pair of strings or numbers and determines if they are not the same numeric value.
12
+ #
13
+ # @param [RDF::Term] term1
14
+ # an RDF term
15
+ # @param [RDF::Term] term2
16
+ # an RDF term
17
+ # @return [RDF::Literal::Boolean] `true` or `false`
18
+ # @raise [TypeError] if either operand is not an RDF term or operands are not comperable
19
+ #
20
+ # @see RDF::Term#==
21
+ def apply(term1, term2)
22
+ RDF::Literal(super != RDF::Literal::TRUE)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ module RDF::N3::Algebra::Math
2
+ ##
3
+ # True iff the subject is a string representation of a number which is NOT greater than the number of which the object is a string representation.
4
+ #
5
+ # @see https://www.w3.org/TR/xpath-functions/#func-numeric-greater-than
6
+ class NotGreaterThan < GreaterThan
7
+ NAME = :mathNotGreaterThan
8
+ URI = RDF::N3::Math.notGreaterThan
9
+
10
+ ##
11
+ # Returns TRUE if `term1` is less than or equal to `term2`.
12
+ #
13
+ # @param [RDF::Term] term1
14
+ # an RDF term
15
+ # @param [RDF::Term] term2
16
+ # an RDF term
17
+ # @return [RDF::Literal::Boolean] `true` or `false`
18
+ # @raise [TypeError] if either operand is not an RDF term or operands are not comperable
19
+ #
20
+ # @see RDF::Term#==
21
+ def apply(term1, term2)
22
+ RDF::Literal(super != RDF::Literal::TRUE)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ module RDF::N3::Algebra::Math
2
+ ##
3
+ # True iff the subject is a string representation of a number which is NOT LESS than a number of which the object is a string representation.
4
+ #
5
+ # @see https://www.w3.org/TR/xpath-functions/#func-numeric-less-than
6
+ class NotLessThan < LessThan
7
+ NAME = :mathNotLessThan
8
+ URI = RDF::N3::Math.notLessThan
9
+
10
+ ##
11
+ # Returns TRUE if `term1` is greater than or equal to `term2`.
12
+ #
13
+ # @param [RDF::Term] term1
14
+ # an RDF term
15
+ # @param [RDF::Term] term2
16
+ # an RDF term
17
+ # @return [RDF::Literal::Boolean] `true` or `false`
18
+ # @raise [TypeError] if either operand is not an RDF term or operands are not comperable
19
+ #
20
+ # @see RDF::Term#==
21
+ def apply(term1, term2)
22
+ RDF::Literal(super != RDF::Literal::TRUE)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,20 @@
1
+ module RDF::N3::Algebra::Math
2
+ ##
3
+ # The subject is a list of numbers. The object is calculated as the arithmentic product of those numbers.
4
+ #
5
+ # @see https://www.w3.org/TR/xpath-functions/#func-numeric-multiply
6
+ class Product < RDF::N3::Algebra::ListOperator
7
+ NAME = :mathProduct
8
+ URI = RDF::N3::Math.product
9
+
10
+ ##
11
+ # The math:product operator takes a list of strings or numbers and calculates their sum.
12
+ #
13
+ # @param [RDF::N3::List] list
14
+ # @return [RDF::Term]
15
+ # @see RDF::N3::ListOperator#evaluate
16
+ def resolve(list)
17
+ list.to_a.map(&:as_number).reduce(&:*) || RDF::Literal(1) # Empty list product is 1
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,36 @@
1
+ module RDF::N3::Algebra::Math
2
+ ##
3
+ # The subject is a pair of numbers. The object is calculated by dividing the first number of the pair by the second.
4
+ #
5
+ # @see https://www.w3.org/TR/xpath-functions/#func-numeric-divide
6
+ class Quotient < RDF::N3::Algebra::ListOperator
7
+ NAME = :mathQuotient
8
+ URI = RDF::N3::Math.quotient
9
+
10
+ ##
11
+ # The math:quotient operator takes a pair of strings or numbers and calculates their quotient.
12
+ #
13
+ #
14
+ # @param [RDF::N3::List] list
15
+ # @return [RDF::Term]
16
+ # @see RDF::N3::ListOperator#evaluate
17
+ def resolve(list)
18
+ list.to_a.map(&:as_number).reduce(&:/)
19
+ end
20
+
21
+ ##
22
+ # The list argument must be a pair of literals.
23
+ #
24
+ # @param [RDF::N3::List] list
25
+ # @return [Boolean]
26
+ # @see RDF::N3::ListOperator#validate
27
+ def validate(list)
28
+ if super && list.all? {|le| le.is_a?(RDF::Literal)} && list.length == 2
29
+ true
30
+ else
31
+ log_error(NAME) {"list is not a pair of literals: #{list.to_sxp}"}
32
+ false
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,35 @@
1
+ module RDF::N3::Algebra::Math
2
+ ##
3
+ # The subject is a pair of integers. The object is calculated by dividing the first number of the pair by the second and taking the remainder.
4
+ #
5
+ # @see https://www.w3.org/TR/xpath-functions/#func-numeric-mod
6
+ class Remainder < RDF::N3::Algebra::ListOperator
7
+ NAME = :mathRemainder
8
+ URI = RDF::N3::Math.remainder
9
+
10
+ ##
11
+ # The math:remainder operator takes a pair of strings or numbers and calculates their remainder.
12
+ #
13
+ # @param [RDF::N3::List] list
14
+ # @return [RDF::Term]
15
+ # @see RDF::N3::ListOperator#evaluate
16
+ def resolve(list)
17
+ list.to_a.map(&:as_number).reduce(&:%)
18
+ end
19
+
20
+ ##
21
+ # The list argument must be a pair of literals.
22
+ #
23
+ # @param [RDF::N3::List] list
24
+ # @return [Boolean]
25
+ # @see RDF::N3::ListOperator#validate
26
+ def validate(list)
27
+ if super && list.all? {|li| li.is_a?(RDF::Literal) && li.as_number.is_a?(RDF::Literal::Integer)} && list.length == 2
28
+ true
29
+ else
30
+ log_error(NAME) {"list is not a pair of integers: #{list.to_sxp}"}
31
+ false
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,26 @@
1
+ module RDF::N3::Algebra::Math
2
+ ##
3
+ # The object is calulated as the subject rounded to the nearest integer.
4
+ class Rounded < RDF::N3::Algebra::ResourceOperator
5
+ NAME = :mathRounded
6
+ URI = RDF::N3::Math.rounded
7
+
8
+ ##
9
+ # The math:rounded operator takes string or number rounds it to the next integer.
10
+ #
11
+ # @param [RDF::Term] resource
12
+ # @param [:subject, :object] position
13
+ # @return [RDF::Term]
14
+ # @see RDF::N3::ResourceOperator#evaluate
15
+ def resolve(resource, position:)
16
+ case position
17
+ when :subject
18
+ return nil unless resource.literal?
19
+ as_literal(resource.as_number.round)
20
+ when :object
21
+ return nil unless resource.literal? || resource.variable?
22
+ resource
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,40 @@
1
+ module RDF::N3::Algebra::Math
2
+ ##
3
+ # The subject is an angle expressed in radians. The object is calulated as the sine value of the subject.
4
+ #
5
+ # @see https://www.w3.org/TR/xpath-functions/#func-math-sin
6
+ class Sin < RDF::N3::Algebra::ResourceOperator
7
+ NAME = :mathSin
8
+ URI = RDF::N3::Math.sin
9
+
10
+ ##
11
+ # The math:sin operator takes string or number and calculates its sine. The arc sine of a concrete object can also calculate a variable subject.
12
+ #
13
+ # @param [RDF::Term] resource
14
+ # @param [:subject, :object] position
15
+ # @return [RDF::Term]
16
+ # @see RDF::N3::ResourceOperator#evaluate
17
+ def resolve(resource, position:)
18
+ case resource
19
+ when RDF::Query::Variable then resource
20
+ when RDF::Literal
21
+ case position
22
+ when :subject
23
+ as_literal(Math.sin(resource.as_number.object))
24
+ when :object
25
+ as_literal(Math.sinh(resource.as_number.object))
26
+ end
27
+ else
28
+ nil
29
+ end
30
+ end
31
+
32
+ ##
33
+ # Input is either the subject or object
34
+ #
35
+ # @return [RDF::Term]
36
+ def input_operand
37
+ RDF::N3::List.new(values: operands)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,38 @@
1
+ module RDF::N3::Algebra::Math
2
+ ##
3
+ # The subject is an angle expressed in radians. The object is calulated as the hyperbolic sine value of the subject.
4
+ class SinH < RDF::N3::Algebra::ResourceOperator
5
+ NAME = :mathSinH
6
+ URI = RDF::N3::Math.sinh
7
+
8
+ ##
9
+ # The math:sinh operator takes string or number and calculates its hyperbolic sine. The inverse hyperbolic sine of a concrete object can also calculate a variable subject.
10
+ #
11
+ # @param [RDF::Term] resource
12
+ # @param [:subject, :object] position
13
+ # @return [RDF::Term]
14
+ # @see RDF::N3::ResourceOperator#evaluate
15
+ def resolve(resource, position:)
16
+ case resource
17
+ when RDF::Query::Variable then resource
18
+ when RDF::Literal
19
+ case position
20
+ when :subject
21
+ as_literal(Math.sinh(resource.as_number.object))
22
+ when :object
23
+ as_literal(Math.asinh(resource.as_number.object))
24
+ end
25
+ else
26
+ nil
27
+ end
28
+ end
29
+
30
+ ##
31
+ # Input is either the subject or object
32
+ #
33
+ # @return [RDF::Term]
34
+ def input_operand
35
+ RDF::N3::List.new(values: operands)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,40 @@
1
+ module RDF::N3::Algebra::Math
2
+ ##
3
+ # **schema**:
4
+ # `($a_1 .. $a_n) math:sum $a_s`
5
+ #
6
+ # **summary**:
7
+ # performs addition of numbers
8
+ #
9
+ # **definition**:
10
+ # `true` if and only if the arithmetic sum of `$a_1, .. $a_n` equals `$a_s`.
11
+ # Requires either:
12
+ #
13
+ # 1. all `$a_1, .., $a_n` to be bound; or
14
+ # 2. all but one `$a_i` (subject list) to be bound, and `$a_s` to be bound.
15
+ #
16
+ # **literal domains**:
17
+ #
18
+ # * `$a_1 .. $a_n` : `xs:decimal` (or its derived types), `xs:float`, or `xs:double` (see note on type promotion, and casting from string)
19
+ # * `$a_s`: `xs:decimal` (or its derived types), `xs:float`, or `xs:double` (see note on type promotion, and casting from string)
20
+ #
21
+ # @example
22
+ # { ("3" "5") math:sum ?x } => { ?x :valueOf "3 + 5" } .
23
+ # { (3 5) math:sum ?x } => { ?x :valueOf "3 + 5 = 8" } .
24
+ #
25
+ # @see https://www.w3.org/TR/xpath-functions/#func-numeric-add
26
+ class Sum < RDF::N3::Algebra::ListOperator
27
+ NAME = :mathSum
28
+ URI = RDF::N3::Math[:sum]
29
+
30
+ ##
31
+ # Evaluates to the sum of the list elements
32
+ #
33
+ # @param [RDF::N3::List] list
34
+ # @return [RDF::Term]
35
+ # @see RDF::N3::ListOperator#evaluate
36
+ def resolve(list)
37
+ list.to_a.map(&:as_number).reduce(&:+) || RDF::Literal(0) # Empty list sums to 0
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ module RDF::N3::Algebra::Math
2
+ ##
3
+ # The subject is an angle expressed in radians. The object is calulated as the tangent value of the subject.
4
+ #
5
+ # @see https://www.w3.org/TR/xpath-functions/#func-math-tan
6
+ class Tan < RDF::N3::Algebra::ResourceOperator
7
+ NAME = :mathTan
8
+ URI = RDF::N3::Math.tan
9
+
10
+ ##
11
+ # The math:tan operator takes string or number and calculates its tangent. The arc tangent of a concrete object can also calculate a variable subject.
12
+ #
13
+ # @param [RDF::Term] resource
14
+ # @param [:subject, :object] position
15
+ # @return [RDF::Term]
16
+ # @see RDF::N3::ResourceOperator#evaluate
17
+ def resolve(resource, position:)
18
+ case resource
19
+ when RDF::Query::Variable then resource
20
+ when RDF::Literal
21
+ case position
22
+ when :subject
23
+ as_literal(Math.tan(resource.as_number.object))
24
+ when :object
25
+ as_literal(Math.atan(resource.as_number.object))
26
+ end
27
+ else
28
+ nil
29
+ end
30
+ end
31
+
32
+ ##
33
+ # Input is either the subject or object
34
+ #
35
+ # @return [RDF::Term]
36
+ def input_operand
37
+ RDF::N3::List.new(values: operands)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,38 @@
1
+ module RDF::N3::Algebra::Math
2
+ ##
3
+ # The subject is an angle expressed in radians. The object is calulated as the tangent value of the subject.
4
+ class TanH < RDF::N3::Algebra::ResourceOperator
5
+ NAME = :mathTanH
6
+ URI = RDF::N3::Math.tanh
7
+
8
+ ##
9
+ # The math:tanh operator takes string or number and calculates its hyperbolic tangent. The inverse hyperbolic tangent of a concrete object can also calculate a variable subject.
10
+ #
11
+ # @param [RDF::Term] resource
12
+ # @param [:subject, :object] position
13
+ # @return [RDF::Term]
14
+ # @see RDF::N3::ResourceOperator#evaluate
15
+ def resolve(resource, position:)
16
+ case resource
17
+ when RDF::Query::Variable then resource
18
+ when RDF::Literal
19
+ case position
20
+ when :subject
21
+ as_literal(Math.tanh(resource.as_number.object))
22
+ when :object
23
+ as_literal(Math.atanh(resource.as_number.object))
24
+ end
25
+ else
26
+ nil
27
+ end
28
+ end
29
+
30
+ ##
31
+ # Input is either the subject or object
32
+ #
33
+ # @return [RDF::Term]
34
+ def input_operand
35
+ RDF::N3::List.new(values: operands)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,13 @@
1
+ require 'rdf'
2
+
3
+ module RDF::N3::Algebra
4
+ #
5
+ # A Notation3 Formula combines a graph with a BGP query.
6
+ class NotImplemented < SPARQL::Algebra::Operator
7
+ include RDF::N3::Algebra::Builtin
8
+
9
+ def initialize(*args, predicate:, **options)
10
+ raise NotImplementedError, "The #{predicate} operator is not implemented"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,122 @@
1
+ module RDF::N3::Algebra
2
+ ##
3
+ # This is a generic operator where the subject is a literal or binds to a literal and the object is either a constant that equals the evaluation of the subject, or a variable to which the result is bound in a solution
4
+ class ResourceOperator < SPARQL::Algebra::Operator::Binary
5
+ include SPARQL::Algebra::Query
6
+ include SPARQL::Algebra::Update
7
+ include RDF::N3::Algebra::Builtin
8
+
9
+ NAME = :resourceOperator
10
+
11
+ ##
12
+ # The operator takes a literal and provides a mechanism for subclasses to operate over (and validate) that argument.
13
+ #
14
+ # @param [RDF::Queryable] queryable
15
+ # the graph or repository to query
16
+ # @param [RDF::Query::Solutions] solutions
17
+ # solutions for chained queries
18
+ # @return [RDF::Query::Solutions]
19
+ def execute(queryable, solutions:, **options)
20
+ RDF::Query::Solutions(solutions.map do |solution|
21
+ subject = operand(0).evaluate(solution.bindings, formulae: formulae) || operand(0)
22
+ object = operand(1).evaluate(solution.bindings, formulae: formulae) || operand(1)
23
+ subject = formulae.fetch(subject, subject) if subject.node?
24
+ object = formulae.fetch(object, object) if object.node?
25
+
26
+ log_info(self.class.const_get(:NAME), "subject") {SXP::Generator.string(subject.to_sxp_bin).strip}
27
+ log_info(self.class.const_get(:NAME), "object") {SXP::Generator.string(object.to_sxp_bin).strip}
28
+ next unless valid?(subject, object)
29
+
30
+ lhs = resolve(subject, position: :subject)
31
+ if lhs.nil?
32
+ log_error(self.class.const_get(:NAME), "subject evaluates to null") {subject.inspect}
33
+ next
34
+ end
35
+
36
+ rhs = resolve(object, position: :object)
37
+ if rhs.nil?
38
+ log_error(self.class.const_get(:NAME), "object evaluates to null") {object.inspect}
39
+ next
40
+ end
41
+
42
+ if object.variable?
43
+ log_debug(self.class.const_get(:NAME), "result") {SXP::Generator.string(lhs.to_sxp_bin).strip}
44
+ solution.merge(object.to_sym => lhs)
45
+ elsif subject.variable?
46
+ log_debug(self.class.const_get(:NAME), "result") {SXP::Generator.string(rhs.to_sxp_bin).strip}
47
+ solution.merge(subject.to_sym => rhs)
48
+ elsif respond_to?(:apply)
49
+ res = apply(lhs, rhs)
50
+ log_debug(self.class.const_get(:NAME), "result") {SXP::Generator.string(res.to_sxp_bin).strip}
51
+ # Return the result applying subject and object
52
+ case res
53
+ when RDF::Literal::TRUE
54
+ solution
55
+ when RDF::Literal::FALSE
56
+ nil
57
+ when RDF::Query::Solution
58
+ solution.merge(res)
59
+ else
60
+ log_error(self.class.const_get(:NAME), "unexpected result type")
61
+ nil
62
+ end
63
+ elsif rhs != lhs
64
+ log_debug(self.class.const_get(:NAME), "result: false")
65
+ nil
66
+ else
67
+ log_debug(self.class.const_get(:NAME), "result: true")
68
+ solution
69
+ end
70
+ end.compact.uniq)
71
+ end
72
+
73
+ ##
74
+ # Input is generically the subject
75
+ #
76
+ # @return [RDF::Term]
77
+ def input_operand
78
+ operand(0)
79
+ end
80
+
81
+ ##
82
+ # Subclasses implement `resolve`.
83
+ #
84
+ # Returns nil if resource does not validate, given its position
85
+ #
86
+ # @param [RDF::Term] resource
87
+ # @return [RDF::Term]
88
+ def resolve(resource, position: :subject)
89
+ raise NotImplemented
90
+ end
91
+
92
+ ##
93
+ # Subclasses may override or supplement validate to perform validation on the list subject
94
+ #
95
+ # @param [RDF::Term] subject
96
+ # @param [RDF::Term] object
97
+ # @return [Boolean]
98
+ def valid?(subject, object)
99
+ case subject
100
+ when RDF::Query::Variable
101
+ object.term?
102
+ when RDF::Term
103
+ object.term? || object.variable?
104
+ else
105
+ false
106
+ end
107
+ end
108
+
109
+ ##
110
+ # Returns a literal for the numeric argument.
111
+ def as_literal(object)
112
+ case object
113
+ when Float
114
+ literal = RDF::Literal(object, canonicalize: true)
115
+ literal.instance_variable_set(:@string, literal.to_s.downcase)
116
+ literal
117
+ else
118
+ RDF::Literal(object, canonicalize: true)
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,27 @@
1
+ module RDF::N3::Algebra::Str
2
+ ##
3
+ # The subject is a list of strings. The object is calculated as a concatenation of those strings.
4
+ #
5
+ # @example
6
+ # ("a" "b") string:concatenation :s
7
+ class Concatenation < RDF::N3::Algebra::ListOperator
8
+ NAME = :strConcatenation
9
+ URI = RDF::N3::Str.concatenation
10
+
11
+ ##
12
+ # The string:concatenation operator takes a list of terms cast to strings and either binds the result of concatenating them to the output variable, removes a solution that does equal the literal object.
13
+ #
14
+ # List entries are stringified using {SPARQL::Algebra::Expression.cast}.
15
+ #
16
+ # @param [RDF::N3::List] list
17
+ # @return [RDF::Term]
18
+ # @see RDF::N3::ListOperator#evaluate
19
+ def resolve(list)
20
+ RDF::Literal(
21
+ list.to_a.map do |o|
22
+ SPARQL::Algebra::Expression.cast(RDF::XSD.string, o)
23
+ end.join("")
24
+ )
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,33 @@
1
+ module RDF::N3::Algebra::Str
2
+ # True iff the subject string contains the object string.
3
+ class Contains < RDF::N3::Algebra::ResourceOperator
4
+ NAME = :strContains
5
+ URI = RDF::N3::Str.contains
6
+
7
+ ##
8
+ # Resolves inputs as strings.
9
+ #
10
+ # @param [RDF::Term] resource
11
+ # @param [:subject, :object] position
12
+ # @return [RDF::Literal]
13
+ # @see RDF::N3::ResourceOperator#evaluate
14
+ def resolve(resource, position:)
15
+ resource if resource.term?
16
+ end
17
+
18
+ # Neither subect nor object are considered inputs, and must be resolved before evaluation.
19
+ def input_operand
20
+ RDF::N3::List.new
21
+ end
22
+
23
+ ##
24
+ # @param [String] left
25
+ # a literal
26
+ # @param [String] right
27
+ # a literal
28
+ # @return [RDF::Literal::Boolean]
29
+ def apply(left, right)
30
+ RDF::Literal(left.to_s.include?(right.to_s))
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ module RDF::N3::Algebra::Str
2
+ # True iff the subject string contains the object string, with the comparison done ignoring the difference between upper case and lower case characters.
3
+ class ContainsIgnoringCase < RDF::N3::Algebra::ResourceOperator
4
+ NAME = :strContainsIgnoringCase
5
+ URI = RDF::N3::Str.containsIgnoringCase
6
+
7
+ ##
8
+ # Resolves inputs as lower-case strings.
9
+ #
10
+ # @param [RDF::Term] resource
11
+ # @param [:subject, :object] position
12
+ # @return [RDF::Literal]
13
+ # @see RDF::N3::ResourceOperator#evaluate
14
+ def resolve(resource, position:)
15
+ RDF::Literal(resource.to_s.downcase) if resource.term?
16
+ end
17
+
18
+ # Both subject and object are inputs.
19
+ def input_operand
20
+ RDF::N3::List.new(values: operands)
21
+ end
22
+
23
+ ##
24
+ # @param [String] left
25
+ # a literal
26
+ # @param [String] right
27
+ # a literal
28
+ # @return [RDF::Literal::Boolean]
29
+ def apply(left, right)
30
+ RDF::Literal(left.to_s.include?(right.to_s))
31
+ end
32
+ end
33
+ end