rdf-n3 3.0.1 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +95 -51
  3. data/VERSION +1 -1
  4. data/lib/rdf/n3.rb +9 -6
  5. data/lib/rdf/n3/algebra.rb +125 -0
  6. data/lib/rdf/n3/algebra/formula.rb +185 -0
  7. data/lib/rdf/n3/algebra/list/append.rb +13 -0
  8. data/lib/rdf/n3/algebra/list/in.rb +9 -0
  9. data/lib/rdf/n3/algebra/list/last.rb +11 -0
  10. data/lib/rdf/n3/algebra/list/member.rb +7 -0
  11. data/lib/rdf/n3/algebra/log/conclusion.rb +9 -0
  12. data/lib/rdf/n3/algebra/log/conjunction.rb +9 -0
  13. data/lib/rdf/n3/algebra/log/equalTo.rb +7 -0
  14. data/lib/rdf/n3/algebra/log/implies.rb +77 -0
  15. data/lib/rdf/n3/algebra/log/includes.rb +13 -0
  16. data/lib/rdf/n3/algebra/log/notEqualTo.rb +7 -0
  17. data/lib/rdf/n3/algebra/log/notIncludes.rb +12 -0
  18. data/lib/rdf/n3/algebra/log/outputString.rb +7 -0
  19. data/lib/rdf/n3/algebra/math/absoluteValue.rb +9 -0
  20. data/lib/rdf/n3/algebra/math/difference.rb +9 -0
  21. data/lib/rdf/n3/algebra/math/equalTo.rb +9 -0
  22. data/lib/rdf/n3/algebra/math/exponentiation.rb +9 -0
  23. data/lib/rdf/n3/algebra/math/greaterThan.rb +9 -0
  24. data/lib/rdf/n3/algebra/math/integerQuotient.rb +9 -0
  25. data/lib/rdf/n3/algebra/math/lessThan.rb +9 -0
  26. data/lib/rdf/n3/algebra/math/memberCount.rb +9 -0
  27. data/lib/rdf/n3/algebra/math/negation.rb +9 -0
  28. data/lib/rdf/n3/algebra/math/notEqualTo.rb +9 -0
  29. data/lib/rdf/n3/algebra/math/notGreaterThan.rb +9 -0
  30. data/lib/rdf/n3/algebra/math/notLessThan.rb +9 -0
  31. data/lib/rdf/n3/algebra/math/product.rb +9 -0
  32. data/lib/rdf/n3/algebra/math/quotient.rb +9 -0
  33. data/lib/rdf/n3/algebra/math/remainder.rb +9 -0
  34. data/lib/rdf/n3/algebra/math/rounded.rb +9 -0
  35. data/lib/rdf/n3/algebra/math/sum.rb +9 -0
  36. data/lib/rdf/n3/algebra/str/concatenation.rb +9 -0
  37. data/lib/rdf/n3/algebra/str/contains.rb +9 -0
  38. data/lib/rdf/n3/algebra/str/containsIgnoringCase.rb +9 -0
  39. data/lib/rdf/n3/algebra/str/endsWith.rb +9 -0
  40. data/lib/rdf/n3/algebra/str/equalIgnoringCase.rb +9 -0
  41. data/lib/rdf/n3/algebra/str/format.rb +9 -0
  42. data/lib/rdf/n3/algebra/str/greaterThan.rb +9 -0
  43. data/lib/rdf/n3/algebra/str/lessThan.rb +9 -0
  44. data/lib/rdf/n3/algebra/str/matches.rb +9 -0
  45. data/lib/rdf/n3/algebra/str/notEqualIgnoringCase.rb +9 -0
  46. data/lib/rdf/n3/algebra/str/notGreaterThan.rb +9 -0
  47. data/lib/rdf/n3/algebra/str/notLessThan.rb +9 -0
  48. data/lib/rdf/n3/algebra/str/notMatches.rb +9 -0
  49. data/lib/rdf/n3/algebra/str/replace.rb +12 -0
  50. data/lib/rdf/n3/algebra/str/scrape.rb +9 -0
  51. data/lib/rdf/n3/algebra/str/startsWith.rb +56 -0
  52. data/lib/rdf/n3/extensions.rb +79 -0
  53. data/lib/rdf/n3/format.rb +1 -1
  54. data/lib/rdf/n3/reader.rb +181 -116
  55. data/lib/rdf/n3/reader/parser.rb +34 -32
  56. data/lib/rdf/n3/reasoner.rb +293 -0
  57. data/lib/rdf/n3/vocab.rb +8 -3
  58. data/lib/rdf/n3/writer.rb +358 -198
  59. metadata +109 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e1e295c958340c4c0dd8f47583cf716f65d3d2164acdddda485281cb2038c09a
4
- data.tar.gz: eb2280ffe26460e5eb01e3c99cf330a47a2aa565711679f4c7ddbb4fffcc0546
3
+ metadata.gz: c5445c08b901dd936cdad807690c55a4b971fd1bd047b175a9b742fd7ce1bf40
4
+ data.tar.gz: 7fa41d9b4cf5bffe6f0e1820a9759009f7f5d2f97cfc7d8d13748a3b05e775a0
5
5
  SHA512:
6
- metadata.gz: 75ca555fe8e9369e7450fd1631f484ddba0af4ba2d370bfb5710310a1c74636cc78d6f8b64358d5dfd0825707be64b489537d2a6759b91d203e00715bb7b7078
7
- data.tar.gz: 2179ab00eec3d52700a4d03cfc07d63ec54e6ec84b17fe922f280181d95bac402c627bed85abfe1789e35d15e2d707b5fcb871e379fd61199fa07c99d4a1f420
6
+ metadata.gz: fb93395268e948bb947072899d2f492809de4d14ccf1a8a0dc23423fe977b5499f0a9e41aeca3a23f2bbe63e1f99f01d952c5470d72820ef3bc87029c16b0625
7
+ data.tar.gz: 48fb73cf4d731e346a0b700a657f09623723901ab9ec41c96d69cf5f64df45dcb530dbb31ab2477a8525ffe08cfdd25fb07e1fc28ff3bccd5a7df4bdce8ea2e4
data/README.md CHANGED
@@ -1,11 +1,11 @@
1
- # RDF::N3 reader/writer
1
+ # RDF::N3 reader/writer and reasoner
2
2
  Notation-3 reader/writer for [RDF.rb][RDF.rb] .
3
3
 
4
- [![Gem Version](https://badge.fury.io/rb/rdf-n3.png)](http://badge.fury.io/rb/rdf-n3)
5
- [![Build Status](https://travis-ci.org/ruby-rdf/rdf-n3.png?branch=master)](http://travis-ci.org/ruby-rdf/rdf-n3)
4
+ [![Gem Version](https://badge.fury.io/rb/rdf-n3.png)](https://badge.fury.io/rb/rdf-n3)
5
+ [![Build Status](https://travis-ci.org/ruby-rdf/rdf-n3.png?branch=master)](https://travis-ci.org/ruby-rdf/rdf-n3)
6
6
 
7
7
  ## Description
8
- RDF::N3 is an Notation-3 parser for Ruby using the [RDF.rb][RDF.rb] library suite.
8
+ RDF::N3 is an Notation-3 parser for Ruby using the [RDF.rb][RDF.rb] library suite. Also implements N3 Entailment.
9
9
 
10
10
  Reader inspired from TimBL predictiveParser and Python librdf implementation.
11
11
 
@@ -14,14 +14,12 @@ Support for Turtle mime-types and specific format support has been deprecated fr
14
14
  as Turtle is now implemented using [RDF::Turtle][RDF::Turtle].
15
15
 
16
16
  ## Features
17
- RDF::N3 parses [Notation-3][N3], [Turtle][Turtle] and [N-Triples][N-Triples] into statements or triples. It also serializes to Turtle.
17
+ RDF::N3 parses [Notation-3][N3], [Turtle][Turtle] and [N-Triples][N-Triples] into statements or quads. It also performs reasoning and serializes to N3.
18
18
 
19
19
  Install with `gem install rdf-n3`
20
20
 
21
21
  ## Limitations
22
- * Full support of Unicode input requires Ruby version 2.0 or greater.
23
- * Support for Variables in Formulae dependent on underlying repository. Existential variables are quantified to RDF::Node instances, Universals to RDF::Query::Variable, with the URI of the variable target used as the variable name.
24
- * No support for N3 Reification. If there were, it would be through a :reify option to the reader.
22
+ * Support for Variables in Formulae. Existential variables are quantified to RDF::Node instances, Universals to RDF::Query::Variable, with the URI of the variable target used as the variable name.
25
23
 
26
24
  ## Usage
27
25
  Instantiate a reader from a local file:
@@ -40,23 +38,53 @@ Write a graph to a file:
40
38
  writer << graph
41
39
  end
42
40
 
43
- ### Formulae
41
+ ### Reasoning
42
+ Experimental N3 reasoning is supported. Instantiate a reasoner from a dataset:
43
+
44
+ RDF::N3::Reasoner.new do |reasoner|
45
+ RDF::N3::Reader.open("etc/foaf.n3") {|reader| reasoner << reader}
46
+
47
+ reader.each_statement do |statement|
48
+ puts statement.inspect
49
+ end
50
+ end
51
+
52
+ Reasoning is performed by turning a repository containing formula and predicate operators into an executable set of operators (similar to the executable SPARQL Algebra). Reasoning adds statements to the base dataset, marked with `:inferred` (e.g. `statement.inferred?`). Predicate operators are defined from the following vocabularies:
53
+
54
+ * RDF List vocabulary <http://www.w3.org/2000/10/swap/list#>
55
+ * list:append (not implemented yet - See {RDF::N3::Algebra::ListAppend})
56
+ * list:in (not implemented yet - See {RDF::N3::Algebra::ListIn})
57
+ * list:last (not implemented yet - See {RDF::N3::Algebra::ListLast})
58
+ * list:member (not implemented yet - See {RDF::N3::Algebra::ListMember})
59
+ * RDF Log vocabulary <http://www.w3.org/2000/10/swap/log#>
60
+ * log:conclusion (not implemented yet - See {RDF::N3::Algebra::LogConclusion})
61
+ * log:conjunction (not implemented yet - See {RDF::N3::Algebra::LogConjunction})
62
+ * log:equalTo (See {not implemented yet - RDF::N3::Algebra::LogEqualTo})
63
+ * log:implies (See {RDF::N3::Algebra::LogImplies})
64
+ * log:includes (not implemented yet - See {RDF::N3::Algebra::LogIncludes})
65
+ * log:notEqualTo (not implemented yet - See {RDF::N3::Algebra::LogNotEqualTo})
66
+ * log:notIncludes (not implemented yet - See {RDF::N3::Algebra::LogNotIncludes})
67
+ * log:outputString (not implemented yet - See {RDF::N3::Algebra::LogOutputString})
68
+
44
69
  N3 Formulae are introduced with the { statement-list } syntax. A given formula is assigned an RDF::Node instance, which is also used as the graph_name for RDF::Statement instances provided to RDF::N3::Reader#each_statement. For example, the following N3 generates the associated statements:
45
70
 
46
- { [ x:firstname "Ora" ] dc:wrote [ dc:title "Moby Dick" ] } a n3:falsehood .
71
+ @prefix x: <http://example.org/x-ns/#> .
72
+ @prefix log: <http://www.w3.org/2000/10/swap/log#> .
73
+ @prefix dc: <http://purl.org/dc/elements/1.1/#> .
74
+
75
+ { [ x:firstname "Ora" ] dc:wrote [ dc:title "Moby Dick" ] } a log:falsehood .
47
76
 
48
- results in
77
+ when turned into an RDF Repository results in the following quads
78
+
79
+ _:form <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/10/swap/log#falsehood> .
80
+ _:moby <http://purl.org/dc/elements/1.1/#title> "Moby Dick" _:form .
81
+ _:ora <http://purl.org/dc/elements/1.1/#wrote> _:moby _:form .
82
+ _:ora <http://example.org/x-ns/#firstname> "Ora" _:form .
49
83
 
50
- f = RDF::Node.new
51
- s = RDF::Node.new
52
- o = RDF::Node.new
53
- RDF::Statement(f, rdf:type n3:falsehood)
54
- RDF::Statement(s, x:firstname, "Ora", graph_name: f)
55
- RDF::Statement(s, dc:wrote, o, graph_name: f)
56
- RDF::Statement(o, dc:title, "Moby Dick", graph_name: f)
84
+ Reasoning uses a Notation3 Algebra, similar to [SPARQL S-Expressions](). This implementation considers formulae to be patterns, which may be asserted on statements made in the default graph, possibly loaded from a separate file. The logical relationships are reduced to algebraic operators.
57
85
 
58
86
  ### Variables
59
- N3 Variables are introduced with @forAll, @forEach, or ?x. Variables reference URIs described in formulae, typically defined in the default vocabulary (e.g., ":x"). Existential variables are replaced with an allocated RDF::Node instance. Universal variables are replaced with a RDF::Query::Variable instance. For example, the following N3 generates the associated statements:
87
+ N3 Variables are introduced with @forAll, @forSome, or ?x. Variables reference URIs described in formulae, typically defined in the default vocabulary (e.g., ":x"). Existential variables are replaced with an allocated RDF::Node instance. Universal variables are replaced with a RDF::Query::Variable instance. For example, the following N3 generates the associated statements:
60
88
 
61
89
  @forAll <#h>. @forSome <#g>. <#g> <#loves> <#h> .
62
90
 
@@ -66,6 +94,8 @@ results in:
66
94
  g = RDF::Node.new()
67
95
  RDF::Statement(f, <#loves>, h)
68
96
 
97
+ Note that the behavior of both existential and universal variables is not entirely in keeping with the [Team Submission][], and neither work quite like SPARQL variables. When used in the antecedent part of an implication, universal variables should behave much like SPARQL variables. This area is subject to a fair amount of change.
98
+
69
99
  ## Implementation Notes
70
100
  The parser is driven through a rules table contained in lib/rdf/n3/reader/meta.rb. This includes
71
101
  branch rules to indicate productions to be taken based on a current production. Terminals are denoted
@@ -79,48 +109,60 @@ http://www.w3.org/2000/10/swap/grammar/n3.n3 (along with bnf-rules.n3) using cwm
79
109
 
80
110
  [n3-selectors.n3][file:lib/rdf/n3/reader/n3-selectors.rb] is itself used to generate meta.rb using script/build_meta.
81
111
 
82
- ## TODO
83
- * Generate Formulae and solutions using BGP and SPARQL CONSTRUCT mechanisms
84
- * Create equivalent to `--think` to iterate on solutions.
85
-
86
112
  ## Dependencies
87
- * [RDF.rb](http://rubygems.org/gems/rdf) (>= 3.0)
113
+ * [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.0, >= 3.0.10)
88
114
 
89
115
  ## Documentation
90
- Full documentation available on [RubyDoc.info](http://rubydoc.info/github/ruby-rdf/rdf-n3/frames)
116
+ Full documentation available on [RubyDoc.info](https://rubydoc.info/github/ruby-rdf/rdf-n3)
91
117
 
92
118
  ### Principle Classes
93
119
  * {RDF::N3}
94
120
  * {RDF::N3::Format}
95
121
  * {RDF::N3::Reader}
122
+ * {RDF::N3::Reasoner}
96
123
  * {RDF::N3::Writer}
124
+ * {RDF::N3::Algebra}
125
+ * {RDF::N3::Algebra::Formula}
126
+ * {RDF::N3::Algebra::ListAppend}
127
+ * {RDF::N3::Algebra::ListIn}
128
+ * {RDF::N3::Algebra::ListLast}
129
+ * {RDF::N3::Algebra::ListMember}
130
+ * {RDF::N3::Algebra::LogConclusion}
131
+ * {RDF::N3::Algebra::LogConjunction}
132
+ * {RDF::N3::Algebra::LogEqualTo}
133
+ * {RDF::N3::Algebra::LogImplies}
134
+ * {RDF::N3::Algebra::LogIncludes}
135
+ * {RDF::N3::Algebra::LogNotEqualTo}
136
+ * {RDF::N3::Algebra::LogNotIncludes}
137
+ * {RDF::N3::Algebra::LogOutputString}
97
138
 
98
139
  ### Additional vocabularies
99
- * {RDF::LOG}
100
- * {RDF::REI}
101
-
102
- ### Patches
103
- * `Array`
104
- * `RDF::List`
140
+ * {RDF::N3::Log}
141
+ * {RDF::N3::Rei}
142
+ * {RDF::N3::Crypto}
143
+ * {RDF::N3::List}
144
+ * {RDF::N3::Math}
145
+ * {RDF::N3::Str}
146
+ * {RDF::N3::Time}
105
147
 
106
148
  ## Resources
107
149
  * [RDF.rb][RDF.rb]
108
150
  * [Distiller](http://rdf.greggkellogg.net/distiller)
109
- * [Documentation](http://rubydoc.info/github/ruby-rdf/rdf-n3/master/frames)
151
+ * [Documentation](https://rubydoc.info/github/ruby-rdf/rdf-n3/)
110
152
  * [History](file:file.History.html)
111
153
  * [Notation-3][N3]
112
- * [N3 Primer](http://www.w3.org/2000/10/swap/Primer.html)
113
- * [N3 Reification](http://www.w3.org/DesignIssues/Reify.html)
154
+ * [N3 Primer](https://www.w3.org/2000/10/swap/Primer.html)
155
+ * [N3 Reification](https://www.w3.org/DesignIssues/Reify.html)
114
156
  * [Turtle][Turtle]
115
- * [W3C SWAP Test suite](http://www.w3.org/2000/10/swap/test/README.html)
116
- * [W3C Turtle Test suite](http://www.w3.org/2001/sw/DataAccess/df1/tests/README.txt)
157
+ * [W3C SWAP Test suite](https://www.w3.org/2000/10/swap/test/README.html)
158
+ * [W3C Turtle Test suite](https://www.w3.org/2001/sw/DataAccess/df1/tests/README.txt)
117
159
  * [N-Triples][N-Triples]
118
160
 
119
161
  ## Author
120
- * [Gregg Kellogg](http://github.com/gkellogg) - <http://greggkellogg.net/>
162
+ * [Gregg Kellogg](https://github.com/gkellogg) - <https://greggkellogg.net/>
121
163
 
122
164
  ## Contributors
123
- * [Nicholas Humfrey](http://github.com/njh) - <http://njh.me/>
165
+ * [Nicholas Humfrey](https://github.com/njh) - <https://njh.me/>
124
166
 
125
167
  ## Contributing
126
168
  This repository uses [Git Flow](https://github.com/nvie/gitflow) to mange development and release activity. All submissions _must_ be on a feature branch based on the _develop_ branch to ease staging and integration.
@@ -140,19 +182,21 @@ This repository uses [Git Flow](https://github.com/nvie/gitflow) to mange develo
140
182
  ## License
141
183
 
142
184
  This is free and unencumbered public domain software. For more information,
143
- see <http://unlicense.org/> or the accompanying {file:UNLICENSE} file.
185
+ see <https://unlicense.org/> or the accompanying {file:UNLICENSE} file.
144
186
 
145
187
  ## Feedback
146
188
  * <gregg@greggkellogg.net>
147
- * <http://rubygems.org/gem/rdf-n3>
148
- * <http://github.com/ruby-rdf/rdf-n3>
149
- * <http://lists.w3.org/Archives/Public/public-rdf-ruby/>
150
-
151
- [RDF.rb]: http://ruby-rdf.github.com/rdf
152
- [RDF::Turtle]: http://ruby-rdf.github.com/rdf-turtle/
153
- [N3]: http://www.w3.org/DesignIssues/Notation3.html "Notation-3"
154
- [Turtle]: http://www.w3.org/TR/turtle/
155
- [N-Triples]: http://www.w3.org/TR/n-triples/
156
- [YARD]: http://yardoc.org/
157
- [YARD-GS]: http://rubydoc.info/docs/yard/file/docs/GettingStarted.md
158
- [PDD]: http://lists.w3.org/Archives/Public/public-rdf-ruby/2010May/0013.html
189
+ * <https://rubygems.org/gem/rdf-n3>
190
+ * <https://github.com/ruby-rdf/rdf-n3>
191
+ * <https://lists.w3.org/Archives/Public/public-rdf-ruby/>
192
+
193
+ [RDF.rb]: https://ruby-rdf.github.com/rdf
194
+ [RDF::Turtle]: https://ruby-rdf.github.com/rdf-turtle/
195
+ [N3]: https://www.w3.org/DesignIssues/Notation3.html "Notation-3"
196
+ [Team Submission]: https://www.w3.org/TeamSubmission/n3/
197
+ [Turtle]: https://www.w3.org/TR/turtle/
198
+ [N-Triples]: https://www.w3.org/TR/n-triples/
199
+ [YARD]: https://yardoc.org/
200
+ [YARD-GS]: https://rubydoc.info/docs/yard/file/docs/GettingStarted.md
201
+ [PDD]: https://lists.w3.org/Archives/Public/public-rdf-ruby/2010May/0013.html
202
+ [SPARQL S-Expressions]: https://jena.apache.org/documentation/notes/sse.html
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.0.1
1
+ 3.1.0
@@ -16,17 +16,20 @@ module RDF
16
16
  # end
17
17
  #
18
18
  # @see http://www.rubydoc.info/github/ruby-rdf/rdf/
19
- # @see http://www.w3.org/TR/REC-rdf-syntax/
19
+ # @see https://www.w3.org/TR/REC-rdf-syntax/
20
20
  #
21
21
  # @author [Gregg Kellogg](http://greggkellogg.net/)
22
22
  module N3
23
+ require 'rdf/n3/algebra'
23
24
  require 'rdf/n3/format'
24
25
  require 'rdf/n3/vocab'
26
+ require 'rdf/n3/extensions'
25
27
  require 'rdf/n3/patches/array_hacks'
26
- autoload :Meta, 'rdf/n3/reader/meta'
27
- autoload :Parser, 'rdf/n3/reader/parser'
28
- autoload :Reader, 'rdf/n3/reader'
29
- autoload :VERSION, 'rdf/n3/version'
30
- autoload :Writer, 'rdf/n3/writer'
28
+ autoload :Meta, 'rdf/n3/reader/meta'
29
+ autoload :Parser, 'rdf/n3/reader/parser'
30
+ autoload :Reader, 'rdf/n3/reader'
31
+ autoload :Reasoner, 'rdf/n3/reasoner'
32
+ autoload :VERSION, 'rdf/n3/version'
33
+ autoload :Writer, 'rdf/n3/writer'
31
34
  end
32
35
  end
@@ -0,0 +1,125 @@
1
+ $:.unshift(File.expand_path("../..", __FILE__))
2
+ require 'sparql/algebra'
3
+ require 'sxp'
4
+
5
+ module RDF::N3
6
+ # Based on the SPARQL Algebra, operators for executing a patch
7
+ #
8
+ # @author [Gregg Kellogg](http://greggkellogg.net/)
9
+ module Algebra
10
+ autoload :Formula, 'rdf/n3/algebra/formula'
11
+
12
+ module List
13
+ autoload :Append, 'rdf/n3/algebra/list/append'
14
+ autoload :In, 'rdf/n3/algebra/list/in'
15
+ autoload :Last, 'rdf/n3/algebra/list/last'
16
+ autoload :Member, 'rdf/n3/algebra/list/member'
17
+ end
18
+
19
+ module Log
20
+ autoload :Conclusion, 'rdf/n3/algebra/log/conclusion'
21
+ autoload :Conjunction, 'rdf/n3/algebra/log/conjunction'
22
+ autoload :EqualTo, 'rdf/n3/algebra/log/equalTo'
23
+ autoload :Implies, 'rdf/n3/algebra/log/implies'
24
+ autoload :Includes, 'rdf/n3/algebra/log/includes'
25
+ autoload :NotEqualTo, 'rdf/n3/algebra/log/notEqualTo'
26
+ autoload :NotIncludes, 'rdf/n3/algebra/log/notIncludes'
27
+ autoload :OutputString, 'rdf/n3/algebra/log/outputString'
28
+ end
29
+
30
+ module Math
31
+ autoload :AbsoluteValue, 'rdf/n3/algebra/math/absoluteValue'
32
+ autoload :Difference, 'rdf/n3/algebra/math/difference'
33
+ autoload :EqualTo, 'rdf/n3/algebra/math/equalTo'
34
+ autoload :Exponentiation, 'rdf/n3/algebra/math/exponentiation'
35
+ autoload :GreaterThan, 'rdf/n3/algebra/math/greaterThan'
36
+ autoload :IntegerQuotient, 'rdf/n3/algebra/math/integerQuotient'
37
+ autoload :LessThan, 'rdf/n3/algebra/math/lessThan'
38
+ autoload :MemberCount, 'rdf/n3/algebra/math/memberCount'
39
+ autoload :Negation, 'rdf/n3/algebra/math/negation'
40
+ autoload :NotEqualTo, 'rdf/n3/algebra/math/notEqualTo'
41
+ autoload :NotGreaterThan, 'rdf/n3/algebra/math/notGreaterThan'
42
+ autoload :NotLessThan, 'rdf/n3/algebra/math/notLessThan'
43
+ autoload :Product, 'rdf/n3/algebra/math/product'
44
+ autoload :Quotient, 'rdf/n3/algebra/math/quotient'
45
+ autoload :Remainder, 'rdf/n3/algebra/math/remainder'
46
+ autoload :Rounded, 'rdf/n3/algebra/math/rounded'
47
+ autoload :Sum, 'rdf/n3/algebra/math/sum'
48
+ end
49
+
50
+ module Str
51
+ autoload :Concatenation, 'rdf/n3/algebra/str/concatenation'
52
+ autoload :Contains, 'rdf/n3/algebra/str/contains'
53
+ autoload :ContainsIgnoringCase, 'rdf/n3/algebra/str/containsIgnoringCase'
54
+ autoload :EndsWith, 'rdf/n3/algebra/str/endsWith'
55
+ autoload :EqualIgnoringCase, 'rdf/n3/algebra/str/equalIgnoringCase'
56
+ autoload :Format, 'rdf/n3/algebra/str/format'
57
+ autoload :GreaterThan, 'rdf/n3/algebra/str/greaterThan'
58
+ autoload :LessThan, 'rdf/n3/algebra/str/lessThan'
59
+ autoload :Matches, 'rdf/n3/algebra/str/matches'
60
+ autoload :NotEqualIgnoringCase, 'rdf/n3/algebra/str/notEqualIgnoringCase'
61
+ autoload :NotGreaterThan, 'rdf/n3/algebra/str/notGreaterThan'
62
+ autoload :NotLessThan, 'rdf/n3/algebra/str/notLessThan'
63
+ autoload :NotMatches, 'rdf/n3/algebra/str/notMatches'
64
+ autoload :Replace, 'rdf/n3/algebra/str/replace'
65
+ autoload :Scrape, 'rdf/n3/algebra/str/scrape'
66
+ autoload :StartsWith, 'rdf/n3/algebra/str/startsWith'
67
+ end
68
+
69
+ def for(uri)
70
+ {
71
+ RDF::N3::List.append => List::Append,
72
+ RDF::N3::List.in => List::In,
73
+ RDF::N3::List.last => List::Last,
74
+ RDF::N3::List.member => List::Member,
75
+
76
+ RDF::N3::Log.conclusion => Log::Conclusion,
77
+ RDF::N3::Log.conjunction => Log::Conjunction,
78
+ RDF::N3::Log.equalTo => Log::EqualTo,
79
+ RDF::N3::Log.implies => Log::Implies,
80
+ RDF::N3::Log.includes => Log::Includes,
81
+ RDF::N3::Log.notEqualTo => Log::NotEqualTo,
82
+ RDF::N3::Log.notIncludes => Log::NotIncludes,
83
+ RDF::N3::Log.outputString => Log::OutputString,
84
+
85
+ RDF::N3::Math.absoluteValue => Math::AbsoluteValue,
86
+ RDF::N3::Math.difference => Math::Difference,
87
+ RDF::N3::Math.equalTo => Math::EqualTo,
88
+ RDF::N3::Math.exponentiation => Math::Exponentiation,
89
+ RDF::N3::Math.greaterThan => Math::GreaterThan,
90
+ RDF::N3::Math.integerQuotient => Math::IntegerQuotient,
91
+ RDF::N3::Math.lessThan => Math::LessThan,
92
+ RDF::N3::Math.memberCount => Math::MemberCount,
93
+ RDF::N3::Math.negation => Math::Negation,
94
+ RDF::N3::Math.notEqualTo => Math::NotEqualTo,
95
+ RDF::N3::Math.notGreaterThan => Math::NotGreaterThan,
96
+ RDF::N3::Math.notLessThan => Math::NotLessThan,
97
+ RDF::N3::Math.product => Math::Product,
98
+ RDF::N3::Math.quotient => Math::Quotient,
99
+ RDF::N3::Math.remainder => Math::Remainder,
100
+ RDF::N3::Math.rounded => Math::Rounded,
101
+ RDF::N3::Math.sum => Math::Sum,
102
+
103
+ RDF::N3::Str.concatenation => Str::Concatenation,
104
+ RDF::N3::Str.contains => Str::Contains,
105
+ RDF::N3::Str.containsIgnoringCase => Str::ContainsIgnoringCase,
106
+ RDF::N3::Str.endsWith => Str::EndsWith,
107
+ RDF::N3::Str.equalIgnoringCase => Str::EqualIgnoringCase,
108
+ RDF::N3::Str.format => Str::Format,
109
+ RDF::N3::Str.greaterThan => Str::GreaterThan,
110
+ RDF::N3::Str.lessThan => Str::LessThan,
111
+ RDF::N3::Str.matches => Str::Matches,
112
+ RDF::N3::Str.notEqualIgnoringCase => Str::NotEqualIgnoringCase,
113
+ RDF::N3::Str.notGreaterThan => Str::NotGreaterThan,
114
+ RDF::N3::Str.notLessThan => Str::NotLessThan,
115
+ RDF::N3::Str.notMatches => Str::NotMatches,
116
+ RDF::N3::Str.replace => Str::Replace,
117
+ RDF::N3::Str.scrape => Str::Scrape,
118
+ RDF::N3::Str.startsWith => Str::StartsWith,
119
+ }[uri]
120
+ end
121
+ module_function :for
122
+ end
123
+ end
124
+
125
+
@@ -0,0 +1,185 @@
1
+ require 'rdf'
2
+
3
+ module RDF::N3::Algebra
4
+ #
5
+ # A Notation3 Formula combines a graph with a BGP query.
6
+ class Formula < SPARQL::Algebra::Operator
7
+ include SPARQL::Algebra::Query
8
+ include SPARQL::Algebra::Update
9
+ include RDF::Enumerable
10
+ include RDF::Util::Logger
11
+
12
+ attr_accessor :query
13
+
14
+ NAME = [:formula]
15
+
16
+ ##
17
+ # Yields solutions from patterns and other operands. Solutions are created by evaluating each pattern and other sub-operand against `queryable`.
18
+ #
19
+ # When executing, blank nodes are turned into non-distinguished existential variables, noted with `$$`. These variables are removed from the returned solutions, as they can't be bound outside of the formula.
20
+ #
21
+ # @param [RDF::Queryable] queryable
22
+ # the graph or repository to query
23
+ # @param [Hash{Symbol => Object}] options
24
+ # any additional keyword options
25
+ # @option options [RDF::Query::Solutions] solutions
26
+ # optional initial solutions for chained queries
27
+ # @return [RDF::Solutions] distinct solutions
28
+ def execute(queryable, solutions: RDF::Query::Solutions(RDF::Query::Solution.new), **options)
29
+ log_debug {"formula #{graph_name} #{operands.to_sxp}"}
30
+
31
+ # If we were passed solutions in options, extract bindings to use for query
32
+ bindings = solutions.bindings
33
+ log_debug {"(formula bindings) #{bindings.map {|k,v| RDF::Query::Variable.new(k,v)}.to_sxp}"}
34
+
35
+ # Only query as patterns if this is an embedded formula
36
+ @query ||= RDF::Query.new(patterns).optimize!
37
+ @solutions = @query.patterns.empty? ? solutions : queryable.query(@query, solutions: solutions, bindings: bindings, **options)
38
+
39
+ # Merge solution sets
40
+ # Reject solutions which include variables as values
41
+ @solutions = @solutions
42
+ .merge(options[:solutions])
43
+ .filter {|s| s.enum_value.none?(&:variable?)}
44
+
45
+ # Use our solutions for sub-ops
46
+ # Join solutions from other operands
47
+ log_depth do
48
+ sub_ops.each do |op|
49
+ @solutions = op.execute(queryable, solutions: @solutions)
50
+ end
51
+ end
52
+ log_debug {"(formula solutions) #{@solutions.to_sxp}"}
53
+
54
+ # Only return solutions with distinguished variables
55
+ variable_names = @solutions.variable_names.reject {|v| v.to_s.start_with?('$$')}
56
+ variable_names.empty? ? @solutions : @solutions.dup.project(*variable_names)
57
+ end
58
+
59
+ ##
60
+ # Yields each statement from this formula bound to previously determined solutions.
61
+ #
62
+ # @yield [statement]
63
+ # each matching statement
64
+ # @yieldparam [RDF::Statement] solution
65
+ # @yieldreturn [void] ignored
66
+ def each(&block)
67
+ @solutions ||= begin
68
+ # If there are no solutions, create a single solution
69
+ RDF::Query::Solutions(RDF::Query::Solution.new)
70
+ end
71
+ log_debug {"formula #{graph_name} each #{@solutions.to_sxp}"}
72
+
73
+ # Yield constant statements/patterns
74
+ constants.each do |pattern|
75
+ log_debug {"(formula constant) #{pattern.to_sxp}"}
76
+ block.call(RDF::Statement.from(pattern, graph_name: graph_name))
77
+ end
78
+
79
+ # Yield patterns by binding variables
80
+ # FIXME: do we need to do something with non-bound non-distinguished extistential variables?
81
+ @solutions.each do |solution|
82
+ # Bind blank nodes to the solution when it doesn't contain a solution for an existential variable
83
+ existential_vars.each do |var|
84
+ solution[var.name] ||= RDF::Node.intern(var.name.to_s.sub(/^\$+/, ''))
85
+ end
86
+
87
+ log_debug {"(formula apply) #{solution.to_sxp} to BGP"}
88
+ # Yield each variable statement which is constant after applying solution
89
+ patterns.each do |pattern|
90
+ terms = {}
91
+ [:subject, :predicate, :object].each do |r|
92
+ terms[r] = case o = pattern.send(r)
93
+ when RDF::Query::Variable then solution[o]
94
+ else o
95
+ end
96
+ end
97
+
98
+ statement = RDF::Statement.from(terms)
99
+
100
+ # Sanity checking on statement
101
+ if statement.variable? ||
102
+ statement.predicate.literal? ||
103
+ statement.subject.is_a?(SPARQL::Algebra::Operator) ||
104
+ statement.object.is_a?(SPARQL::Algebra::Operator)
105
+ log_debug {"(formula skip) #{statement.to_sxp}"}
106
+ next
107
+ end
108
+
109
+ log_debug {"(formula add) #{statement.to_sxp}"}
110
+ block.call(statement)
111
+ end
112
+ end
113
+
114
+ # statements from sub-operands
115
+ log_depth {sub_ops.each {|op| op.each(&block)}}
116
+ end
117
+
118
+ # Set solutions
119
+ # @param [RDF::Query::Solutions] solutions
120
+ def solutions=(solutions)
121
+ @solutions = solutions
122
+ end
123
+
124
+ # Graph name associated with this formula
125
+ # @return [RDF::Resource]
126
+ def graph_name; @options[:graph_name]; end
127
+
128
+ ##
129
+ # Statements memoizer
130
+ def statements
131
+ # BNodes in statements are non-distinguished existential variables
132
+ @statements ||= operands.
133
+ select {|op| op.is_a?(RDF::Statement)}.
134
+ map do |pattern|
135
+
136
+ # Map nodes to non-distinguished existential variables (except when in top-level formula)
137
+ if graph_name
138
+ terms = {}
139
+ [:subject, :predicate, :object].each do |r|
140
+ terms[r] = case o = pattern.send(r)
141
+ when RDF::Node then RDF::Query::Variable.new(o.id, existential: true, distinguished: false)
142
+ else o
143
+ end
144
+ end
145
+
146
+ RDF::Query::Pattern.from(terms)
147
+ else
148
+ RDF::Query::Pattern.from(pattern)
149
+ end
150
+ end
151
+ end
152
+
153
+ ##
154
+ # Constants memoizer
155
+ def constants
156
+ # BNodes in statements are existential variables
157
+ @constants ||= statements.select(&:constant?)
158
+ end
159
+
160
+ ##
161
+ # Patterns memoizer
162
+ def patterns
163
+ # BNodes in statements are existential variables
164
+ @patterns ||= statements.reject(&:constant?)
165
+ end
166
+
167
+ ##
168
+ # Non-statement operands memoizer
169
+ def sub_ops
170
+ # operands that aren't statements, ordered by their graph_name
171
+ @sub_ops ||= operands.reject {|op| op.is_a?(RDF::Statement)}
172
+ end
173
+
174
+ ##
175
+ # Existential vars in this formula
176
+ def existential_vars
177
+ @existentials ||= patterns.vars.select(&:existential?)
178
+ end
179
+
180
+ def to_sxp_bin
181
+ [:formula, graph_name].compact +
182
+ operands.map(&:to_sxp_bin)
183
+ end
184
+ end
185
+ end