rdf-turtle 3.0.1 → 3.0.2
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.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/rdf/turtle/writer.rb +109 -73
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1a8fb1c87f5b5149cc3430a1cdac50fdd7bfbaeacfeaa1a6770e54e83a1aff09
|
|
4
|
+
data.tar.gz: 7bf9532ca0c78ce4e24e51ef3a4076a8563e2f0fa2e9f9853616f47776f0947f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 55ec7f72b8b020506c134805828ff43341ce455b469edfb396332c61b67ae3cc7bdf2a0dcfcb3808c47201c77564e046a84d0aaaba2a74553fd2d1c30c93a184
|
|
7
|
+
data.tar.gz: 308390211f1da6158fe12d322d8dec7e24ce94931ccd994fb202bf9ac5f38665ac3f1f2e7c02ae9a20e8f3b775462e8831b1357a96be045f8f427d5d241dbf84
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.0.
|
|
1
|
+
3.0.2
|
data/lib/rdf/turtle/writer.rb
CHANGED
|
@@ -183,8 +183,15 @@ module RDF::Turtle
|
|
|
183
183
|
log_debug("\nserialize") {"graph: #{@graph.size}"}
|
|
184
184
|
|
|
185
185
|
preprocess
|
|
186
|
+
|
|
186
187
|
start_document
|
|
187
188
|
|
|
189
|
+
# Remove lists that are referenced and have non-list properties;
|
|
190
|
+
# these are legal, but can't be serialized as lists
|
|
191
|
+
@lists.reject! do |node, list|
|
|
192
|
+
ref_count(node) > 0 && non_list_prop_count(node) > 0
|
|
193
|
+
end
|
|
194
|
+
|
|
188
195
|
order_subjects.each do |subject|
|
|
189
196
|
unless is_done?(subject)
|
|
190
197
|
statement(subject)
|
|
@@ -193,7 +200,7 @@ module RDF::Turtle
|
|
|
193
200
|
end
|
|
194
201
|
super
|
|
195
202
|
end
|
|
196
|
-
|
|
203
|
+
|
|
197
204
|
# Return a QName for the URI, or nil. Adds namespace of QName to defined prefixes
|
|
198
205
|
# @param [RDF::Resource] resource
|
|
199
206
|
# @return [String, nil] value to use to identify URI
|
|
@@ -210,7 +217,7 @@ module RDF::Turtle
|
|
|
210
217
|
pname = case
|
|
211
218
|
when @uri_to_pname.has_key?(uri)
|
|
212
219
|
return @uri_to_pname[uri]
|
|
213
|
-
when u = @uri_to_prefix.keys.sort_by {|
|
|
220
|
+
when u = @uri_to_prefix.keys.sort_by {|uu| uu.length}.reverse.detect {|uu| uri.index(uu.to_s) == 0}
|
|
214
221
|
# Use a defined prefix
|
|
215
222
|
prefix = @uri_to_prefix[u]
|
|
216
223
|
unless u.to_s.empty?
|
|
@@ -227,7 +234,7 @@ module RDF::Turtle
|
|
|
227
234
|
else
|
|
228
235
|
nil
|
|
229
236
|
end
|
|
230
|
-
|
|
237
|
+
|
|
231
238
|
# Make sure pname is a valid pname
|
|
232
239
|
if pname
|
|
233
240
|
md = Terminals::PNAME_LN.match(pname) || Terminals::PNAME_NS.match(pname)
|
|
@@ -236,7 +243,7 @@ module RDF::Turtle
|
|
|
236
243
|
|
|
237
244
|
@uri_to_pname[uri] = pname
|
|
238
245
|
end
|
|
239
|
-
|
|
246
|
+
|
|
240
247
|
# Take a hash from predicate uris to lists of values.
|
|
241
248
|
# Sort the lists of values. Return a sorted list of properties.
|
|
242
249
|
# @param [Hash{String => Array<Resource>}] properties A hash of Property to Resource mappings
|
|
@@ -244,17 +251,17 @@ module RDF::Turtle
|
|
|
244
251
|
def sort_properties(properties)
|
|
245
252
|
# Make sorted list of properties
|
|
246
253
|
prop_list = []
|
|
247
|
-
|
|
254
|
+
|
|
248
255
|
predicate_order.each do |prop|
|
|
249
256
|
next unless properties[prop.to_s]
|
|
250
257
|
prop_list << prop.to_s
|
|
251
258
|
end
|
|
252
|
-
|
|
259
|
+
|
|
253
260
|
properties.keys.sort.each do |prop|
|
|
254
261
|
next if prop_list.include?(prop.to_s)
|
|
255
262
|
prop_list << prop.to_s
|
|
256
263
|
end
|
|
257
|
-
|
|
264
|
+
|
|
258
265
|
log_debug("sort_properties") {prop_list.join(', ')}
|
|
259
266
|
prop_list
|
|
260
267
|
end
|
|
@@ -283,7 +290,7 @@ module RDF::Turtle
|
|
|
283
290
|
quoted(literal.to_s)
|
|
284
291
|
end
|
|
285
292
|
end
|
|
286
|
-
|
|
293
|
+
|
|
287
294
|
##
|
|
288
295
|
# Returns the Turtle representation of a URI reference.
|
|
289
296
|
#
|
|
@@ -295,7 +302,7 @@ module RDF::Turtle
|
|
|
295
302
|
log_debug("relativize") {"#{uri.to_ntriples} => #{md.inspect}"} if md != uri.to_s
|
|
296
303
|
md != uri.to_s ? "<#{md}>" : (get_pname(uri) || "<#{uri}>")
|
|
297
304
|
end
|
|
298
|
-
|
|
305
|
+
|
|
299
306
|
##
|
|
300
307
|
# Returns the Turtle representation of a blank node.
|
|
301
308
|
#
|
|
@@ -305,12 +312,12 @@ module RDF::Turtle
|
|
|
305
312
|
def format_node(node, options = {})
|
|
306
313
|
options[:unique_bnodes] ? node.to_unique_base : node.to_base
|
|
307
314
|
end
|
|
308
|
-
|
|
315
|
+
|
|
309
316
|
protected
|
|
310
317
|
# Output @base and @prefix definitions
|
|
311
318
|
def start_document
|
|
312
319
|
@output.write("#{indent}@base <#{base_uri}> .\n") unless base_uri.to_s.empty?
|
|
313
|
-
|
|
320
|
+
|
|
314
321
|
log_debug("start_document") {prefixes.inspect}
|
|
315
322
|
prefixes.keys.sort_by(&:to_s).each do |prefix|
|
|
316
323
|
@output.write("#{indent}@prefix #{prefix}: <#{prefixes[prefix]}> .\n")
|
|
@@ -325,7 +332,7 @@ module RDF::Turtle
|
|
|
325
332
|
# `\[rdf:type, rdfs:label, dc:title\]`
|
|
326
333
|
# @return [Array<URI>]
|
|
327
334
|
def predicate_order; [RDF.type, RDF::RDFS.label, RDF::URI("http://purl.org/dc/terms/title")]; end
|
|
328
|
-
|
|
335
|
+
|
|
329
336
|
# Order subjects for output. Override this to output subjects in another order.
|
|
330
337
|
#
|
|
331
338
|
# Uses #top_classes and #base_uri.
|
|
@@ -333,31 +340,44 @@ module RDF::Turtle
|
|
|
333
340
|
def order_subjects
|
|
334
341
|
seen = {}
|
|
335
342
|
subjects = []
|
|
336
|
-
|
|
343
|
+
|
|
337
344
|
# Start with base_uri
|
|
338
345
|
if base_uri && @subjects.keys.include?(base_uri)
|
|
339
346
|
subjects << RDF::URI(base_uri)
|
|
340
347
|
seen[RDF::URI(base_uri)] = true
|
|
341
348
|
end
|
|
342
|
-
|
|
349
|
+
|
|
343
350
|
# Add distinguished classes
|
|
344
351
|
top_classes.each do |class_uri|
|
|
345
|
-
graph.query(predicate: RDF.type, object: class_uri).
|
|
352
|
+
graph.query(predicate: RDF.type, object: class_uri).
|
|
353
|
+
map {|st| st.subject}.
|
|
354
|
+
sort.
|
|
355
|
+
uniq.
|
|
356
|
+
each do |subject|
|
|
346
357
|
log_debug("order_subjects") {subject.to_ntriples}
|
|
347
358
|
subjects << subject
|
|
348
359
|
seen[subject] = true
|
|
349
360
|
end
|
|
350
361
|
end
|
|
351
|
-
|
|
362
|
+
|
|
363
|
+
# Mark as seen lists that are part of another list
|
|
364
|
+
@lists.values.map(&:statements).
|
|
365
|
+
flatten.each do |st|
|
|
366
|
+
seen[st.object] if @lists.has_key?(st.object)
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
# List elements should not be targets for top-level serialization
|
|
370
|
+
list_elements = @lists.values.map(&:to_a).flatten.compact
|
|
371
|
+
|
|
352
372
|
# Sort subjects by resources over bnodes, ref_counts and the subject URI itself
|
|
353
|
-
recursable = @subjects.keys.
|
|
373
|
+
recursable = (@subjects.keys - list_elements).
|
|
354
374
|
select {|s| !seen.include?(s)}.
|
|
355
375
|
map {|r| [r.node? ? 1 : 0, ref_count(r), r]}.
|
|
356
376
|
sort
|
|
357
|
-
|
|
358
|
-
subjects
|
|
377
|
+
|
|
378
|
+
subjects + recursable.map{|r| r.last}
|
|
359
379
|
end
|
|
360
|
-
|
|
380
|
+
|
|
361
381
|
# Perform any preprocessing of statements required
|
|
362
382
|
def preprocess
|
|
363
383
|
# Load defined prefixes
|
|
@@ -375,14 +395,27 @@ module RDF::Turtle
|
|
|
375
395
|
@graph.each {|statement| preprocess_statement(statement)}
|
|
376
396
|
end
|
|
377
397
|
end
|
|
378
|
-
|
|
398
|
+
|
|
379
399
|
# Perform any statement preprocessing required. This is used to perform reference counts and determine required
|
|
380
400
|
# prefixes.
|
|
381
401
|
# @param [Statement] statement
|
|
382
402
|
def preprocess_statement(statement)
|
|
383
403
|
#log_debug("preprocess") {statement.to_ntriples}
|
|
384
404
|
bump_reference(statement.object)
|
|
385
|
-
|
|
405
|
+
# Count properties of this subject
|
|
406
|
+
(@subjects[statement.subject] ||= {})[statement.predicate] ||= 0
|
|
407
|
+
@subjects[statement.subject][statement.predicate] += 1
|
|
408
|
+
|
|
409
|
+
# Collect lists
|
|
410
|
+
if statement.predicate == RDF.first
|
|
411
|
+
l = RDF::List.new(subject: statement.subject, graph: graph)
|
|
412
|
+
@lists[statement.subject] = l if l.valid?
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
if statement.object == RDF.nil || statement.subject == RDF.nil
|
|
416
|
+
# Add an entry for the list tail
|
|
417
|
+
@lists[RDF.nil] ||= RDF::List[]
|
|
418
|
+
end
|
|
386
419
|
|
|
387
420
|
# Pre-fetch pnames, to fill prefixes
|
|
388
421
|
get_pname(statement.subject)
|
|
@@ -401,6 +434,7 @@ module RDF::Turtle
|
|
|
401
434
|
# Reset internal helper instance variables
|
|
402
435
|
def reset
|
|
403
436
|
@lists = {}
|
|
437
|
+
|
|
404
438
|
@references = {}
|
|
405
439
|
@serialized = {}
|
|
406
440
|
@subjects = {}
|
|
@@ -425,13 +459,13 @@ module RDF::Turtle
|
|
|
425
459
|
# Checks if l is a valid RDF list, i.e. no nodes have other properties.
|
|
426
460
|
def is_valid_list?(l)
|
|
427
461
|
#log_debug("is_valid_list?") {l.inspect}
|
|
428
|
-
return
|
|
462
|
+
return @lists[l] && @lists[l].valid?
|
|
429
463
|
end
|
|
430
|
-
|
|
431
|
-
def do_list(l)
|
|
432
|
-
list =
|
|
464
|
+
|
|
465
|
+
def do_list(l, position)
|
|
466
|
+
list = @lists[l]
|
|
433
467
|
log_debug("do_list") {list.inspect}
|
|
434
|
-
|
|
468
|
+
subject_done(RDF.nil)
|
|
435
469
|
list.each_statement do |st|
|
|
436
470
|
next unless st.predicate == RDF.first
|
|
437
471
|
log_debug {" list this: #{st.subject} first: #{st.object}[#{position}]"}
|
|
@@ -443,38 +477,38 @@ module RDF::Turtle
|
|
|
443
477
|
|
|
444
478
|
def collection(node, position)
|
|
445
479
|
return false if !is_valid_list?(node)
|
|
480
|
+
return false if position == :subject && ref_count(node) > 0
|
|
481
|
+
return false if position == :object && non_list_prop_count(node) > 0
|
|
446
482
|
#log_debug("collection") {"#{node.to_ntriples}, #{position}"}
|
|
447
483
|
|
|
448
484
|
@output.write(position == :subject ? "(" : " (")
|
|
449
|
-
log_depth {do_list(node)}
|
|
485
|
+
log_depth {do_list(node, position)}
|
|
450
486
|
@output.write(')')
|
|
451
487
|
end
|
|
452
488
|
|
|
453
|
-
# Can
|
|
454
|
-
def
|
|
489
|
+
# Can subject be represented as a blankNodePropertyList?
|
|
490
|
+
def blankNodePropertyList?(resource, position)
|
|
455
491
|
resource.node? &&
|
|
456
|
-
|
|
457
|
-
|
|
492
|
+
!is_valid_list?(resource) &&
|
|
493
|
+
(!is_done?(resource) || position == :subject) &&
|
|
494
|
+
ref_count(resource) == (position == :object ? 1 : 0)
|
|
458
495
|
end
|
|
459
496
|
|
|
460
|
-
# Represent
|
|
461
|
-
def
|
|
462
|
-
return false unless
|
|
497
|
+
# Represent resource as a blankNodePropertyList
|
|
498
|
+
def blankNodePropertyList(resource, position)
|
|
499
|
+
return false unless blankNodePropertyList?(resource, position)
|
|
463
500
|
|
|
464
|
-
|
|
501
|
+
log_debug("blankNodePropertyList") {resource.to_ntriples}
|
|
465
502
|
subject_done(resource)
|
|
466
|
-
@output.write(position == :subject ?
|
|
467
|
-
log_depth
|
|
468
|
-
|
|
469
|
-
@output.write(num_props > 1 ? "\n#{indent} ]" : "]")
|
|
470
|
-
end
|
|
471
|
-
|
|
503
|
+
@output.write(position == :subject ? "\n#{indent} [" : ' [')
|
|
504
|
+
num_props = log_depth {predicateObjectList(resource, true)}
|
|
505
|
+
@output.write((num_props > 1 ? "\n#{indent}" : "") + (position == :object ? ']' : '] .'))
|
|
472
506
|
true
|
|
473
507
|
end
|
|
474
508
|
|
|
475
509
|
# Default singular resource representation.
|
|
476
|
-
def
|
|
477
|
-
#log_debug("
|
|
510
|
+
def p_term(resource, position)
|
|
511
|
+
#log_debug("p_term") {"#{resource.to_ntriples}, #{position}"}
|
|
478
512
|
l = (position == :subject ? "" : " ") + format_term(resource, options)
|
|
479
513
|
@output.write(l)
|
|
480
514
|
end
|
|
@@ -486,12 +520,15 @@ module RDF::Turtle
|
|
|
486
520
|
"#{resource.to_ntriples}, " +
|
|
487
521
|
"pos: #{position}, " +
|
|
488
522
|
"()?: #{is_valid_list?(resource)}, " +
|
|
489
|
-
"[]?: #{
|
|
523
|
+
"[]?: #{blankNodePropertyList?(resource, position)}, " +
|
|
490
524
|
"rc: #{ref_count(resource)}"
|
|
491
525
|
end
|
|
492
|
-
raise RDF::WriterError, "Cannot serialize resource '#{resource}'" unless
|
|
526
|
+
raise RDF::WriterError, "Cannot serialize resource '#{resource}'" unless
|
|
527
|
+
collection(resource, position) ||
|
|
528
|
+
blankNodePropertyList(resource, position) ||
|
|
529
|
+
p_term(resource, position)
|
|
493
530
|
end
|
|
494
|
-
|
|
531
|
+
|
|
495
532
|
def predicate(resource)
|
|
496
533
|
log_debug("predicate") {resource.to_ntriples}
|
|
497
534
|
if resource == RDF.type
|
|
@@ -507,7 +544,7 @@ module RDF::Turtle
|
|
|
507
544
|
return if objects.empty?
|
|
508
545
|
|
|
509
546
|
objects.each_with_index do |obj, i|
|
|
510
|
-
if i > 0 &&
|
|
547
|
+
if i > 0 && blankNodePropertyList?(obj, :object)
|
|
511
548
|
@output.write ", "
|
|
512
549
|
elsif i > 0
|
|
513
550
|
@output.write ",\n#{indent(4)}"
|
|
@@ -524,7 +561,8 @@ module RDF::Turtle
|
|
|
524
561
|
(properties[st.predicate.to_s] ||= []) << st.object
|
|
525
562
|
end
|
|
526
563
|
|
|
527
|
-
prop_list = sort_properties(properties)
|
|
564
|
+
prop_list = sort_properties(properties)
|
|
565
|
+
prop_list -= [RDF.first.to_s, RDF.rest.to_s] if @lists.include?(subject)
|
|
528
566
|
log_debug("predicateObjectList") {prop_list.inspect}
|
|
529
567
|
return 0 if prop_list.empty?
|
|
530
568
|
|
|
@@ -539,22 +577,6 @@ module RDF::Turtle
|
|
|
539
577
|
properties.keys.length
|
|
540
578
|
end
|
|
541
579
|
|
|
542
|
-
# Can subject be represented as a blankNodePropertyList?
|
|
543
|
-
def blankNodePropertyList?(subject)
|
|
544
|
-
ref_count(subject) == 0 && subject.node? && !is_valid_list?(subject)
|
|
545
|
-
end
|
|
546
|
-
|
|
547
|
-
# Represent subject as a blankNodePropertyList?
|
|
548
|
-
def blankNodePropertyList(subject)
|
|
549
|
-
return false unless blankNodePropertyList?(subject)
|
|
550
|
-
|
|
551
|
-
log_debug("blankNodePropertyList") {subject.to_ntriples}
|
|
552
|
-
@output.write("\n#{indent} [")
|
|
553
|
-
num_props = log_depth {predicateObjectList(subject, true)}
|
|
554
|
-
@output.write(num_props > 1 ? "\n#{indent} ] ." : "] .")
|
|
555
|
-
true
|
|
556
|
-
end
|
|
557
|
-
|
|
558
580
|
# Render triples having the same subject using an explicit subject
|
|
559
581
|
def triples(subject)
|
|
560
582
|
@output.write("\n#{indent}")
|
|
@@ -563,18 +585,28 @@ module RDF::Turtle
|
|
|
563
585
|
@output.write(" .")
|
|
564
586
|
true
|
|
565
587
|
end
|
|
566
|
-
|
|
588
|
+
|
|
567
589
|
def statement(subject)
|
|
568
|
-
log_debug("statement") {"#{subject.to_ntriples}, bnodePL?: #{blankNodePropertyList?(subject)}"}
|
|
590
|
+
log_debug("statement") {"#{subject.to_ntriples}, bnodePL?: #{blankNodePropertyList?(subject, :subject)}"}
|
|
569
591
|
subject_done(subject)
|
|
570
|
-
blankNodePropertyList(subject) || triples(subject)
|
|
592
|
+
blankNodePropertyList(subject, :subject) || triples(subject)
|
|
571
593
|
@output.puts
|
|
572
594
|
end
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
595
|
+
|
|
596
|
+
# Return the number of statements having this resource as a subject
|
|
597
|
+
# @return [Integer]
|
|
598
|
+
def prop_count(subject)
|
|
599
|
+
@subjects.fetch(subject, {}).values.reduce(:+) || 0
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
# Return the number of statements having this resource as a subject other than for list properties
|
|
603
|
+
# @return [Integer]
|
|
604
|
+
def non_list_prop_count(subject)
|
|
605
|
+
@subjects.fetch(subject, {}).
|
|
606
|
+
reject {|k, v| [RDF.type, RDF.first, RDF.rest].include?(k)}.
|
|
607
|
+
values.reduce(:+) || 0
|
|
576
608
|
end
|
|
577
|
-
|
|
609
|
+
|
|
578
610
|
# Return the number of times this node has been referenced in the object position
|
|
579
611
|
# @return [Integer]
|
|
580
612
|
def ref_count(resource)
|
|
@@ -587,7 +619,11 @@ module RDF::Turtle
|
|
|
587
619
|
def bump_reference(resource)
|
|
588
620
|
@references[resource] = ref_count(resource) + 1
|
|
589
621
|
end
|
|
590
|
-
|
|
622
|
+
|
|
623
|
+
def is_done?(subject)
|
|
624
|
+
@serialized.include?(subject)
|
|
625
|
+
end
|
|
626
|
+
|
|
591
627
|
# Mark a subject as done.
|
|
592
628
|
def subject_done(subject)
|
|
593
629
|
@serialized[subject] = true
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rdf-turtle
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0.
|
|
4
|
+
version: 3.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gregg Kellogg
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2018-
|
|
11
|
+
date: 2018-09-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rdf
|
|
@@ -195,7 +195,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
195
195
|
version: '0'
|
|
196
196
|
requirements: []
|
|
197
197
|
rubyforge_project:
|
|
198
|
-
rubygems_version: 2.7.
|
|
198
|
+
rubygems_version: 2.7.6
|
|
199
199
|
signing_key:
|
|
200
200
|
specification_version: 4
|
|
201
201
|
summary: Turtle reader/writer for Ruby.
|