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.
- checksums.yaml +4 -4
- data/README.md +95 -51
- data/VERSION +1 -1
- data/lib/rdf/n3.rb +9 -6
- data/lib/rdf/n3/algebra.rb +125 -0
- data/lib/rdf/n3/algebra/formula.rb +185 -0
- data/lib/rdf/n3/algebra/list/append.rb +13 -0
- data/lib/rdf/n3/algebra/list/in.rb +9 -0
- data/lib/rdf/n3/algebra/list/last.rb +11 -0
- data/lib/rdf/n3/algebra/list/member.rb +7 -0
- data/lib/rdf/n3/algebra/log/conclusion.rb +9 -0
- data/lib/rdf/n3/algebra/log/conjunction.rb +9 -0
- data/lib/rdf/n3/algebra/log/equalTo.rb +7 -0
- data/lib/rdf/n3/algebra/log/implies.rb +77 -0
- data/lib/rdf/n3/algebra/log/includes.rb +13 -0
- data/lib/rdf/n3/algebra/log/notEqualTo.rb +7 -0
- data/lib/rdf/n3/algebra/log/notIncludes.rb +12 -0
- data/lib/rdf/n3/algebra/log/outputString.rb +7 -0
- data/lib/rdf/n3/algebra/math/absoluteValue.rb +9 -0
- data/lib/rdf/n3/algebra/math/difference.rb +9 -0
- data/lib/rdf/n3/algebra/math/equalTo.rb +9 -0
- data/lib/rdf/n3/algebra/math/exponentiation.rb +9 -0
- data/lib/rdf/n3/algebra/math/greaterThan.rb +9 -0
- data/lib/rdf/n3/algebra/math/integerQuotient.rb +9 -0
- data/lib/rdf/n3/algebra/math/lessThan.rb +9 -0
- data/lib/rdf/n3/algebra/math/memberCount.rb +9 -0
- data/lib/rdf/n3/algebra/math/negation.rb +9 -0
- data/lib/rdf/n3/algebra/math/notEqualTo.rb +9 -0
- data/lib/rdf/n3/algebra/math/notGreaterThan.rb +9 -0
- data/lib/rdf/n3/algebra/math/notLessThan.rb +9 -0
- data/lib/rdf/n3/algebra/math/product.rb +9 -0
- data/lib/rdf/n3/algebra/math/quotient.rb +9 -0
- data/lib/rdf/n3/algebra/math/remainder.rb +9 -0
- data/lib/rdf/n3/algebra/math/rounded.rb +9 -0
- data/lib/rdf/n3/algebra/math/sum.rb +9 -0
- data/lib/rdf/n3/algebra/str/concatenation.rb +9 -0
- data/lib/rdf/n3/algebra/str/contains.rb +9 -0
- data/lib/rdf/n3/algebra/str/containsIgnoringCase.rb +9 -0
- data/lib/rdf/n3/algebra/str/endsWith.rb +9 -0
- data/lib/rdf/n3/algebra/str/equalIgnoringCase.rb +9 -0
- data/lib/rdf/n3/algebra/str/format.rb +9 -0
- data/lib/rdf/n3/algebra/str/greaterThan.rb +9 -0
- data/lib/rdf/n3/algebra/str/lessThan.rb +9 -0
- data/lib/rdf/n3/algebra/str/matches.rb +9 -0
- data/lib/rdf/n3/algebra/str/notEqualIgnoringCase.rb +9 -0
- data/lib/rdf/n3/algebra/str/notGreaterThan.rb +9 -0
- data/lib/rdf/n3/algebra/str/notLessThan.rb +9 -0
- data/lib/rdf/n3/algebra/str/notMatches.rb +9 -0
- data/lib/rdf/n3/algebra/str/replace.rb +12 -0
- data/lib/rdf/n3/algebra/str/scrape.rb +9 -0
- data/lib/rdf/n3/algebra/str/startsWith.rb +56 -0
- data/lib/rdf/n3/extensions.rb +79 -0
- data/lib/rdf/n3/format.rb +1 -1
- data/lib/rdf/n3/reader.rb +181 -116
- data/lib/rdf/n3/reader/parser.rb +34 -32
- data/lib/rdf/n3/reasoner.rb +293 -0
- data/lib/rdf/n3/vocab.rb +8 -3
- data/lib/rdf/n3/writer.rb +358 -198
- metadata +109 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5445c08b901dd936cdad807690c55a4b971fd1bd047b175a9b742fd7ce1bf40
|
4
|
+
data.tar.gz: 7fa41d9b4cf5bffe6f0e1820a9759009f7f5d2f97cfc7d8d13748a3b05e775a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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)](
|
5
|
-
[![Build Status](https://travis-ci.org/ruby-rdf/rdf-n3.png?branch=master)](
|
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
|
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
|
-
*
|
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
|
-
###
|
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
|
-
|
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
|
-
|
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, @
|
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](
|
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](
|
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::
|
100
|
-
* {RDF::
|
101
|
-
|
102
|
-
|
103
|
-
*
|
104
|
-
*
|
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](
|
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](
|
113
|
-
* [N3 Reification](
|
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](
|
116
|
-
* [W3C Turtle Test suite](
|
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](
|
162
|
+
* [Gregg Kellogg](https://github.com/gkellogg) - <https://greggkellogg.net/>
|
121
163
|
|
122
164
|
## Contributors
|
123
|
-
* [Nicholas Humfrey](
|
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 <
|
185
|
+
see <https://unlicense.org/> or the accompanying {file:UNLICENSE} file.
|
144
186
|
|
145
187
|
## Feedback
|
146
188
|
* <gregg@greggkellogg.net>
|
147
|
-
* <
|
148
|
-
* <
|
149
|
-
* <
|
150
|
-
|
151
|
-
[RDF.rb]:
|
152
|
-
[RDF::Turtle]:
|
153
|
-
[N3]:
|
154
|
-
[
|
155
|
-
[
|
156
|
-
[
|
157
|
-
[YARD
|
158
|
-
[
|
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
|
+
3.1.0
|
data/lib/rdf/n3.rb
CHANGED
@@ -16,17 +16,20 @@ module RDF
|
|
16
16
|
# end
|
17
17
|
#
|
18
18
|
# @see http://www.rubydoc.info/github/ruby-rdf/rdf/
|
19
|
-
# @see
|
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,
|
27
|
-
autoload :Parser,
|
28
|
-
autoload :Reader,
|
29
|
-
autoload :
|
30
|
-
autoload :
|
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
|