rdf-n3 3.1.1 → 3.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +148 -69
- data/UNLICENSE +1 -1
- data/VERSION +1 -1
- data/lib/rdf/n3.rb +8 -8
- data/lib/rdf/n3/algebra.rb +147 -68
- data/lib/rdf/n3/algebra/builtin.rb +79 -0
- data/lib/rdf/n3/algebra/formula.rb +355 -94
- data/lib/rdf/n3/algebra/list/append.rb +33 -4
- data/lib/rdf/n3/algebra/list/first.rb +24 -0
- data/lib/rdf/n3/algebra/list/in.rb +42 -3
- data/lib/rdf/n3/algebra/list/last.rb +17 -4
- data/lib/rdf/n3/algebra/list/length.rb +24 -0
- data/lib/rdf/n3/algebra/list/member.rb +39 -2
- data/lib/rdf/n3/algebra/list_operator.rb +83 -0
- data/lib/rdf/n3/algebra/log/conclusion.rb +57 -1
- data/lib/rdf/n3/algebra/log/conjunction.rb +28 -1
- data/lib/rdf/n3/algebra/log/content.rb +34 -0
- data/lib/rdf/n3/algebra/log/equal_to.rb +34 -0
- data/lib/rdf/n3/algebra/log/implies.rb +55 -30
- data/lib/rdf/n3/algebra/log/includes.rb +58 -1
- data/lib/rdf/n3/algebra/log/n3_string.rb +34 -0
- data/lib/rdf/n3/algebra/log/not_equal_to.rb +23 -0
- data/lib/rdf/n3/algebra/log/not_includes.rb +27 -0
- data/lib/rdf/n3/algebra/log/output_string.rb +40 -0
- data/lib/rdf/n3/algebra/log/parsed_as_n3.rb +36 -0
- data/lib/rdf/n3/algebra/log/semantics.rb +40 -0
- data/lib/rdf/n3/algebra/math/absolute_value.rb +36 -0
- data/lib/rdf/n3/algebra/math/acos.rb +26 -0
- data/lib/rdf/n3/algebra/math/acosh.rb +26 -0
- data/lib/rdf/n3/algebra/math/asin.rb +26 -0
- data/lib/rdf/n3/algebra/math/asinh.rb +26 -0
- data/lib/rdf/n3/algebra/math/atan.rb +26 -0
- data/lib/rdf/n3/algebra/math/atanh.rb +26 -0
- data/lib/rdf/n3/algebra/math/ceiling.rb +28 -0
- data/lib/rdf/n3/algebra/math/cos.rb +40 -0
- data/lib/rdf/n3/algebra/math/cosh.rb +38 -0
- data/lib/rdf/n3/algebra/math/difference.rb +34 -3
- data/lib/rdf/n3/algebra/math/equal_to.rb +54 -0
- data/lib/rdf/n3/algebra/math/exponentiation.rb +29 -3
- data/lib/rdf/n3/algebra/math/floor.rb +28 -0
- data/lib/rdf/n3/algebra/math/greater_than.rb +41 -0
- data/lib/rdf/n3/algebra/math/less_than.rb +41 -0
- data/lib/rdf/n3/algebra/math/negation.rb +31 -2
- data/lib/rdf/n3/algebra/math/not_equal_to.rb +25 -0
- data/lib/rdf/n3/algebra/math/not_greater_than.rb +25 -0
- data/lib/rdf/n3/algebra/math/not_less_than.rb +25 -0
- data/lib/rdf/n3/algebra/math/product.rb +14 -3
- data/lib/rdf/n3/algebra/math/quotient.rb +30 -3
- data/lib/rdf/n3/algebra/math/remainder.rb +29 -3
- data/lib/rdf/n3/algebra/math/rounded.rb +20 -3
- data/lib/rdf/n3/algebra/math/sin.rb +40 -0
- data/lib/rdf/n3/algebra/math/sinh.rb +38 -0
- data/lib/rdf/n3/algebra/math/sum.rb +35 -4
- data/lib/rdf/n3/algebra/math/tan.rb +40 -0
- data/lib/rdf/n3/algebra/math/tanh.rb +38 -0
- data/lib/rdf/n3/algebra/not_implemented.rb +13 -0
- data/lib/rdf/n3/algebra/resource_operator.rb +123 -0
- data/lib/rdf/n3/algebra/str/concatenation.rb +21 -3
- data/lib/rdf/n3/algebra/str/contains.rb +28 -4
- data/lib/rdf/n3/algebra/str/contains_ignoring_case.rb +33 -0
- data/lib/rdf/n3/algebra/str/ends_with.rb +33 -0
- data/lib/rdf/n3/algebra/str/equal_ignoring_case.rb +34 -0
- data/lib/rdf/n3/algebra/str/format.rb +12 -4
- data/lib/rdf/n3/algebra/str/greater_than.rb +38 -0
- data/lib/rdf/n3/algebra/str/less_than.rb +33 -0
- data/lib/rdf/n3/algebra/str/matches.rb +33 -5
- data/lib/rdf/n3/algebra/str/not_equal_ignoring_case.rb +17 -0
- data/lib/rdf/n3/algebra/str/not_greater_than.rb +17 -0
- data/lib/rdf/n3/algebra/str/not_less_than.rb +17 -0
- data/lib/rdf/n3/algebra/str/not_matches.rb +18 -0
- data/lib/rdf/n3/algebra/str/replace.rb +28 -5
- data/lib/rdf/n3/algebra/str/scrape.rb +31 -5
- data/lib/rdf/n3/algebra/str/starts_with.rb +33 -0
- data/lib/rdf/n3/algebra/time/day.rb +35 -0
- data/lib/rdf/n3/algebra/time/day_of_week.rb +27 -0
- data/lib/rdf/n3/algebra/time/gm_time.rb +29 -0
- data/lib/rdf/n3/algebra/time/hour.rb +35 -0
- data/lib/rdf/n3/algebra/time/in_seconds.rb +59 -0
- data/lib/rdf/n3/algebra/time/local_time.rb +29 -0
- data/lib/rdf/n3/algebra/time/minute.rb +35 -0
- data/lib/rdf/n3/algebra/time/month.rb +35 -0
- data/lib/rdf/n3/algebra/time/second.rb +35 -0
- data/lib/rdf/n3/algebra/time/timezone.rb +36 -0
- data/lib/rdf/n3/algebra/time/year.rb +29 -0
- data/lib/rdf/n3/extensions.rb +180 -21
- data/lib/rdf/n3/format.rb +65 -0
- data/lib/rdf/n3/list.rb +630 -0
- data/lib/rdf/n3/reader.rb +762 -485
- data/lib/rdf/n3/reasoner.rb +57 -68
- data/lib/rdf/n3/refinements.rb +178 -0
- data/lib/rdf/n3/repository.rb +332 -0
- data/lib/rdf/n3/terminals.rb +80 -0
- data/lib/rdf/n3/vocab.rb +35 -7
- data/lib/rdf/n3/writer.rb +208 -148
- metadata +110 -52
- data/AUTHORS +0 -1
- data/History.markdown +0 -99
- data/lib/rdf/n3/algebra/log/equalTo.rb +0 -7
- data/lib/rdf/n3/algebra/log/notEqualTo.rb +0 -7
- data/lib/rdf/n3/algebra/log/notIncludes.rb +0 -12
- data/lib/rdf/n3/algebra/log/outputString.rb +0 -7
- data/lib/rdf/n3/algebra/math/absoluteValue.rb +0 -9
- data/lib/rdf/n3/algebra/math/equalTo.rb +0 -9
- data/lib/rdf/n3/algebra/math/greaterThan.rb +0 -9
- data/lib/rdf/n3/algebra/math/integerQuotient.rb +0 -9
- data/lib/rdf/n3/algebra/math/lessThan.rb +0 -9
- data/lib/rdf/n3/algebra/math/memberCount.rb +0 -9
- data/lib/rdf/n3/algebra/math/notEqualTo.rb +0 -9
- data/lib/rdf/n3/algebra/math/notGreaterThan.rb +0 -9
- data/lib/rdf/n3/algebra/math/notLessThan.rb +0 -9
- data/lib/rdf/n3/algebra/str/containsIgnoringCase.rb +0 -9
- data/lib/rdf/n3/algebra/str/endsWith.rb +0 -9
- data/lib/rdf/n3/algebra/str/equalIgnoringCase.rb +0 -9
- data/lib/rdf/n3/algebra/str/greaterThan.rb +0 -9
- data/lib/rdf/n3/algebra/str/lessThan.rb +0 -9
- data/lib/rdf/n3/algebra/str/notEqualIgnoringCase.rb +0 -9
- data/lib/rdf/n3/algebra/str/notGreaterThan.rb +0 -9
- data/lib/rdf/n3/algebra/str/notLessThan.rb +0 -9
- data/lib/rdf/n3/algebra/str/notMatches.rb +0 -9
- data/lib/rdf/n3/algebra/str/startsWith.rb +0 -56
- data/lib/rdf/n3/patches/array_hacks.rb +0 -53
- data/lib/rdf/n3/reader/meta.rb +0 -641
- data/lib/rdf/n3/reader/parser.rb +0 -239
@@ -0,0 +1,80 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module RDF::N3
|
3
|
+
module Terminals
|
4
|
+
# Definitions of token regular expressions used for lexical analysis
|
5
|
+
##
|
6
|
+
# Unicode regular expressions for Ruby 1.9+ with the Oniguruma engine.
|
7
|
+
U_CHARS1 = Regexp.compile(<<-EOS.gsub(/\s+/, ''))
|
8
|
+
[\\u00C0-\\u00D6]|[\\u00D8-\\u00F6]|[\\u00F8-\\u02FF]|
|
9
|
+
[\\u0370-\\u037D]|[\\u037F-\\u1FFF]|[\\u200C-\\u200D]|
|
10
|
+
[\\u2070-\\u218F]|[\\u2C00-\\u2FEF]|[\\u3001-\\uD7FF]|
|
11
|
+
[\\uF900-\\uFDCF]|[\\uFDF0-\\uFFFD]|[\\u{10000}-\\u{EFFFF}]
|
12
|
+
EOS
|
13
|
+
U_CHARS2 = Regexp.compile("\\u00B7|[\\u0300-\\u036F]|[\\u203F-\\u2040]", Regexp::FIXEDENCODING).freeze
|
14
|
+
IRI_RANGE = Regexp.compile("[[^<>\"{}|^`\\\\]&&[^\\x00-\\x20]]", Regexp::FIXEDENCODING).freeze
|
15
|
+
|
16
|
+
ESCAPE_CHAR4 = /\\u(?:[0-9A-Fa-f]{4,4})/u.freeze # \uXXXX
|
17
|
+
ESCAPE_CHAR8 = /\\U(?:[0-9A-Fa-f]{8,8})/u.freeze # \UXXXXXXXX
|
18
|
+
UCHAR = /#{ESCAPE_CHAR4}|#{ESCAPE_CHAR8}/n.freeze
|
19
|
+
# 170s
|
20
|
+
PERCENT = /%[0-9A-Fa-f]{2}/u.freeze
|
21
|
+
# 172s
|
22
|
+
PN_LOCAL_ESC = /\\[_~\.\-\!$\&'\(\)\*\+,;=\/\?\#@%]/u.freeze
|
23
|
+
# 169s
|
24
|
+
PLX = /#{PERCENT}|#{PN_LOCAL_ESC}/u.freeze
|
25
|
+
# 163s
|
26
|
+
PN_CHARS_BASE = /[A-Z]|[a-z]|#{U_CHARS1}/u.freeze
|
27
|
+
# 164s
|
28
|
+
PN_CHARS_U = /_|#{PN_CHARS_BASE}/u.freeze
|
29
|
+
# 166s
|
30
|
+
PN_CHARS = /-|[0-9]|#{PN_CHARS_U}|#{U_CHARS2}/u.freeze
|
31
|
+
PN_LOCAL_BODY = /(?:(?:\.|:|#{PN_CHARS}|#{PLX})*(?:#{PN_CHARS}|:|#{PLX}))?/u.freeze
|
32
|
+
PN_CHARS_BODY = /(?:(?:\.|#{PN_CHARS})*#{PN_CHARS})?/u.freeze
|
33
|
+
# 167s
|
34
|
+
PN_PREFIX = /#{PN_CHARS_BASE}#{PN_CHARS_BODY}/u.freeze
|
35
|
+
# 168s
|
36
|
+
PN_LOCAL = /(?:[0-9]|:|#{PN_CHARS_U}|#{PLX})#{PN_LOCAL_BODY}/u.freeze
|
37
|
+
# 154s
|
38
|
+
EXPONENT = /[eE][+-]?[0-9]+/u.freeze
|
39
|
+
# 159s
|
40
|
+
ECHAR = /\\[tbnrf\\"']/u.freeze
|
41
|
+
# 18
|
42
|
+
IRIREF = /<(?:#{IRI_RANGE}|#{UCHAR})*>/mu.freeze
|
43
|
+
# 139s
|
44
|
+
PNAME_NS = /#{PN_PREFIX}?:/u.freeze
|
45
|
+
# 140s
|
46
|
+
PNAME_LN = /#{PNAME_NS}#{PN_LOCAL}/u.freeze
|
47
|
+
# 141s
|
48
|
+
BLANK_NODE_LABEL = /_:(?:[0-9]|#{PN_CHARS_U})(?:(?:#{PN_CHARS}|\.)*#{PN_CHARS})?/u.freeze
|
49
|
+
# 144s
|
50
|
+
# XXX: negative-lookahed for @is and @has
|
51
|
+
LANGTAG = /@(?!(?:is|has))(?:[a-zA-Z]+(?:-[a-zA-Z0-9]+)*)/u.freeze
|
52
|
+
# 19
|
53
|
+
INTEGER = /[+-]?[0-9]+/u.freeze
|
54
|
+
# 20
|
55
|
+
DECIMAL = /[+-]?(?:[0-9]*\.[0-9]+)/u.freeze
|
56
|
+
# 21
|
57
|
+
DOUBLE = /[+-]?(?:[0-9]+\.[0-9]*#{EXPONENT}|\.?[0-9]+#{EXPONENT})/u.freeze
|
58
|
+
# 22
|
59
|
+
STRING_LITERAL_SINGLE_QUOTE = /'(?:[^\'\\\n\r]|#{ECHAR}|#{UCHAR})*'/u.freeze
|
60
|
+
# 23
|
61
|
+
STRING_LITERAL_QUOTE = /"(?:[^\"\\\n\r]|#{ECHAR}|#{UCHAR})*"/u.freeze
|
62
|
+
# 24
|
63
|
+
STRING_LITERAL_LONG_SINGLE_QUOTE = /'''(?:(?:'|'')?(?:[^'\\]|#{ECHAR}|#{UCHAR}))*'''/um.freeze
|
64
|
+
# 25
|
65
|
+
STRING_LITERAL_LONG_QUOTE = /"""(?:(?:"|"")?(?:[^"\\]|#{ECHAR}|#{UCHAR}))*"""/um.freeze
|
66
|
+
|
67
|
+
# 28t
|
68
|
+
PREFIX = /@?prefix/ui.freeze
|
69
|
+
# 29t
|
70
|
+
BASE = /@?base/ui.freeze
|
71
|
+
QUICK_VAR_NAME = /\?#{PN_LOCAL}/.freeze
|
72
|
+
|
73
|
+
# 161s
|
74
|
+
WS = /(?:\s|(?:#[^\n\r]*))+/um.freeze
|
75
|
+
# 162s
|
76
|
+
ANON = /\[\s*\]/u.freeze
|
77
|
+
|
78
|
+
FORALL = /@forAll/u.freeze
|
79
|
+
end
|
80
|
+
end
|
data/lib/rdf/n3/vocab.rb
CHANGED
@@ -1,9 +1,37 @@
|
|
1
1
|
module RDF::N3
|
2
|
-
|
3
|
-
|
4
|
-
class
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
2
|
+
# @!parse
|
3
|
+
# # Crypto namespace
|
4
|
+
# class Crypto < RDF::Vocabulary; end
|
5
|
+
const_set("Crypto", Class.new(RDF::Vocabulary("http://www.w3.org/2000/10/swap/crypto#")))
|
6
|
+
RDF::Vocabulary.register(:crypto, Crypto)
|
7
|
+
|
8
|
+
# @!parse
|
9
|
+
# # Log namespace
|
10
|
+
# class Log < RDF::Vocabulary; end
|
11
|
+
const_set("Log", Class.new(RDF::Vocabulary("http://www.w3.org/2000/10/swap/log#")))
|
12
|
+
RDF::Vocabulary.register(:log, Log)
|
13
|
+
|
14
|
+
# @!parse
|
15
|
+
# # Math namespace
|
16
|
+
# class Math < RDF::Vocabulary; end
|
17
|
+
const_set("Math", Class.new(RDF::Vocabulary("http://www.w3.org/2000/10/swap/math#")))
|
18
|
+
RDF::Vocabulary.register(:math, Math)
|
19
|
+
|
20
|
+
# @!parse
|
21
|
+
# # Rei namespace
|
22
|
+
# class Rei < RDF::Vocabulary; end
|
23
|
+
const_set("Rei", Class.new(RDF::Vocabulary("http://www.w3.org/2000/10/swap/reify#")))
|
24
|
+
RDF::Vocabulary.register(:rei, Rei)
|
25
|
+
|
26
|
+
# @!parse
|
27
|
+
# # Str namespace
|
28
|
+
# class Str < RDF::Vocabulary; end
|
29
|
+
const_set("Str", Class.new(RDF::Vocabulary("http://www.w3.org/2000/10/swap/string#")))
|
30
|
+
RDF::Vocabulary.register(:string, Str)
|
31
|
+
|
32
|
+
# @!parse
|
33
|
+
# # Time namespace
|
34
|
+
# class Time < RDF::Vocabulary; end
|
35
|
+
const_set("Time", Class.new(RDF::Vocabulary("http://www.w3.org/2000/10/swap/time#")))
|
36
|
+
RDF::Vocabulary.register(:time, Time)
|
9
37
|
end
|
data/lib/rdf/n3/writer.rb
CHANGED
@@ -49,7 +49,8 @@ module RDF::N3
|
|
49
49
|
class Writer < RDF::Writer
|
50
50
|
format RDF::N3::Format
|
51
51
|
include RDF::Util::Logger
|
52
|
-
|
52
|
+
include Terminals
|
53
|
+
using Refinements
|
53
54
|
|
54
55
|
# @return [RDF::Repository] Repository of statements serialized
|
55
56
|
attr_accessor :repo
|
@@ -57,6 +58,9 @@ module RDF::N3
|
|
57
58
|
# @return [RDF::Graph] Graph being serialized
|
58
59
|
attr_accessor :graph
|
59
60
|
|
61
|
+
# @return [Array<RDF::Node>] formulae names
|
62
|
+
attr_accessor :formula_names
|
63
|
+
|
60
64
|
##
|
61
65
|
# N3 Writer options
|
62
66
|
# @see http://www.rubydoc.info/github/ruby-rdf/rdf/RDF/Writer#options-class_method
|
@@ -104,10 +108,13 @@ module RDF::N3
|
|
104
108
|
# @yield [writer]
|
105
109
|
# @yieldparam [RDF::Writer] writer
|
106
110
|
def initialize(output = $stdout, **options, &block)
|
107
|
-
@repo = RDF::Repository.new
|
111
|
+
@repo = RDF::N3::Repository.new
|
108
112
|
@uri_to_pname = {}
|
109
113
|
@uri_to_prefix = {}
|
110
114
|
super do
|
115
|
+
if base_uri
|
116
|
+
@uri_to_prefix[base_uri.to_s.end_with?('#', '/') ? base_uri : RDF::URI("#{base_uri}#")] = nil
|
117
|
+
end
|
111
118
|
reset
|
112
119
|
if block_given?
|
113
120
|
case block.arity
|
@@ -152,12 +159,14 @@ module RDF::N3
|
|
152
159
|
|
153
160
|
self.reset
|
154
161
|
|
155
|
-
log_debug
|
162
|
+
log_debug("\nserialize: repo:") {repo.size}
|
156
163
|
|
157
164
|
preprocess
|
158
165
|
|
159
166
|
start_document
|
160
167
|
|
168
|
+
@formula_names = repo.graph_names(unique: true)
|
169
|
+
|
161
170
|
with_graph(nil) do
|
162
171
|
count = 0
|
163
172
|
order_subjects.each do |subject|
|
@@ -168,10 +177,13 @@ module RDF::N3
|
|
168
177
|
end
|
169
178
|
|
170
179
|
# Output any formulae not already serialized using owl:sameAs
|
171
|
-
|
180
|
+
formula_names.each do |graph_name|
|
172
181
|
next if graph_done?(graph_name)
|
173
182
|
|
174
|
-
|
183
|
+
# Add graph_name to @formulae
|
184
|
+
@formulae[graph_name] = true
|
185
|
+
|
186
|
+
log_debug {"formula(#{graph_name})"}
|
175
187
|
@output.write("\n#{indent}")
|
176
188
|
p_term(graph_name, :subject)
|
177
189
|
@output.write(" ")
|
@@ -200,7 +212,7 @@ module RDF::N3
|
|
200
212
|
|
201
213
|
#log_debug {"get_pname(#{resource}), std?}"}
|
202
214
|
pname = case
|
203
|
-
when @uri_to_pname.
|
215
|
+
when @uri_to_pname.key?(uri)
|
204
216
|
return @uri_to_pname[uri]
|
205
217
|
when u = @uri_to_prefix.keys.detect {|u| uri.index(u.to_s) == 0}
|
206
218
|
# Use a defined prefix
|
@@ -222,34 +234,31 @@ module RDF::N3
|
|
222
234
|
|
223
235
|
# Make sure pname is a valid pname
|
224
236
|
if pname
|
225
|
-
md =
|
237
|
+
md = PNAME_LN.match(pname) || PNAME_NS.match(pname)
|
226
238
|
pname = nil unless md.to_s.length == pname.length
|
227
239
|
end
|
228
240
|
|
229
241
|
@uri_to_pname[uri] = pname
|
230
|
-
rescue Addressable::URI::InvalidURIError => e
|
231
|
-
raise RDF::WriterError, "Invalid URI #{resource.inspect}: #{e.message}"
|
232
242
|
end
|
233
243
|
|
234
244
|
# Take a hash from predicate uris to lists of values.
|
235
245
|
# Sort the lists of values. Return a sorted list of properties.
|
236
|
-
# @param [Hash{
|
237
|
-
# @return [Array<
|
246
|
+
# @param [Hash{RDF::Term => Array<RDF::Term>}] properties A hash of Property to Resource mappings
|
247
|
+
# @return [Array<RDF::Term>}] Ordered list of properties. Uses predicate_order.
|
238
248
|
def sort_properties(properties)
|
239
249
|
# Make sorted list of properties
|
240
250
|
prop_list = []
|
241
251
|
|
242
252
|
predicate_order.each do |prop|
|
243
|
-
next unless properties
|
244
|
-
prop_list << prop
|
253
|
+
next unless properties.key?(prop)
|
254
|
+
prop_list << prop
|
245
255
|
end
|
246
256
|
|
247
257
|
properties.keys.sort.each do |prop|
|
248
|
-
next if prop_list.include?(prop
|
249
|
-
prop_list << prop
|
258
|
+
next if prop_list.include?(prop)
|
259
|
+
prop_list << prop
|
250
260
|
end
|
251
261
|
|
252
|
-
log_debug {"sort_properties: #{prop_list.join(', ')}"}
|
253
262
|
prop_list
|
254
263
|
end
|
255
264
|
|
@@ -267,7 +276,11 @@ module RDF::N3
|
|
267
276
|
when RDF::XSD.boolean, RDF::XSD.integer, RDF::XSD.decimal
|
268
277
|
literal.canonicalize.to_s
|
269
278
|
when RDF::XSD.double
|
270
|
-
literal.
|
279
|
+
if literal.nan? || literal.infinite?
|
280
|
+
quoted(literal.value) + "^^#{format_uri(literal.datatype)}"
|
281
|
+
else
|
282
|
+
literal.canonicalize.to_s
|
283
|
+
end
|
271
284
|
else
|
272
285
|
text = quoted(literal.value)
|
273
286
|
text << "@#{literal.language}" if literal.has_language?
|
@@ -286,8 +299,8 @@ module RDF::N3
|
|
286
299
|
# @param [Hash{Symbol => Object}] options
|
287
300
|
# @return [String]
|
288
301
|
def format_uri(uri, **options)
|
289
|
-
md = uri.relativize(base_uri)
|
290
|
-
log_debug("relativize") {"#{uri.to_sxp} =>
|
302
|
+
md = uri == base_uri ? '' : uri.relativize(base_uri)
|
303
|
+
log_debug("relativize") {"#{uri.to_sxp} => <#{md.inspect}>"} if md != uri.to_s
|
291
304
|
md != uri.to_s ? "<#{md}>" : (get_pname(uri) || "<#{uri}>")
|
292
305
|
end
|
293
306
|
|
@@ -298,7 +311,15 @@ module RDF::N3
|
|
298
311
|
# @param [Hash{Symbol => Object}] options
|
299
312
|
# @return [String]
|
300
313
|
def format_node(node, **options)
|
301
|
-
|
314
|
+
if node.id.match(/^([^_]+)_[^_]+_([^_]+)$/)
|
315
|
+
sn, seq = $1, $2.to_i
|
316
|
+
seq = nil if seq == 0
|
317
|
+
"_:#{sn}#{seq}"
|
318
|
+
elsif options[:unique_bnodes]
|
319
|
+
node.to_unique_base
|
320
|
+
else
|
321
|
+
node.to_base
|
322
|
+
end
|
302
323
|
end
|
303
324
|
|
304
325
|
protected
|
@@ -306,20 +327,21 @@ module RDF::N3
|
|
306
327
|
def start_document
|
307
328
|
@output.write("@base <#{base_uri}> .\n") unless base_uri.to_s.empty?
|
308
329
|
|
309
|
-
log_debug
|
330
|
+
log_debug("start_document: prefixes") { prefixes.inspect}
|
310
331
|
prefixes.keys.sort_by(&:to_s).each do |prefix|
|
311
332
|
@output.write("@prefix #{prefix}: <#{prefixes[prefix]}> .\n")
|
312
333
|
end
|
313
334
|
|
335
|
+
# Universals and extentials at top-level
|
314
336
|
unless @universals.empty?
|
315
|
-
log_debug
|
337
|
+
log_debug("start_document: universals") { @universals.inspect}
|
316
338
|
terms = @universals.map {|v| format_uri(RDF::URI(v.name.to_s))}
|
317
339
|
@output.write("@forAll #{terms.join(', ')} .\n")
|
318
340
|
end
|
319
341
|
|
320
342
|
unless @existentials.empty?
|
321
|
-
log_debug
|
322
|
-
terms = @existentials.map {|v| format_uri(RDF::URI(v.name.to_s))}
|
343
|
+
log_debug("start_document: existentials") { @existentials.inspect}
|
344
|
+
terms = @existentials.map {|v| format_uri(RDF::URI(v.name.to_s.sub(/_ext$/, '')))}
|
323
345
|
@output.write("@forSome #{terms.join(', ')} .\n")
|
324
346
|
end
|
325
347
|
end
|
@@ -331,7 +353,17 @@ module RDF::N3
|
|
331
353
|
# Defines order of predicates to to emit at begninning of a resource description. Defaults to
|
332
354
|
# [rdf:type, rdfs:label, dc:title]
|
333
355
|
# @return [Array<URI>]
|
334
|
-
def predicate_order
|
356
|
+
def predicate_order
|
357
|
+
[
|
358
|
+
RDF.type,
|
359
|
+
RDF::RDFS.label,
|
360
|
+
RDF::RDFS.comment,
|
361
|
+
RDF::URI("http://purl.org/dc/terms/title"),
|
362
|
+
RDF::URI("http://purl.org/dc/terms/description"),
|
363
|
+
RDF::OWL.sameAs,
|
364
|
+
RDF::N3::Log.implies
|
365
|
+
]
|
366
|
+
end
|
335
367
|
|
336
368
|
# Order subjects for output. Override this to output subjects in another order.
|
337
369
|
#
|
@@ -342,7 +374,7 @@ module RDF::N3
|
|
342
374
|
subjects = []
|
343
375
|
|
344
376
|
# Start with base_uri
|
345
|
-
if base_uri && @subjects.keys.include?(base_uri)
|
377
|
+
if base_uri && @subjects.keys.select(&:uri?).include?(base_uri)
|
346
378
|
subjects << base_uri
|
347
379
|
seen[base_uri] = true
|
348
380
|
end
|
@@ -350,24 +382,26 @@ module RDF::N3
|
|
350
382
|
# Add distinguished classes
|
351
383
|
top_classes.each do |class_uri|
|
352
384
|
graph.query({predicate: RDF.type, object: class_uri}).
|
353
|
-
map {|st| st.subject}.
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
385
|
+
map {|st| st.subject}.sort.uniq.each do |subject|
|
386
|
+
log_debug("order_subjects") {subject.to_sxp}
|
387
|
+
subjects << subject
|
388
|
+
seen[subject] = true
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
# Add formulae which are subjects in this graph
|
393
|
+
@formulae.each_key do |bn|
|
394
|
+
next unless @subjects.key?(bn)
|
395
|
+
subjects << bn
|
396
|
+
seen[bn] = true
|
361
397
|
end
|
362
398
|
|
363
399
|
# Mark as seen lists that are part of another list
|
364
|
-
@lists.values.
|
365
|
-
|
366
|
-
|
367
|
-
end
|
400
|
+
@lists.values.flatten.each do |v|
|
401
|
+
seen[v] = true if @lists.key?(v)
|
402
|
+
end
|
368
403
|
|
369
|
-
|
370
|
-
list_elements = @lists.values.map(&:to_a).flatten.select(&:node?).compact
|
404
|
+
list_elements = [] # Lists may be top-level elements
|
371
405
|
|
372
406
|
# Sort subjects by resources over bnodes, ref_counts and the subject URI itself
|
373
407
|
recursable = (@subjects.keys - list_elements).
|
@@ -391,7 +425,7 @@ module RDF::N3
|
|
391
425
|
@options[:prefixes] = {} # Will define actual used when matched
|
392
426
|
repo.each {|statement| preprocess_statement(statement)}
|
393
427
|
|
394
|
-
vars = repo.enum_term.to_a.uniq.select {|r| r.is_a?(RDF::Query::Variable)}
|
428
|
+
vars = repo.enum_term.to_a.uniq.select {|r| r.is_a?(RDF::Query::Variable) && !r.to_s.end_with?('_quick')}
|
395
429
|
@universals = vars.reject(&:existential?)
|
396
430
|
@existentials = vars - @universals
|
397
431
|
end
|
@@ -400,7 +434,7 @@ module RDF::N3
|
|
400
434
|
# prefixes.
|
401
435
|
# @param [Statement] statement
|
402
436
|
def preprocess_statement(statement)
|
403
|
-
#log_debug
|
437
|
+
#log_debug("preprocess") {statement.inspect}
|
404
438
|
|
405
439
|
# Pre-fetch pnames, to fill prefixes
|
406
440
|
get_pname(statement.subject)
|
@@ -410,24 +444,13 @@ module RDF::N3
|
|
410
444
|
end
|
411
445
|
|
412
446
|
# Perform graph-specific preprocessing
|
413
|
-
# @param [Statement]
|
447
|
+
# @param [Statement] statement
|
414
448
|
def preprocess_graph_statement(statement)
|
415
449
|
bump_reference(statement.object)
|
416
450
|
# Count properties of this subject
|
417
451
|
@subjects[statement.subject] ||= {}
|
418
452
|
@subjects[statement.subject][statement.predicate] ||= 0
|
419
453
|
@subjects[statement.subject][statement.predicate] += 1
|
420
|
-
|
421
|
-
# Collect lists
|
422
|
-
if statement.predicate == RDF.first
|
423
|
-
l = RDF::List.new(subject: statement.subject, graph: graph)
|
424
|
-
@lists[statement.subject] = l if l.valid?
|
425
|
-
end
|
426
|
-
|
427
|
-
if statement.object == RDF.nil || statement.subject == RDF.nil
|
428
|
-
# Add an entry for the list tail
|
429
|
-
@lists[RDF.nil] ||= RDF::List[]
|
430
|
-
end
|
431
454
|
end
|
432
455
|
|
433
456
|
# Returns indent string multiplied by the depth
|
@@ -464,35 +487,33 @@ module RDF::N3
|
|
464
487
|
private
|
465
488
|
|
466
489
|
# Checks if l is a valid RDF list, i.e. no nodes have other properties.
|
467
|
-
def
|
468
|
-
|
469
|
-
return @lists[l] && @lists[l].valid?
|
470
|
-
end
|
471
|
-
|
472
|
-
def do_list(l, position)
|
473
|
-
list = @lists[l]
|
474
|
-
log_debug("do_list") {list.inspect}
|
475
|
-
subject_done(RDF.nil)
|
476
|
-
index = 0
|
477
|
-
list.each_statement do |st|
|
478
|
-
next unless st.predicate == RDF.first
|
479
|
-
log_debug {" list this: #{st.subject} first: #{st.object}[#{position}]"}
|
480
|
-
@output.write(" ") if index > 0
|
481
|
-
path(st.object, position)
|
482
|
-
subject_done(st.subject)
|
483
|
-
position = :object
|
484
|
-
index += 1
|
485
|
-
end
|
490
|
+
def collection?(l)
|
491
|
+
return @lists.key?(l) || l.list?
|
486
492
|
end
|
487
493
|
|
488
494
|
def collection(node, position)
|
489
|
-
return false if !
|
490
|
-
|
491
|
-
|
492
|
-
|
495
|
+
return false if !collection?(node)
|
496
|
+
log_debug("collection") do
|
497
|
+
"#{node.to_sxp}, " +
|
498
|
+
"pos: #{position}, " +
|
499
|
+
"rc: #{ref_count(node)}"
|
500
|
+
end
|
493
501
|
|
494
502
|
@output.write("(")
|
495
|
-
log_depth
|
503
|
+
log_depth do
|
504
|
+
list = node.list? ? node : @lists[node]
|
505
|
+
log_debug("collection") {list.inspect}
|
506
|
+
subject_done(RDF.nil)
|
507
|
+
subject_done(node)
|
508
|
+
index = 0
|
509
|
+
list.each do |li|
|
510
|
+
log_debug("(list first)") {"#{li}[#{position}]"}
|
511
|
+
@output.write(" ") if index > 0
|
512
|
+
path(li, :object)
|
513
|
+
subject_done(li)
|
514
|
+
index += 1
|
515
|
+
end
|
516
|
+
end
|
496
517
|
@output.write(')')
|
497
518
|
end
|
498
519
|
|
@@ -500,7 +521,11 @@ module RDF::N3
|
|
500
521
|
def p_term(resource, position)
|
501
522
|
#log_debug("p_term") {"#{resource.to_sxp}, #{position}"}
|
502
523
|
l = if resource.is_a?(RDF::Query::Variable)
|
503
|
-
|
524
|
+
if resource.to_s.end_with?('_quick')
|
525
|
+
'?' + RDF::URI(resource.name).fragment.sub(/_quick$/, '')
|
526
|
+
else
|
527
|
+
format_term(RDF::URI(resource.name.to_s.sub(/_ext$/, '')))
|
528
|
+
end
|
504
529
|
elsif resource == RDF.nil
|
505
530
|
"()"
|
506
531
|
else
|
@@ -515,9 +540,9 @@ module RDF::N3
|
|
515
540
|
log_debug("path") do
|
516
541
|
"#{resource.to_sxp}, " +
|
517
542
|
"pos: #{position}, " +
|
518
|
-
"{}?: #{formula?(resource, position)}, " +
|
519
|
-
"()?: #{
|
520
|
-
"[]?: #{blankNodePropertyList?(resource, position)}, " +
|
543
|
+
"{}?: #{formula?(resource, position).inspect}, " +
|
544
|
+
"()?: #{collection?(resource).inspect}, " +
|
545
|
+
"[]?: #{blankNodePropertyList?(resource, position).inspect}, " +
|
521
546
|
"rc: #{ref_count(resource)}"
|
522
547
|
end
|
523
548
|
raise RDF::WriterError, "Cannot serialize resource '#{resource}'" unless
|
@@ -537,7 +562,7 @@ module RDF::N3
|
|
537
562
|
when RDF::N3::Log.implies
|
538
563
|
@output.write("=>")
|
539
564
|
else
|
540
|
-
path(resource, :predicate)
|
565
|
+
log_depth {path(resource, :predicate)}
|
541
566
|
end
|
542
567
|
end
|
543
568
|
|
@@ -546,13 +571,15 @@ module RDF::N3
|
|
546
571
|
log_debug("objectList") {objects.inspect}
|
547
572
|
return if objects.empty?
|
548
573
|
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
574
|
+
log_depth do
|
575
|
+
objects.each_with_index do |obj, i|
|
576
|
+
if i > 0 && (formula?(obj, :object) || blankNodePropertyList?(obj, :object))
|
577
|
+
@output.write ", "
|
578
|
+
elsif i > 0
|
579
|
+
@output.write ",\n#{indent(4)}"
|
580
|
+
end
|
581
|
+
path(obj, :object)
|
554
582
|
end
|
555
|
-
path(obj, :object)
|
556
583
|
end
|
557
584
|
end
|
558
585
|
|
@@ -560,29 +587,24 @@ module RDF::N3
|
|
560
587
|
# @return [Integer] the number of properties serialized
|
561
588
|
def predicateObjectList(subject, from_bpl = false)
|
562
589
|
properties = {}
|
563
|
-
|
564
|
-
|
565
|
-
@graph.enum_statement.select {|s| s.subject.equal?(subject)}.each do |st|
|
566
|
-
(properties[st.predicate.to_s] ||= []) << st.object
|
567
|
-
end
|
568
|
-
else
|
569
|
-
@graph.query({subject: subject}) do |st|
|
570
|
-
(properties[st.predicate.to_s] ||= []) << st.object
|
571
|
-
end
|
590
|
+
@graph.enum_statement.select {|s| s.subject.sameTerm?(subject)}.each do |st|
|
591
|
+
(properties[st.predicate] ||= []) << st.object
|
572
592
|
end
|
573
593
|
|
574
594
|
prop_list = sort_properties(properties)
|
575
|
-
prop_list -= [RDF.first
|
576
|
-
log_debug("predicateObjectList") {prop_list.
|
595
|
+
prop_list -= [RDF.first, RDF.rest] if @lists.key?(subject)
|
596
|
+
log_debug("predicateObjectList") { "subject: #{subject.to_sxp}, properties: #{prop_list.join(', ')}" }
|
577
597
|
return 0 if prop_list.empty?
|
578
598
|
|
579
599
|
@output.write("\n#{indent(2)}") if properties.keys.length > 1 && from_bpl
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
600
|
+
log_depth do
|
601
|
+
prop_list.each_with_index do |prop, i|
|
602
|
+
begin
|
603
|
+
@output.write(";\n#{indent(2)}") if i > 0
|
604
|
+
predicate(prop)
|
605
|
+
@output.write(" ")
|
606
|
+
objectList(properties[prop])
|
607
|
+
end
|
586
608
|
end
|
587
609
|
end
|
588
610
|
properties.keys.length
|
@@ -592,10 +614,9 @@ module RDF::N3
|
|
592
614
|
def blankNodePropertyList?(resource, position)
|
593
615
|
resource.node? &&
|
594
616
|
!formula?(resource, position) &&
|
595
|
-
!
|
617
|
+
!collection?(resource) &&
|
596
618
|
(!is_done?(resource) || position == :subject) &&
|
597
619
|
ref_count(resource) == (position == :object ? 1 : 0) &&
|
598
|
-
resource_in_single_graph?(resource) &&
|
599
620
|
!repo.has_graph?(resource)
|
600
621
|
end
|
601
622
|
|
@@ -604,20 +625,15 @@ module RDF::N3
|
|
604
625
|
|
605
626
|
log_debug("blankNodePropertyList") {resource.to_sxp}
|
606
627
|
subject_done(resource)
|
607
|
-
@output.write(position == :subject ? "\n#{indent}[" : '[')
|
628
|
+
@output.write((position == :subject ? "\n#{indent}[" : '['))
|
608
629
|
num_props = log_depth {predicateObjectList(resource, true)}
|
609
|
-
@output.write((num_props > 1 ? "\n#{indent(2)}" : "") + (position == :
|
630
|
+
@output.write((num_props > 1 ? "\n#{indent(2)}" : "") + (position == :subject ? '] .' : ']'))
|
610
631
|
true
|
611
632
|
end
|
612
633
|
|
613
634
|
# Can subject be represented as a formula?
|
614
635
|
def formula?(resource, position)
|
615
|
-
|
616
|
-
repo.has_graph?(resource) &&
|
617
|
-
!is_valid_list?(resource) &&
|
618
|
-
(!is_done?(resource) || position == :subject) &&
|
619
|
-
ref_count(resource) == (position == :object ? 1 : 0) &&
|
620
|
-
resource_in_single_graph?(resource)
|
636
|
+
!!@formulae[resource]
|
621
637
|
end
|
622
638
|
|
623
639
|
def formula(resource, position)
|
@@ -626,9 +642,9 @@ module RDF::N3
|
|
626
642
|
log_debug("formula") {resource.to_sxp}
|
627
643
|
subject_done(resource)
|
628
644
|
@output.write('{')
|
645
|
+
count = 0
|
629
646
|
log_depth do
|
630
647
|
with_graph(resource) do
|
631
|
-
count = 0
|
632
648
|
order_subjects.each do |subject|
|
633
649
|
unless is_done?(subject)
|
634
650
|
statement(subject, count)
|
@@ -637,7 +653,7 @@ module RDF::N3
|
|
637
653
|
end
|
638
654
|
end
|
639
655
|
end
|
640
|
-
@output.write((
|
656
|
+
@output.write((count > 0 ? "#{indent}" : "") + '}')
|
641
657
|
true
|
642
658
|
end
|
643
659
|
|
@@ -647,25 +663,22 @@ module RDF::N3
|
|
647
663
|
path(subject, :subject)
|
648
664
|
@output.write(" ")
|
649
665
|
num_props = predicateObjectList(subject)
|
650
|
-
@output.
|
666
|
+
@output.puts("#{num_props > 0 ? ' ' : ''}.")
|
651
667
|
true
|
652
668
|
end
|
653
669
|
|
654
670
|
def statement(subject, count)
|
655
|
-
log_debug("statement")
|
671
|
+
log_debug("statement") do
|
672
|
+
"#{subject.to_sxp}, " +
|
673
|
+
"{}?: #{formula?(subject, :subject).inspect}, " +
|
674
|
+
"()?: #{collection?(subject).inspect}, " +
|
675
|
+
"[]?: #{blankNodePropertyList?(subject, :subject).inspect}, "
|
676
|
+
end
|
656
677
|
subject_done(subject)
|
657
678
|
blankNodePropertyList(subject, :subject) || triples(subject)
|
658
679
|
@output.puts if count > 0 || graph.graph_name
|
659
680
|
end
|
660
681
|
|
661
|
-
# Return the number of statements having this resource as a subject other than for list properties
|
662
|
-
# @return [Integer]
|
663
|
-
def prop_count(subject)
|
664
|
-
@subjects.fetch(subject, {}).
|
665
|
-
reject {|k, v| [RDF.type, RDF.first, RDF.rest].include?(k)}.
|
666
|
-
values.reduce(:+) || 0
|
667
|
-
end
|
668
|
-
|
669
682
|
# Return the number of times this node has been referenced in the object position
|
670
683
|
# @return [Integer]
|
671
684
|
def ref_count(node)
|
@@ -697,19 +710,6 @@ module RDF::N3
|
|
697
710
|
@graphs[graph_name] = true
|
698
711
|
end
|
699
712
|
|
700
|
-
def resource_in_single_graph?(resource)
|
701
|
-
if resource.variable?
|
702
|
-
graph_names = @repo.
|
703
|
-
enum_statement.
|
704
|
-
select {|st| st.subject.equal?(resource) || st.object.equal?(resource)}.
|
705
|
-
map(&:graph_name)
|
706
|
-
else
|
707
|
-
graph_names = @repo.query({subject: resource}).map(&:graph_name)
|
708
|
-
graph_names += @repo.query({object: resource}).map(&:graph_name)
|
709
|
-
end
|
710
|
-
graph_names.uniq.length <= 1
|
711
|
-
end
|
712
|
-
|
713
713
|
# Process a graph projection
|
714
714
|
def with_graph(graph_name)
|
715
715
|
old_lists, @lists = @lists, {}
|
@@ -717,21 +717,81 @@ module RDF::N3
|
|
717
717
|
old_serialized, @serialized = @serialized, {}
|
718
718
|
old_subjects, @subjects = @subjects, {}
|
719
719
|
old_graph, @graph = @graph, repo.project_graph(graph_name)
|
720
|
+
old_formulae, @formulae = @formulae, {}
|
720
721
|
|
721
722
|
graph_done(graph_name)
|
722
723
|
|
723
|
-
|
724
|
+
lists = {}
|
725
|
+
graph.each do |statement|
|
726
|
+
preprocess_graph_statement(statement)
|
727
|
+
[statement.subject, statement.object].each do |resource|
|
728
|
+
@formulae[resource] = true if
|
729
|
+
resource.node? &&
|
730
|
+
(formula_names.include?(resource) || resource.id.start_with?('_form_'))
|
731
|
+
|
732
|
+
# First-class list may have members which are formulae, and need reference counts
|
733
|
+
if resource.list?
|
734
|
+
resource.each_descendant do |term|
|
735
|
+
bump_reference(term)
|
736
|
+
@formulae[term] = true if
|
737
|
+
term.node? &&
|
738
|
+
(formula_names.include?(term) || term.id.start_with?('_form_'))
|
739
|
+
end
|
740
|
+
end
|
741
|
+
end
|
742
|
+
|
743
|
+
# Collect list elements
|
744
|
+
if [RDF.first, RDF.rest].include?(statement.predicate) && statement.subject.node?
|
745
|
+
lists[statement.subject] ||= {}
|
746
|
+
lists[statement.subject][statement.predicate] = statement.object
|
747
|
+
end
|
748
|
+
end
|
749
|
+
|
750
|
+
# Remove list entries after head with more than two properties (other than rdf:type)
|
751
|
+
rests = lists.values.map {|props| props[RDF.rest]}
|
752
|
+
|
753
|
+
# Remove non-head lists that have too many properties
|
754
|
+
rests.select do |bn|
|
755
|
+
pc = 0
|
756
|
+
@subjects.fetch(bn, {}).each do |pred, count|
|
757
|
+
next if pred == RDF.type
|
758
|
+
pc += count
|
759
|
+
end
|
760
|
+
lists.delete(bn) if pc > 2
|
761
|
+
end
|
762
|
+
|
763
|
+
# Values for this list element, recursive
|
764
|
+
def list_values(bn, lists)
|
765
|
+
raise "no list" unless lists.has_key?(bn)
|
766
|
+
first, rest = lists[bn][RDF.first], lists[bn][RDF.rest]
|
767
|
+
(rest == RDF.nil ? [] : list_values(rest, lists)).unshift(first)
|
768
|
+
rescue
|
769
|
+
lists.delete(bn)
|
770
|
+
raise $!
|
771
|
+
end
|
772
|
+
|
773
|
+
# Create value arrays for each entry
|
774
|
+
lists.each do |bn, props|
|
775
|
+
begin
|
776
|
+
@lists[bn] = list_values(bn, lists)
|
777
|
+
rescue
|
778
|
+
# Skip this list element, if it raises an exception
|
779
|
+
lists.delete(bn)
|
780
|
+
end
|
781
|
+
end
|
782
|
+
|
783
|
+
# Mark all remaining rests done
|
784
|
+
rests.each {|bn| subject_done(bn) if lists.include?(bn)}
|
724
785
|
|
725
|
-
# Remove
|
726
|
-
|
727
|
-
|
728
|
-
ref_count(node) > 0 && prop_count(node) > 0 ||
|
729
|
-
list.subjects.any? {|elt| !resource_in_single_graph?(elt)}
|
786
|
+
# Remove entries that are referenced as rdf:rest of some entry
|
787
|
+
lists.each do |bn, props|
|
788
|
+
@lists.delete(props[RDF.rest])
|
730
789
|
end
|
731
790
|
|
791
|
+
# Record nodes in subject or object
|
732
792
|
yield
|
733
793
|
ensure
|
734
|
-
@graph, @lists, @references, @serialized, @subjects = old_graph, old_lists, old_references, old_serialized, old_subjects
|
794
|
+
@graph, @lists, @references, @serialized, @subjects, @formulae = old_graph, old_lists, old_references, old_serialized, old_subjects, old_formulae
|
735
795
|
end
|
736
796
|
end
|
737
797
|
end
|