rdf_context 0.4.8 → 0.5.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.
- data/History.txt +27 -0
- data/README.rdoc +22 -9
- data/Rakefile +11 -6
- data/VERSION +1 -1
- data/bin/rdf_context +12 -4
- data/lib/rdf_context.rb +3 -1
- data/lib/rdf_context/aggregate_graph.rb +86 -0
- data/lib/rdf_context/array_hacks.rb +53 -0
- data/lib/rdf_context/conjunctive_graph.rb +1 -1
- data/lib/rdf_context/exceptions.rb +9 -7
- data/lib/rdf_context/graph.rb +174 -15
- data/lib/rdf_context/literal.rb +34 -2
- data/lib/rdf_context/n3_grammar.treetop +213 -129
- data/lib/rdf_context/n3parser.rb +281 -57
- data/lib/rdf_context/namespace.rb +23 -12
- data/lib/rdf_context/parser.rb +4 -3
- data/lib/rdf_context/quoted_graph.rb +38 -0
- data/lib/rdf_context/rdfaparser.rb +2 -1
- data/lib/rdf_context/rdfxmlparser.rb +4 -3
- data/lib/rdf_context/store/abstract_sql_store.rb +4 -4
- data/lib/rdf_context/store/abstract_store.rb +5 -1
- data/lib/rdf_context/store/sqlite3_store.rb +10 -8
- data/lib/rdf_context/string_hacks.rb +44 -21
- data/lib/rdf_context/term_utils.rb +73 -4
- data/lib/rdf_context/triple.rb +32 -47
- data/lib/rdf_context/uriref.rb +33 -26
- data/spec/aggregate_graph_spec.rb +59 -0
- data/spec/conjunctive_graph_spec.rb +1 -1
- data/spec/cwm_spec.rb +32 -0
- data/spec/graph_spec.rb +114 -3
- data/spec/literal_spec.rb +107 -5
- data/spec/matchers.rb +104 -51
- data/spec/n3parser_spec.rb +798 -99
- data/spec/namespaces_spec.rb +26 -0
- data/spec/quoted_graph_spec.rb +0 -0
- data/spec/rdf_helper.rb +197 -0
- data/spec/rdfa_helper.rb +15 -11
- data/spec/rdfa_parser_spec.rb +6 -8
- data/spec/rdfxml_spec.rb +21 -28
- data/spec/spec_helper.rb +20 -0
- data/spec/sqlite3_store_spec.rb +6 -5
- data/spec/store_helper.rb +9 -1
- data/spec/string_hacks_spec.rb +14 -0
- data/spec/{rdfxml_helper.rb → swap_helper.rb} +8 -9
- data/spec/swap_spec.rb +77 -0
- data/spec/swap_test/animal.rdf +17 -0
- data/spec/swap_test/anon-prop.n3 +14 -0
- data/spec/swap_test/anonymous_loop.n3 +2 -0
- data/spec/swap_test/contexts.n3 +16 -0
- data/spec/swap_test/daml-pref.n3 +10 -0
- data/spec/swap_test/i18n/hiragana.n3 +22 -0
- data/spec/swap_test/i18n/n3string.n3 +4 -0
- data/spec/swap_test/list/itemType.rdf +12 -0
- data/spec/swap_test/lists-simple.n3 +40 -0
- data/spec/swap_test/lists.n3 +35 -0
- data/spec/swap_test/n3/n3parser.tests_n3_10001.nt +3 -0
- data/spec/swap_test/n3/n3parser.tests_n3_10002.nt +7 -0
- data/spec/swap_test/n3/n3parser.tests_n3_10003.nt +3 -0
- data/spec/swap_test/n3/n3parser.tests_n3_10004.nt +119 -0
- data/spec/swap_test/n3/n3parser.tests_n3_10005.nt +3 -0
- data/spec/swap_test/n3/n3parser.tests_n3_10006.nt +225 -0
- data/spec/swap_test/n3/n3parser.tests_n3_10007.nt +79 -0
- data/spec/swap_test/n3/n3parser.tests_n3_10008.nt +5 -0
- data/spec/swap_test/n3/n3parser.tests_n3_10009.nt +13 -0
- data/spec/swap_test/n3/n3parser.tests_n3_10010.nt +21 -0
- data/spec/swap_test/n3/n3parser.tests_n3_10011.nt +9 -0
- data/spec/swap_test/n3/n3parser.tests_n3_10012.nt +53 -0
- data/spec/swap_test/n3/n3parser.tests_n3_10013.nt +19 -0
- data/spec/swap_test/n3/n3parser.tests_n3_10014.nt +103 -0
- data/spec/swap_test/n3/n3parser.tests_n3_10015.nt +103 -0
- data/spec/swap_test/n3/n3parser.tests_n3_10016.nt +3 -0
- data/spec/swap_test/n3/n3parser.tests_n3_10017.nt +151 -0
- data/spec/swap_test/n3/n3parser.tests_n3_10018.nt +9 -0
- data/spec/swap_test/n3/n3parser.tests_n3_10019.nt +3 -0
- data/spec/swap_test/n3/n3parser.tests_n3_10020.nt +13 -0
- data/spec/swap_test/n3parser.tests +160 -0
- data/spec/swap_test/nodeID/classes.n3 +9 -0
- data/spec/swap_test/nodeID/classes.ref.rdf +15 -0
- data/spec/swap_test/nodeID/ex1.rdf +15 -0
- data/spec/swap_test/norm/fix.rdf +33 -0
- data/spec/swap_test/owl-ex.rdf +150 -0
- data/spec/swap_test/ref/animal.n3 +11 -0
- data/spec/swap_test/ref/anon-prop-1.n3 +8 -0
- data/spec/swap_test/ref/anonymous_loop.ref +7 -0
- data/spec/swap_test/ref/bnode.n3 +6 -0
- data/spec/swap_test/ref/bnode.rdf +16 -0
- data/spec/swap_test/ref/colon-in-uri.n3 +15 -0
- data/spec/swap_test/ref/daml-ex.n3 +103 -0
- data/spec/swap_test/ref/daml-ont.n3 +289 -0
- data/spec/swap_test/ref/djb1a-out.n3 +4 -0
- data/spec/swap_test/ref/dot-dash.n3 +8 -0
- data/spec/swap_test/ref/in-xml-t.n3 +4 -0
- data/spec/swap_test/ref/itemType.n3 +9 -0
- data/spec/swap_test/ref/keywords1.n3 +11 -0
- data/spec/swap_test/ref/keywords2.n3 +11 -0
- data/spec/swap_test/ref/lists-simple-1.rdf +108 -0
- data/spec/swap_test/ref/lists.n3 +43 -0
- data/spec/swap_test/ref/lstring-out.n3 +20 -0
- data/spec/swap_test/ref/n3string.n3 +13 -0
- data/spec/swap_test/ref/no-last-nl.n3 +3 -0
- data/spec/swap_test/ref/numbers.n3 +18 -0
- data/spec/swap_test/ref/path1.n3 +8 -0
- data/spec/swap_test/ref/path2.n3 +39 -0
- data/spec/swap_test/ref/prefix1.rdf +31 -0
- data/spec/swap_test/ref/prefix3.rdf +31 -0
- data/spec/swap_test/ref/rdf-redefine.rdf +11 -0
- data/spec/swap_test/ref/reluri-1.rdf +18 -0
- data/spec/swap_test/ref/strquot.n3 +23 -0
- data/spec/swap_test/ref/strquot_a.n3 +23 -0
- data/spec/swap_test/ref/xml-base3.n3 +5 -0
- data/spec/swap_test/ref/xml-redefine.rdf +20 -0
- data/spec/swap_test/ref/xml-redefine2.rdf +23 -0
- data/spec/swap_test/ref/xml-syntax-basic-serialization.rdf +10 -0
- data/spec/swap_test/ref/xmllit.nt +3 -0
- data/spec/swap_test/regression.n3 +231 -0
- data/spec/swap_test/reluri-1.n3 +10 -0
- data/spec/swap_test/strquot.n3 +23 -0
- data/spec/swap_test/syntax/colon-in-uri.rdf +27 -0
- data/spec/swap_test/syntax/djb1a.n3 +3 -0
- data/spec/swap_test/syntax/dot-dash.n3 +15 -0
- data/spec/swap_test/syntax/equals1.n3 +1 -0
- data/spec/swap_test/syntax/equals2.n3 +1 -0
- data/spec/swap_test/syntax/keywords1.n3 +17 -0
- data/spec/swap_test/syntax/keywords2.n3 +18 -0
- data/spec/swap_test/syntax/lstring.n3 +26 -0
- data/spec/swap_test/syntax/neg-formula-predicate.n3 +1 -0
- data/spec/swap_test/syntax/neg-keywords3.n3 +1 -0
- data/spec/swap_test/syntax/neg-literal-predicate.n3 +1 -0
- data/spec/swap_test/syntax/neg-single-quote.n3 +1 -0
- data/spec/swap_test/syntax/neg-thisadoc.n3 +1 -0
- data/spec/swap_test/syntax/no-last-nl.n3 +2 -0
- data/spec/swap_test/syntax/numbers.n3 +26 -0
- data/spec/swap_test/syntax/path1.n3 +23 -0
- data/spec/swap_test/syntax/path2.n3 +31 -0
- data/spec/swap_test/syntax/qvars1.n3 +19 -0
- data/spec/swap_test/syntax/qvars2.n3 +19 -0
- data/spec/swap_test/syntax/this-quantifiers.n3 +164 -0
- data/spec/swap_test/syntax/this-rules.n3 +43 -0
- data/spec/swap_test/syntax/too-nested.n3 +25 -0
- data/spec/swap_test/syntax/trailing-semicolon.n3 +12 -0
- data/spec/swap_test/syntax/zero-objects.n3 +1 -0
- data/spec/swap_test/syntax/zero-predicates.n3 +3 -0
- data/spec/swap_test/tests-work.txt +25 -0
- data/spec/swap_test/xml-syntax/basic-serialization.n3 +8 -0
- data/spec/swap_test/xml-syntax/in-xml.xml +13 -0
- data/spec/swap_test/xml-syntax/non-ascii-pred.rdf +14 -0
- data/spec/swap_test/xml-syntax/rdf_prefix.n3 +2 -0
- data/spec/swap_test/xml-syntax/xml_prefix.n3 +7 -0
- data/spec/swap_test/xml-syntax/xml_prefix2.n3 +9 -0
- data/spec/swap_test/xml-syntax/xmlbase3.rdf +10 -0
- data/spec/swap_test/xml-syntax/xmllit.rdf +33 -0
- data/spec/triple_spec.rb +90 -46
- data/spec/turtle/README.txt +20 -0
- data/spec/turtle/bad-00.ttl +2 -0
- data/spec/turtle/bad-01.ttl +3 -0
- data/spec/turtle/bad-02.ttl +3 -0
- data/spec/turtle/bad-03.ttl +3 -0
- data/spec/turtle/bad-04.ttl +3 -0
- data/spec/turtle/bad-05.ttl +4 -0
- data/spec/turtle/bad-06.ttl +3 -0
- data/spec/turtle/bad-07.ttl +4 -0
- data/spec/turtle/bad-08.ttl +2 -0
- data/spec/turtle/bad-09.ttl +3 -0
- data/spec/turtle/bad-10.ttl +3 -0
- data/spec/turtle/bad-11.ttl +3 -0
- data/spec/turtle/bad-12.ttl +3 -0
- data/spec/turtle/bad-13.ttl +3 -0
- data/spec/turtle/bad-14.ttl +6 -0
- data/spec/turtle/manifest-bad.ttl +88 -0
- data/spec/turtle/manifest.ttl +215 -0
- data/spec/turtle/rdf-schema.out +126 -0
- data/spec/turtle/rdf-schema.ttl +156 -0
- data/spec/turtle/rdfq-results.out +36 -0
- data/spec/turtle/rdfq-results.ttl +39 -0
- data/spec/turtle/rdfs-namespace.out +131 -0
- data/spec/turtle/rdfs-namespace.ttl +160 -0
- data/spec/turtle/test-00.out +1 -0
- data/spec/turtle/test-00.ttl +2 -0
- data/spec/turtle/test-01.out +3 -0
- data/spec/turtle/test-01.ttl +7 -0
- data/spec/turtle/test-02.out +3 -0
- data/spec/turtle/test-02.ttl +5 -0
- data/spec/turtle/test-03.out +3 -0
- data/spec/turtle/test-03.ttl +5 -0
- data/spec/turtle/test-04.out +2 -0
- data/spec/turtle/test-04.ttl +4 -0
- data/spec/turtle/test-05.out +4 -0
- data/spec/turtle/test-05.ttl +4 -0
- data/spec/turtle/test-06.out +1 -0
- data/spec/turtle/test-06.ttl +3 -0
- data/spec/turtle/test-07.out +5 -0
- data/spec/turtle/test-07.ttl +3 -0
- data/spec/turtle/test-08.out +1 -0
- data/spec/turtle/test-08.ttl +3 -0
- data/spec/turtle/test-09.out +4 -0
- data/spec/turtle/test-09.ttl +10 -0
- data/spec/turtle/test-10.out +5 -0
- data/spec/turtle/test-10.ttl +5 -0
- data/spec/turtle/test-11.out +4 -0
- data/spec/turtle/test-11.ttl +10 -0
- data/spec/turtle/test-12.out +4 -0
- data/spec/turtle/test-12.ttl +9 -0
- data/spec/turtle/test-13.out +2 -0
- data/spec/turtle/test-13.ttl +7 -0
- data/spec/turtle/test-14.out +10000 -0
- data/spec/turtle/test-14.ttl +10002 -0
- data/spec/turtle/test-15.out +10000 -0
- data/spec/turtle/test-15.ttl +3 -0
- data/spec/turtle/test-16.out +10000 -0
- data/spec/turtle/test-16.ttl +10002 -0
- data/spec/turtle/test-17.out +1 -0
- data/spec/turtle/test-17.ttl +6 -0
- data/spec/turtle/test-18.out +2 -0
- data/spec/turtle/test-18.ttl +9 -0
- data/spec/turtle/test-19.out +1 -0
- data/spec/turtle/test-19.ttl +4 -0
- data/spec/turtle/test-20.out +2 -0
- data/spec/turtle/test-20.ttl +6 -0
- data/spec/turtle/test-21.out +3 -0
- data/spec/turtle/test-21.ttl +4 -0
- data/spec/turtle/test-22.out +3 -0
- data/spec/turtle/test-22.ttl +4 -0
- data/spec/turtle/test-23.out +1 -0
- data/spec/turtle/test-23.ttl +3 -0
- data/spec/turtle/test-24.out +2 -0
- data/spec/turtle/test-24.ttl +3 -0
- data/spec/turtle/test-25.out +7 -0
- data/spec/turtle/test-25.ttl +14 -0
- data/spec/turtle/test-26.out +1 -0
- data/spec/turtle/test-26.ttl +4 -0
- data/spec/turtle/test-27.out +1 -0
- data/spec/turtle/test-27.ttl +5 -0
- data/spec/turtle/test-28-out.ttl +6 -0
- data/spec/turtle/test-28.out +22 -0
- data/spec/turtle/test-28.ttl +22 -0
- data/spec/turtle/test-29.out +1 -0
- data/spec/turtle/test-29.ttl +1 -0
- data/spec/turtle/test-30.out +5 -0
- data/spec/turtle/test-30.ttl +12 -0
- data/spec/turtle_spec.rb +64 -0
- data/spec/uriref_spec.rb +74 -34
- data/test/n3_tests/rdflib/n3-writer-teset-26.n3 +31 -0
- data/test/n3_tests/rdflib/n3-writer-teset-26.nt +14 -0
- data/test/rdf_tests/xml-literal-mixed.nt +1 -2
- metadata +278 -39
- data/lib/rdf_context/n3_grammar.rb +0 -2171
- data/test/perf_test/test.rb +0 -11
- data/test/perf_test/tommorris.rdf +0 -2267
data/History.txt
CHANGED
|
@@ -1,3 +1,30 @@
|
|
|
1
|
+
=== 0.5.0
|
|
2
|
+
* Support for Ruby 1.9, 1.8.7 and 1.8.6.
|
|
3
|
+
* Unicode escapes and URIRefs only work properly in Ruby 1.9
|
|
4
|
+
* Replaced some (&:meth) spells with {|c| c.meth} for Ruby 1.8.6 compatibility
|
|
5
|
+
* Fully compliant N3 parser (n3-rdf level) with extnensive tests, including SWAP, CWM and Turtle test suites.
|
|
6
|
+
* Supports paths, keywords, all semantic expressions.
|
|
7
|
+
* No support yet for Formulae, variables, rules or automatic reification
|
|
8
|
+
* Allow Triple#subject to be like an object, allowing literals and graphs
|
|
9
|
+
* Allow Triple#predicate to be a BNode as well as a URIRef
|
|
10
|
+
* Graph changes
|
|
11
|
+
* Graph#properties(subject) returns properties of a subject expressed as a hash to arrays of objects.
|
|
12
|
+
* Graph#seq(subject) returns ordered rdf:_n objects if subject is a rdf:Seq., or list of rdf:first/rdf:rest
|
|
13
|
+
* Graph#qname(uri) as alternative to uri.qname, has namespaces available.
|
|
14
|
+
* Graph#type_of(subject) array of RDF_TYPE objects.
|
|
15
|
+
* Graph#allow_n3 (getter/setter and option) controls if extra N3 semantics for graphs are allowed. Otherwise, calls Triple#validate_rdf to raise exception
|
|
16
|
+
* Real graph comparisons, including permutation search of triples containing BNodes (obviously, may be expensive)
|
|
17
|
+
* Add QuotedGraph and AggregateGraph
|
|
18
|
+
* Literal changes
|
|
19
|
+
* Literal#== as alias to eql? Needed for sort and uniq.
|
|
20
|
+
* Normalize valid typed literals
|
|
21
|
+
* Added Literal#valid? to perform some content validations.
|
|
22
|
+
* URIRef/Namespace changes
|
|
23
|
+
* Fix URI generation, performing normalizations for normal URI refs, and not for Namespace URIs.
|
|
24
|
+
* Fixed bug in URIRef#namespace & to_qname when namespace does not have a trailing / or #
|
|
25
|
+
* URIRef#short_name may return a different value after a namespace is assigned.
|
|
26
|
+
* Reduce dependency on Redland when running tests
|
|
27
|
+
|
|
1
28
|
=== 0.4.8
|
|
2
29
|
* Add Duration and support in Literal
|
|
3
30
|
* Add datatype support for xs:boolean, xs:double, xs:duration and xs:time.
|
data/README.rdoc
CHANGED
|
@@ -7,7 +7,7 @@ A set of compliant RDF parsers:
|
|
|
7
7
|
* RDF/XML
|
|
8
8
|
* RDFa
|
|
9
9
|
|
|
10
|
-
Multiple
|
|
10
|
+
Multiple data-stores may be attached to a Graph, including Memory, List and SQLite3
|
|
11
11
|
|
|
12
12
|
== DESCRIPTION:
|
|
13
13
|
|
|
@@ -18,7 +18,7 @@ RdfContext parses RDF/XML, RDFa and N3-rdf into a Graph object. It also serializ
|
|
|
18
18
|
|
|
19
19
|
* Fully compliant RDF/XML parser.
|
|
20
20
|
* Fully compliant XHTML/RDFa 1.0 parser.
|
|
21
|
-
* N3-rdf parser
|
|
21
|
+
* Fully compliant N3-rdf parser (N3-rdf level)
|
|
22
22
|
* N-Triples and RDF/XML serializer
|
|
23
23
|
* RDFa tests use SPARQL for most tests due to Rasqal limitations. Other tests compare directly against N-triples.
|
|
24
24
|
* Graph serializes into RDF/XML and N-Triples.
|
|
@@ -49,11 +49,24 @@ Graphs also store namespace associations, and can serialize graphs to RDF/XML or
|
|
|
49
49
|
g.to_rdfxml
|
|
50
50
|
g.to_ntriples
|
|
51
51
|
|
|
52
|
+
Resource properties
|
|
53
|
+
|
|
54
|
+
graph.parse(':foo a :bar; rdfs:label "An example" .', "http://example.com/")
|
|
55
|
+
graph.resources("http://example.com/subject") =>
|
|
56
|
+
{
|
|
57
|
+
"http://www.w3.org/1999/02/22-rdf-syntax-ns#type" => [<http://example.com/#bar>],
|
|
58
|
+
"http://example.com/#label" => ["An example"]
|
|
59
|
+
}
|
|
60
|
+
|
|
52
61
|
Instantiate an existing graph from a datastore
|
|
53
62
|
|
|
54
63
|
s = SQLIte3Store.new(:path => "store.db")
|
|
55
64
|
g = Graph.new(:store => s, :identifier => "http://example.com/context")
|
|
56
65
|
|
|
66
|
+
QuotedGraph implements N3 Formulae semantics, by creating a graph within a store that is formula_aware. QuotedGraph triples are not returned in a query to a ConjunctiveGraph.
|
|
67
|
+
|
|
68
|
+
AggregateGraphs allow multiple graphs from a given context_aware store to be combined into a single read-only graph.
|
|
69
|
+
|
|
57
70
|
=== Parsers
|
|
58
71
|
Instantiate a parser and parse source, specifying type and base-URL
|
|
59
72
|
|
|
@@ -94,14 +107,9 @@ SQLite3Store:: context aware datastore using a SQLite3 database to create a pers
|
|
|
94
107
|
|
|
95
108
|
== TODO:
|
|
96
109
|
* Testing
|
|
97
|
-
* Integrate ntriples tests in spec/ntriples/test.nt
|
|
98
|
-
* Turtle tests from http://www.w3.org/2000/10/swap/test/n3/turtle-manifest.n3 (if can find .ttl and .out files)
|
|
99
|
-
* N3-RDF tests from http://www.w3.org/2000/10/swap/test/n3/n3-rdf.tests
|
|
100
|
-
* N3-Full tests from http://www.w3.org/2000/10/swap/test/n3/n3-full.tests
|
|
101
|
-
* N3 grammar tests?
|
|
102
110
|
* RDFa updates for new tests and non XHTML representations.
|
|
103
111
|
* Graphs
|
|
104
|
-
* n3 serialization
|
|
112
|
+
* n3/turtle serialization
|
|
105
113
|
* Reasoner/inference engine
|
|
106
114
|
* SPARQL
|
|
107
115
|
* RDFS logic and RDF entailment tests
|
|
@@ -109,11 +117,16 @@ SQLite3Store:: context aware datastore using a SQLite3 database to create a pers
|
|
|
109
117
|
* ActiveRDF-like class support
|
|
110
118
|
* Integrate with RDFObjects (http://github.com/rsinger/RDFObjects)
|
|
111
119
|
|
|
120
|
+
== Resources:
|
|
121
|
+
* Distiller[http://kellogg-assoc/distiller]
|
|
122
|
+
* RDoc[http://rdoc.info/projects/gkellogg/rdf_context]
|
|
123
|
+
* History[http://github.com/gkellogg/rdf_context/blob/master/History.txt]
|
|
124
|
+
|
|
112
125
|
== LICENSE:
|
|
113
126
|
|
|
114
127
|
(The MIT License)
|
|
115
128
|
|
|
116
|
-
Copyright (c) 2009 Gregg Kellogg
|
|
129
|
+
Copyright (c) 2009-2010 Gregg Kellogg
|
|
117
130
|
|
|
118
131
|
Copyright (c) 2008 Tom Morris and contributors
|
|
119
132
|
|
data/Rakefile
CHANGED
|
@@ -50,28 +50,33 @@ Spec::Rake::SpecTask.new(:spec) do |spec|
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
desc "Run specs through RCov"
|
|
53
|
-
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
|
53
|
+
Spec::Rake::SpecTask.new("spec:rcov") do |spec|
|
|
54
54
|
spec.libs << 'lib' << 'spec'
|
|
55
55
|
spec.pattern = 'spec/*_spec.rb'
|
|
56
56
|
spec.rcov = true
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
+
desc "Generate HTML report specs"
|
|
60
|
+
Spec::Rake::SpecTask.new("doc:spec") do |spec|
|
|
61
|
+
spec.libs << 'lib' << 'spec'
|
|
62
|
+
spec.spec_files = FileList['spec/*_spec.rb']
|
|
63
|
+
spec.spec_opts = ["--format", "html:doc/spec.html"]
|
|
64
|
+
end
|
|
65
|
+
|
|
59
66
|
task :spec => :check_dependencies
|
|
60
67
|
|
|
61
68
|
task :default => :spec
|
|
62
69
|
|
|
63
70
|
require 'rake/rdoctask'
|
|
64
|
-
Rake::RDocTask.new do |rdoc|
|
|
71
|
+
Rake::RDocTask.new("doc:rdoc") do |rdoc|
|
|
65
72
|
if File.exist?('VERSION')
|
|
66
73
|
version = File.read('VERSION')
|
|
67
74
|
else
|
|
68
|
-
version =
|
|
75
|
+
version = RdfContext::VERSION
|
|
69
76
|
end
|
|
70
77
|
|
|
71
|
-
rdoc.rdoc_dir = 'rdoc'
|
|
78
|
+
rdoc.rdoc_dir = 'doc/rdoc'
|
|
72
79
|
rdoc.title = "rdf_context #{version}"
|
|
73
80
|
rdoc.rdoc_files.include('README*', "History.txt")
|
|
74
81
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
75
82
|
end
|
|
76
|
-
|
|
77
|
-
# vim: syntax=Ruby
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.5.0
|
data/bin/rdf_context
CHANGED
|
@@ -9,7 +9,7 @@ class Parse
|
|
|
9
9
|
graph_opts = {:identifier => base_uri}
|
|
10
10
|
graph_opts[:store] = store if store
|
|
11
11
|
parser = Parser.new(:graph => Graph.new(graph_opts))
|
|
12
|
-
parser.parse(File.
|
|
12
|
+
parser.parse(file.respond_to?(:read) ? file : File.open(file), base_uri, :strict => true)
|
|
13
13
|
output = case $format
|
|
14
14
|
when "xml"
|
|
15
15
|
parser.graph.to_rdfxml
|
|
@@ -30,9 +30,12 @@ class Parse
|
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
+
mode = ARGV.shift
|
|
34
|
+
raise "Mode must be one of 'parse'" unless mode == "parse"
|
|
35
|
+
|
|
33
36
|
$verbose = false
|
|
34
37
|
base_uri = "http://example.com"
|
|
35
|
-
store
|
|
38
|
+
store = :list_store
|
|
36
39
|
opts = GetoptLong.new(
|
|
37
40
|
["--verbose", GetoptLong::NO_ARGUMENT],
|
|
38
41
|
["--quiet", GetoptLong::NO_ARGUMENT],
|
|
@@ -62,7 +65,12 @@ opts.each do |opt, arg|
|
|
|
62
65
|
end
|
|
63
66
|
|
|
64
67
|
x = Parse.new
|
|
65
|
-
ARGV.
|
|
66
|
-
|
|
68
|
+
if ARGV.empty?
|
|
69
|
+
s = $stdin.read
|
|
70
|
+
x.parse(StringIO.new(s), base_uri, store)
|
|
71
|
+
else
|
|
72
|
+
ARGV.each do |test_file|
|
|
73
|
+
x.parse(test_file, base_uri, store)
|
|
74
|
+
end
|
|
67
75
|
end
|
|
68
76
|
|
data/lib/rdf_context.rb
CHANGED
|
@@ -43,7 +43,7 @@ module RdfContext
|
|
|
43
43
|
| \\\\u[0-9a-fA-F]
|
|
44
44
|
)
|
|
45
45
|
( [0-9a-zA-Z_\.-]
|
|
46
|
-
| \\\\u([0-9a-fA-F]{4})
|
|
46
|
+
| \\\\u([0-9a-fA-F]{4})
|
|
47
47
|
)*
|
|
48
48
|
$},
|
|
49
49
|
Regexp::EXTENDED)
|
|
@@ -51,6 +51,8 @@ module RdfContext
|
|
|
51
51
|
RDF_TYPE = URIRef.new("http://www.w3.org/1999/02/22-rdf-syntax-ns#type")
|
|
52
52
|
XML_LITERAL = Literal::Encoding.xmlliteral
|
|
53
53
|
|
|
54
|
+
OWL_NS = Namespace.new("http://www.w3.org/2002/07/owl#", "owl")
|
|
55
|
+
LOG_NS = Namespace.new("http://www.w3.org/2000/10/swap/log#", "log")
|
|
54
56
|
RDF_NS = Namespace.new("http://www.w3.org/1999/02/22-rdf-syntax-ns#", "rdf")
|
|
55
57
|
RDFS_NS = Namespace.new("http://www.w3.org/2000/01/rdf-schema#", "rdfs")
|
|
56
58
|
XHV_NS = Namespace.new("http://www.w3.org/1999/xhtml/vocab#", "xhv")
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), "graph")
|
|
2
|
+
|
|
3
|
+
module RdfContext
|
|
4
|
+
# AggregateGraph - A read-only graph composed of multiple other graphs.
|
|
5
|
+
#
|
|
6
|
+
# Essentially a ConjunctiveGraph over an explicit subset of the entire store.
|
|
7
|
+
class AggregateGraph < Graph
|
|
8
|
+
attr_reader :graphs
|
|
9
|
+
|
|
10
|
+
# List of graphs to aggregate
|
|
11
|
+
def initialize(*graph)
|
|
12
|
+
@graphs = graph
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def destroy(configuration = nil); raise ReadOnlyGraphException; end
|
|
16
|
+
def commit; raise ReadOnlyGraphException; end
|
|
17
|
+
def rollback; raise ReadOnlyGraphException; end
|
|
18
|
+
def add; raise ReadOnlyGraphException; end
|
|
19
|
+
def remove; raise ReadOnlyGraphException; end
|
|
20
|
+
def bind(namespace); raise ReadOnlyGraphException; end
|
|
21
|
+
def parse(stream, uri, options = {}); raise ReadOnlyGraphException; end
|
|
22
|
+
def n3; raise ReadOnlyGraphException; end
|
|
23
|
+
|
|
24
|
+
# Open the graphs
|
|
25
|
+
def open(configuration = {})
|
|
26
|
+
@graphs.each {|g| g.open(configuration)}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Close the graphs
|
|
30
|
+
def close(configuration = {})
|
|
31
|
+
@graphs.each {|g| g.close(configuration)}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Number of Triples in the graph
|
|
35
|
+
def size
|
|
36
|
+
@graphs.inject(0) {|memo, g| memo += g.size}
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# List of distinct subjects in graph
|
|
40
|
+
def subjects
|
|
41
|
+
@graphs.inject([]) {|memo, g| memo += g.subjects}
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# List of distinct predicates in graph
|
|
45
|
+
def predicates
|
|
46
|
+
@graphs.inject([]) {|memo, g| memo += g.predicates}
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# List of distinct objects in graph
|
|
50
|
+
def objects
|
|
51
|
+
@graphs.inject([]) {|memo, g| memo += g.objects}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Triples from graph, optionally matching subject, predicate, or object.
|
|
55
|
+
# Delegates to Store#triples.
|
|
56
|
+
#
|
|
57
|
+
# @param [Triple, nil] triple:: Triple to match, may be a pattern triple or nil
|
|
58
|
+
# @return [Array]:: List of matched triples
|
|
59
|
+
def triples(triple = Triple.new(nil, nil, nil), &block) # :yields: triple, context
|
|
60
|
+
@graphs.inject([]) {|memo, g| memo += g.triples(triple, &block)}
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Check to see if this graph contains the specified triple
|
|
64
|
+
def contains?(triple)
|
|
65
|
+
@graphs.any? {|g| g.contains?(triple) }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Get all BNodes with usage count used within graph
|
|
69
|
+
def bnodes
|
|
70
|
+
@graphs.inject([]) {|memo, g| memo += g.bnodes}
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Only compares to another AggregateGraph. Compares each sub-graph
|
|
74
|
+
def eql?(other)
|
|
75
|
+
other.is_a?(AggregateGraph) ? super : false
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def nsbinding
|
|
79
|
+
@graphs.inject({}) {|memo, g| memo.merge(g.nsbinding)}
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def uri_binding
|
|
83
|
+
@graphs.inject({}) {|memo, g| memo.merge(g.uri_binding)}
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
class Array
|
|
2
|
+
# http://wiki.rubygarden.org/Ruby/page/show/ArrayPermute
|
|
3
|
+
# Permute an array, and call a block for each permutation
|
|
4
|
+
# Author: Paul Battley
|
|
5
|
+
def permute(prefixed=[])
|
|
6
|
+
if (length < 2)
|
|
7
|
+
# there are no elements left to permute
|
|
8
|
+
yield(prefixed + self)
|
|
9
|
+
else
|
|
10
|
+
# recursively permute the remaining elements
|
|
11
|
+
each_with_index do |e, i|
|
|
12
|
+
(self[0,i]+self[(i+1)..-1]).permute(prefixed+[e]) { |a| yield a }
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Converts the array to a comma-separated sentence where the last element is joined by the connector word. Options:
|
|
18
|
+
# * <tt>:words_connector</tt> - The sign or word used to join the elements in arrays with two or more elements (default: ", ")
|
|
19
|
+
# * <tt>:two_words_connector</tt> - The sign or word used to join the elements in arrays with two elements (default: " and ")
|
|
20
|
+
# * <tt>:last_word_connector</tt> - The sign or word used to join the last element in arrays with three or more elements (default: ", and ")
|
|
21
|
+
def to_sentence(options = {})
|
|
22
|
+
default_words_connector = ", "
|
|
23
|
+
default_two_words_connector = " and "
|
|
24
|
+
default_last_word_connector = ", and "
|
|
25
|
+
|
|
26
|
+
# Try to emulate to_senteces previous to 2.3
|
|
27
|
+
if options.has_key?(:connector) || options.has_key?(:skip_last_comma)
|
|
28
|
+
::ActiveSupport::Deprecation.warn(":connector has been deprecated. Use :words_connector instead", caller) if options.has_key? :connector
|
|
29
|
+
::ActiveSupport::Deprecation.warn(":skip_last_comma has been deprecated. Use :last_word_connector instead", caller) if options.has_key? :skip_last_comma
|
|
30
|
+
|
|
31
|
+
skip_last_comma = options.delete :skip_last_comma
|
|
32
|
+
if connector = options.delete(:connector)
|
|
33
|
+
options[:last_word_connector] ||= skip_last_comma ? connector : ", #{connector}"
|
|
34
|
+
else
|
|
35
|
+
options[:last_word_connector] ||= skip_last_comma ? default_two_words_connector : default_last_word_connector
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale)
|
|
40
|
+
options = {:words_connector => default_words_connector, :two_words_connector => default_two_words_connector, :last_word_connector => default_last_word_connector}.merge(options)
|
|
41
|
+
|
|
42
|
+
case length
|
|
43
|
+
when 0
|
|
44
|
+
""
|
|
45
|
+
when 1
|
|
46
|
+
self[0].to_s
|
|
47
|
+
when 2
|
|
48
|
+
"#{self[0]}#{options[:two_words_connector]}#{self[1]}"
|
|
49
|
+
else
|
|
50
|
+
"#{self[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{self[-1]}"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -36,7 +36,7 @@ module RdfContext
|
|
|
36
36
|
# Triples across all contexts in store, optionally matching subject, predicate, or object.
|
|
37
37
|
# Delegates to Store#triples.
|
|
38
38
|
#
|
|
39
|
-
# @param [Triple, nil] triple:: Triple to match, may be a
|
|
39
|
+
# @param [Triple, nil] triple:: Triple to match, may be a pattern triple or nil
|
|
40
40
|
# @return [Array]:: List of matched triples
|
|
41
41
|
def triples(triple = Triple.new(nil, nil, nil), &block) # :yields: triple, context
|
|
42
42
|
@store.triples(triple, nil, &block) || []
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
module RdfContext
|
|
2
|
-
class RdfException
|
|
2
|
+
class RdfException < RuntimeError; end
|
|
3
|
+
|
|
3
4
|
class ParserException < RdfException; end
|
|
4
|
-
class GraphException
|
|
5
|
-
class StoreException
|
|
6
|
-
class BNodeException
|
|
7
|
-
class TypeError
|
|
5
|
+
class GraphException < RdfException; end
|
|
6
|
+
class StoreException < RdfException; end
|
|
7
|
+
class BNodeException < RdfException; end
|
|
8
|
+
class TypeError < RdfException; end
|
|
9
|
+
class InvalidNode < RdfException; end
|
|
8
10
|
class InvalidPredicate < RdfException; end
|
|
9
|
-
|
|
10
|
-
class
|
|
11
|
+
|
|
12
|
+
class ReadOnlyGraphException < GraphException; end
|
|
11
13
|
end
|
data/lib/rdf_context/graph.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'namespace')
|
|
2
2
|
require File.join(File.dirname(__FILE__), 'triple')
|
|
3
|
+
require File.join(File.dirname(__FILE__), 'array_hacks')
|
|
3
4
|
require File.join(File.dirname(__FILE__), 'store', 'list_store')
|
|
4
5
|
require File.join(File.dirname(__FILE__), 'store', 'memory_store')
|
|
5
6
|
|
|
@@ -12,6 +13,7 @@ module RdfContext
|
|
|
12
13
|
attr_reader :nsbinding
|
|
13
14
|
attr_reader :identifier
|
|
14
15
|
attr_reader :store
|
|
16
|
+
attr_accessor :allow_n3
|
|
15
17
|
|
|
16
18
|
# Create a Graph with the given store and identifier.
|
|
17
19
|
#
|
|
@@ -30,6 +32,7 @@ module RdfContext
|
|
|
30
32
|
# @param [Hash] options:: Options
|
|
31
33
|
# <em>options[:store]</em>:: storage, defaults to a new ListStore instance. May be symbol :list_store or :memory_store
|
|
32
34
|
# <em>options[:identifier]</em>:: Identifier for this graph, BNode or URIRef
|
|
35
|
+
# <em>options[:allow_n3]</em>:: Allow N3-specific triples: Literals as subject, BNodes as predicate
|
|
33
36
|
def initialize(options = {})
|
|
34
37
|
@nsbinding = {}
|
|
35
38
|
|
|
@@ -41,7 +44,9 @@ module RdfContext
|
|
|
41
44
|
else ListStore.new
|
|
42
45
|
end
|
|
43
46
|
|
|
44
|
-
@
|
|
47
|
+
@allow_n3 = options[:allow_n3]
|
|
48
|
+
|
|
49
|
+
@identifier = Triple.coerce_node(options[:identifier]) || BNode.new
|
|
45
50
|
end
|
|
46
51
|
|
|
47
52
|
def inspect
|
|
@@ -53,7 +58,7 @@ module RdfContext
|
|
|
53
58
|
[self.class.to_s, self.identifier].hash
|
|
54
59
|
end
|
|
55
60
|
|
|
56
|
-
def context_aware?; @context_aware
|
|
61
|
+
def context_aware?; @store.context_aware?; end
|
|
57
62
|
|
|
58
63
|
# Data Store interface
|
|
59
64
|
def nsbinding; @store.nsbinding; end
|
|
@@ -136,7 +141,8 @@ module RdfContext
|
|
|
136
141
|
# Add bindings for predicates not already having bindings
|
|
137
142
|
tmp_ns = "ns0"
|
|
138
143
|
predicates.each do |p|
|
|
139
|
-
unless
|
|
144
|
+
raise "Attempt to serialize graph containing non-strict RDF compiant BNode as predicate" unless p.is_a?(URIRef)
|
|
145
|
+
if !p.namespace(uri_bindings)
|
|
140
146
|
uri_bindings[p.base] = Namespace.new(p.base, tmp_ns)
|
|
141
147
|
rdf_attrs["xmlns:#{tmp_ns}"] = p.base
|
|
142
148
|
tmp_ns = tmp_ns.succ
|
|
@@ -188,6 +194,11 @@ module RdfContext
|
|
|
188
194
|
# Hash of uri => Namespace bindings
|
|
189
195
|
def uri_binding; @store.uri_binding; end
|
|
190
196
|
|
|
197
|
+
# QName for a URI
|
|
198
|
+
def qname(uri)
|
|
199
|
+
uri.to_qname(self.uri_binding)
|
|
200
|
+
end
|
|
201
|
+
|
|
191
202
|
# Namespace for prefix
|
|
192
203
|
def namespace(prefix); @store.namespace(prefix); end
|
|
193
204
|
|
|
@@ -235,6 +246,7 @@ module RdfContext
|
|
|
235
246
|
# @param [Triple] t:: the triple to be added to the graph
|
|
236
247
|
# @return [Graph]:: Returns the graph
|
|
237
248
|
def << (triple)
|
|
249
|
+
triple.validate_rdf unless @allow_n3 # Only add triples if n3-mode is set
|
|
238
250
|
@store.add(triple, self)
|
|
239
251
|
self
|
|
240
252
|
end
|
|
@@ -254,7 +266,10 @@ module RdfContext
|
|
|
254
266
|
def add(*triples)
|
|
255
267
|
options = triples.last.is_a?(Hash) ? triples.pop : {}
|
|
256
268
|
ctx = options[:context] || @default_context || self
|
|
257
|
-
triples.each
|
|
269
|
+
triples.each do |t|
|
|
270
|
+
t.validate_rdf unless @allow_n3 # Only add triples if n3-mode is set
|
|
271
|
+
@store.add(t, ctx)
|
|
272
|
+
end
|
|
258
273
|
self
|
|
259
274
|
end
|
|
260
275
|
|
|
@@ -265,19 +280,73 @@ module RdfContext
|
|
|
265
280
|
# Triples from graph, optionally matching subject, predicate, or object.
|
|
266
281
|
# Delegates to Store#triples.
|
|
267
282
|
#
|
|
268
|
-
# @param [Triple, nil] triple:: Triple to match, may be a
|
|
283
|
+
# @param [Triple, nil] triple:: Triple to match, may be a pattern triple or nil
|
|
269
284
|
# @return [Array]:: List of matched triples
|
|
270
285
|
def triples(triple = Triple.new(nil, nil, nil), &block) # :yields: triple, context
|
|
271
286
|
@store.triples(triple, self, &block) || []
|
|
272
287
|
end
|
|
273
288
|
alias_method :find, :triples
|
|
289
|
+
|
|
290
|
+
# Returns ordered rdf:_n objects or rdf:first, rdf:rest for a given subject
|
|
291
|
+
def seq(subject)
|
|
292
|
+
props = properties(subject)
|
|
293
|
+
rdf_type = props[RDF_TYPE.to_s] || []
|
|
294
|
+
|
|
295
|
+
if rdf_type.include?(RDF_NS.Seq)
|
|
296
|
+
props.keys.select {|k| k.match(/#{RDF_NS.uri}_(\d)$/)}.
|
|
297
|
+
sort_by {|i| i.sub(RDF_NS._.to_s, "").to_i}.
|
|
298
|
+
map {|key| props[key]}.
|
|
299
|
+
flatten
|
|
300
|
+
elsif self.triples(Triple.new(subject, RDF_NS.first, nil))
|
|
301
|
+
# N3-style first/rest chain
|
|
302
|
+
list = []
|
|
303
|
+
while subject != RDF_NS.nil
|
|
304
|
+
props = properties(subject)
|
|
305
|
+
list += props[RDF_NS.first.to_s]
|
|
306
|
+
subject = props[RDF_NS.rest.to_s].first
|
|
307
|
+
end
|
|
308
|
+
list
|
|
309
|
+
else
|
|
310
|
+
[]
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
# Resource properties
|
|
315
|
+
#
|
|
316
|
+
# Properties arranged as a hash with the predicate Term as index to an array of resources or literals
|
|
317
|
+
#
|
|
318
|
+
# Example:
|
|
319
|
+
# graph.parse(':foo a :bar; rdfs:label "An example" .', "http://example.com/")
|
|
320
|
+
# graph.resources("http://example.com/subject") =>
|
|
321
|
+
# {
|
|
322
|
+
# "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" => [<http://example.com/#bar>],
|
|
323
|
+
# "http://example.com/#label" => ["An example"]
|
|
324
|
+
# }
|
|
325
|
+
def properties(subject)
|
|
326
|
+
@properties ||= {}
|
|
327
|
+
@properties[subject.to_s] ||= begin
|
|
328
|
+
hash = Hash.new
|
|
329
|
+
self.triples(Triple.new(subject, nil, nil)).map do |t, ctx|
|
|
330
|
+
pred = t.predicate.to_s
|
|
331
|
+
|
|
332
|
+
hash[pred] ||= []
|
|
333
|
+
hash[pred] << t.object
|
|
334
|
+
end
|
|
335
|
+
hash
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
# Return an n3 identifier for the Graph
|
|
340
|
+
def n3
|
|
341
|
+
"[#{self.identifier.to_n3}]"
|
|
342
|
+
end
|
|
274
343
|
|
|
275
344
|
# Detect the presence of a BNode in the graph, either as a subject or an object
|
|
276
345
|
#
|
|
277
346
|
# @param [BNode] bn:: BNode to find
|
|
278
347
|
#
|
|
279
348
|
def has_bnode_identifier?(bn)
|
|
280
|
-
triples do |triple, context|
|
|
349
|
+
self.triples do |triple, context|
|
|
281
350
|
return true if triple.subject.eql?(bn) || triple.object.eql?(bn)
|
|
282
351
|
end
|
|
283
352
|
false
|
|
@@ -300,6 +369,11 @@ module RdfContext
|
|
|
300
369
|
triples(Triple.new(nil, RDF_TYPE, object)).map {|t, ctx| t.subject}
|
|
301
370
|
end
|
|
302
371
|
|
|
372
|
+
# Get type(s) of subject, returns a list of symbols
|
|
373
|
+
def type_of(subject)
|
|
374
|
+
triples(Triple.new(subject, RDF_TYPE, nil)).map {|t, ctx| t.object}
|
|
375
|
+
end
|
|
376
|
+
|
|
303
377
|
# Merge a graph into this graph
|
|
304
378
|
def merge!(graph)
|
|
305
379
|
raise GraphException.new("merge without a graph") unless graph.is_a?(Graph)
|
|
@@ -310,9 +384,10 @@ module RdfContext
|
|
|
310
384
|
|
|
311
385
|
graph.triples do |triple, context|
|
|
312
386
|
# If triple contains bnodes, remap to new values
|
|
313
|
-
if triple.subject.is_a?(BNode) || triple.object.is_a?(BNode)
|
|
387
|
+
if triple.subject.is_a?(BNode) || triple.predicate.is_a?(BNode) || triple.object.is_a?(BNode)
|
|
314
388
|
triple = triple.clone
|
|
315
389
|
triple.subject = bn[triple.subject] if triple.subject.is_a?(BNode)
|
|
390
|
+
triple.predicate = bn[triple.predicate] if triple.predicate.is_a?(BNode)
|
|
316
391
|
triple.object = bn[triple.object] if triple.object.is_a?(BNode)
|
|
317
392
|
end
|
|
318
393
|
self << triple
|
|
@@ -326,26 +401,53 @@ module RdfContext
|
|
|
326
401
|
#
|
|
327
402
|
# We just follow Python RDFlib's lead and do a simple comparison
|
|
328
403
|
def eql?(other)
|
|
329
|
-
|
|
404
|
+
puts "eql? size #{self.size} vs #{other.size}" if $DEBUG
|
|
330
405
|
return false if !other.is_a?(Graph) || self.size != other.size
|
|
331
|
-
return false unless other.identifier.to_s == identifier.to_s
|
|
406
|
+
return false unless other.identifier.to_s == identifier.to_s unless other.identifier.is_a?(BNode) && identifier.is_a?(BNode)
|
|
332
407
|
|
|
333
408
|
bn_self = bnodes.values.sort
|
|
334
409
|
bn_other = other.bnodes.values.sort
|
|
335
|
-
|
|
410
|
+
puts "eql? bnodes '#{bn_self.to_sentence}' vs '#{bn_other.to_sentence}'" if $DEBUG
|
|
336
411
|
return false unless bn_self == bn_other
|
|
337
412
|
|
|
338
413
|
# Check each triple to see if it's contained in the other graph
|
|
339
414
|
triples do |t, ctx|
|
|
340
|
-
next if t.subject.is_a?(BNode) || t.object.is_a?(BNode)
|
|
341
|
-
|
|
415
|
+
next if t.subject.is_a?(BNode) || t.predicate.is_a?(BNode) || t.object.is_a?(BNode)
|
|
416
|
+
puts "eql? contains '#{t.to_ntriples}: #{other.contains?(t)}'" if $DEBUG
|
|
342
417
|
return false unless other.contains?(t)
|
|
343
418
|
end
|
|
344
|
-
|
|
419
|
+
|
|
420
|
+
# For each BNode, check permutations of similar bnodes in other graph
|
|
421
|
+
bnode_permutations(bnodes, other.bnodes) do |bn_map|
|
|
422
|
+
puts "bnode permutations: #{bn_map.inspect}" if $DEBUG
|
|
423
|
+
# bn_map contains 1-1 mapping of bnodes from self to other
|
|
424
|
+
catch :next_perm do
|
|
425
|
+
triples do |t, ctx|
|
|
426
|
+
next unless t.subject.is_a?(BNode) || t.predicate.is_a?(BNode) || t.object.is_a?(BNode)
|
|
427
|
+
subject, predicate, object = t.subject, t.predicate, t.object
|
|
428
|
+
subject = bn_map[subject] if bn_map.has_key?(subject)
|
|
429
|
+
predicate = bn_map[predicate] if bn_map.has_key?(predicate)
|
|
430
|
+
object = bn_map[object] if bn_map.has_key?(object)
|
|
431
|
+
tn = Triple.new(subject, predicate, object)
|
|
432
|
+
puts " eql? contains '#{tn.inspect}': #{other.contains?(tn)}" if $DEBUG
|
|
433
|
+
next if other.contains?(tn)
|
|
434
|
+
|
|
435
|
+
puts " no, next permutation" if $DEBUG
|
|
436
|
+
# Not a match, try next permutation
|
|
437
|
+
throw :next_perm
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
# If we matched all triples in the graph using this permutation, we're done
|
|
441
|
+
return true
|
|
442
|
+
end
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
# Exhausted all permutations, unless there were no bnodes
|
|
446
|
+
bn_self.length == 0
|
|
345
447
|
end
|
|
346
448
|
|
|
347
449
|
alias_method :==, :eql?
|
|
348
|
-
|
|
450
|
+
|
|
349
451
|
# Parse source into Graph.
|
|
350
452
|
#
|
|
351
453
|
# Merges results into a common Graph
|
|
@@ -356,9 +458,66 @@ module RdfContext
|
|
|
356
458
|
# <em>options[:debug]</em>:: Array to place debug messages
|
|
357
459
|
# <em>options[:type]</em>:: One of _rdfxml_, _html_, or _n3_
|
|
358
460
|
# <em>options[:strict]</em>:: Raise Error if true, continue with lax parsing, otherwise
|
|
461
|
+
# <em>options[:allow_n3]</em>:: Allow N3-specific triples: Literals as subject, BNodes as predicate
|
|
359
462
|
# @return [Graph]:: Returns the graph containing parsed triples
|
|
360
|
-
def parse(stream, uri, options = {}, &block) # :yields: triple
|
|
463
|
+
def parse(stream, uri = nil, options = {}, &block) # :yields: triple
|
|
464
|
+
@allow_n3 ||= options[:allow_n3]
|
|
361
465
|
Parser.parse(stream, uri, options.merge(:graph => self), &block)
|
|
362
466
|
end
|
|
363
467
|
end
|
|
468
|
+
|
|
469
|
+
protected
|
|
470
|
+
|
|
471
|
+
# Permutations of two BNode lists
|
|
472
|
+
#
|
|
473
|
+
# Take source keys and run permutations mapping to other keys, if the permutation
|
|
474
|
+
# maps to the same counts for each
|
|
475
|
+
def bnode_permutations(bn_source, bn_other)
|
|
476
|
+
puts "compare #{bn_source.inspect}\n with #{bn_other.inspect}" if $DEBUG
|
|
477
|
+
|
|
478
|
+
source_keys = bn_source.keys
|
|
479
|
+
other_keys = bn_other.keys
|
|
480
|
+
values = bn_source.values.uniq
|
|
481
|
+
|
|
482
|
+
# Break key lists into groups based on sharing equivalent usage counts
|
|
483
|
+
case values.length
|
|
484
|
+
when 0
|
|
485
|
+
{}
|
|
486
|
+
when 1
|
|
487
|
+
# All keys have equivalent counts, yield permutations
|
|
488
|
+
if source_keys.length == 1
|
|
489
|
+
puts "yield #{{source_keys.first => other_keys.first}.inspect}" if $DEBUG
|
|
490
|
+
yield({source_keys.first => other_keys.first})
|
|
491
|
+
else
|
|
492
|
+
(0..(source_keys.length-1)).to_a.permute do |indicies|
|
|
493
|
+
puts "indicies #{indicies.inspect}" if $DEBUG
|
|
494
|
+
ok = other_keys.dup
|
|
495
|
+
map = indicies.inject({}) { |hash, i| hash[source_keys[i]] = ok.shift; hash}
|
|
496
|
+
puts "yield #{map.inspect}" if $DEBUG
|
|
497
|
+
yield(map)
|
|
498
|
+
end
|
|
499
|
+
end
|
|
500
|
+
else
|
|
501
|
+
# Break bnodes into 2 arrays sharing a common usage count and permute each separately
|
|
502
|
+
max = values.max
|
|
503
|
+
bn_source_min = bn_source.clone
|
|
504
|
+
bn_other_min = bn_other.clone
|
|
505
|
+
bn_source_max = {}
|
|
506
|
+
bn_other_max = {}
|
|
507
|
+
bn_source.each_pair do |bn, v|
|
|
508
|
+
bn_source_max[bn] = bn_source_min.delete(bn) if v == max
|
|
509
|
+
end
|
|
510
|
+
bn_other.each_pair do |bn, v|
|
|
511
|
+
bn_other_max[bn] = bn_other_min.delete(bn) if v == max
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
puts "yield permutations of multiple with max #{bn_source_max.inspect}\n and #{bn_other_max.inspect}" if $DEBUG
|
|
515
|
+
# Yield for each permutation of max joined with permutations of min
|
|
516
|
+
bnode_permutations(bn_source_max, bn_other_max) do |bn_perm_max|
|
|
517
|
+
bnode_permutations(bn_source_min, bn_other_min) do |bn_perm_min|
|
|
518
|
+
yield bn_perm_max.merge(bn_perm_min)
|
|
519
|
+
end
|
|
520
|
+
end
|
|
521
|
+
end
|
|
522
|
+
end
|
|
364
523
|
end
|