rdf-turtle 3.1.2 → 3.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cab6a95280c9ece9d97ed7bde134044c247d0990cd9451772b3726a85c1dafce
4
- data.tar.gz: 56c87a3f41a22ffae491aed4197261e204332541855777f1822bd24d965047f0
3
+ metadata.gz: 57d92c642076069a911db896415fa9dbd3203b6c82a9074e0fc8a53dafb2389d
4
+ data.tar.gz: 238620d914ce1ff78d8710e12083d03eacb5f9be7106d0d12ef15c5105445b72
5
5
  SHA512:
6
- metadata.gz: c5ce46d746a7ed5ac19c3b8fde60934485781149302d6b02e64d1b45dd70a6402c46ba8ca9e7eb06c3d96030c93c26646751bc92155dc239dbc41179d9c72c49
7
- data.tar.gz: ad9a7a6ea210992f5a0ddbd037ded7b7f0a0129e4fc4a5610ad03f313381354207394840c9c729c70192906dfac58294c216a62382316b909f79a34c3db9d172
6
+ metadata.gz: 0db24a8c173d7b522ba06e1af9e957c513a551a211d22b6a2d19b7218a79e236f6db1f66b738a1a76e5b96ef6161f432f7ece17dea4af8d3de46520960a89977
7
+ data.tar.gz: a2826f9e8fbd34364acc54a117e283067982491e9c8e736ac1c8fcb86aac1f6a3acc43811040242fea19e79019d809fd14dae6b46ecc0568b67775dddd84369d
data/README.md CHANGED
@@ -3,8 +3,9 @@
3
3
  [Turtle][] reader/writer for [RDF.rb][RDF.rb] .
4
4
 
5
5
  [![Gem Version](https://badge.fury.io/rb/rdf-turtle.png)](https://badge.fury.io/rb/rdf-turtle)
6
- [![Build Status](https://travis-ci.org/ruby-rdf/rdf-turtle.png?branch=master)](https://travis-ci.org/ruby-rdf/rdf-turtle)
7
- [![Coverage Status](https://coveralls.io/repos/ruby-rdf/rdf-turtle/badge.svg)](https://coveralls.io/r/ruby-rdf/rdf-turtle)
6
+ [![Build Status](https://github.com/ruby-rdf/rdf-turtle/workflows/CI/badge.svg?branch=develop)](https://github.com/ruby-rdf/rdf-turtle/actions?query=workflow%3ACI)
7
+ [![Coverage Status](https://coveralls.io/repos/ruby-rdf/rdf-turtle/badge.svg?branch=develop)](https://coveralls.io/github/ruby-rdf/rdf-turtle?branch=develop)
8
+ [![Gitter chat](https://badges.gitter.im/ruby-rdf/rdf.png)](https://gitter.im/ruby-rdf/rdf)
8
9
 
9
10
  ## Description
10
11
  This is a [Ruby][] implementation of a [Turtle][] parser for [RDF.rb][].
@@ -16,9 +17,9 @@ Install with `gem install rdf-turtle`
16
17
 
17
18
  * 100% free and unencumbered [public domain](https://unlicense.org/) software.
18
19
  * Implements a complete parser for [Turtle][].
19
- * Compatible with Ruby >= 2.2.2.
20
+ * Compatible with Ruby >= 2.6.
20
21
  * Optional streaming writer, to serialize large graphs
21
- * Provisional support for [Turtle*][RDF*].
22
+ * Provisional support for [Turtle-star][RDF-star].
22
23
 
23
24
  ## Usage
24
25
  Instantiate a reader from a local file:
@@ -35,9 +36,9 @@ Write a graph to a file:
35
36
  writer << graph
36
37
  end
37
38
 
38
- ## Turtle* (RDFStar)
39
+ ## Turtle-star (RDF-star)
39
40
 
40
- Both reader and writer include provisional support for [Turtle*][RDF*].
41
+ Both reader and writer include provisional support for [Turtle-star][RDF-star].
41
42
 
42
43
  Internally, an `RDF::Statement` is treated as another resource, along with `RDF::URI` and `RDF::Node`, which allows an `RDF::Statement` to have a `#subject` or `#object` which is also an `RDF::Statement`.
43
44
 
@@ -65,19 +66,29 @@ By default, the Turtle reader will reject a document containing a subject resour
65
66
  end
66
67
  # => RDF::ReaderError
67
68
 
68
- Readers support a `rdfstar` option with either `:PG` (Property Graph) or `:SA` (Separate Assertions) modes. In `:PG` mode, statements that are used in the subject or object positions are also implicitly added to the graph:
69
+ Readers support a boolean valued `rdfstar` option; only one statement is asserted, although the reified statement is contained within the graph.
69
70
 
70
71
  graph = RDF::Graph.new do |graph|
71
- RDF::Turtle::Reader.new(ttl, rdfstar: :PG) {|reader| graph << reader}
72
+ RDF::Turtle::Reader.new(ttl, rdfstar: true) {|reader| graph << reader}
72
73
  end
73
- graph.count #=> 2
74
+ graph.count #=> 1
75
+
76
+ ### Reading a Graph containing statement annotations
74
77
 
75
- When using the `:SA` mode, only one statement is asserted, although the reified statement is contained within the graph.
78
+ Annotations are introduced using the `{| ... |}` syntax, which is treated like a `blankNodePropertyList`,
79
+ where the subject is the the triple ending with that annotation.
76
80
 
81
+ ttl = %(
82
+ @prefix foaf: <http://xmlns.com/foaf/0.1/> .
83
+ @prefix ex: <http://example.com/> .
84
+ <bob> foaf:age 23 {| ex:certainty 9.0e-1 |} .
85
+ )
77
86
  graph = RDF::Graph.new do |graph|
78
- RDF::Turtle::Reader.new(ttl, rdfstar: :SA) {|reader| graph << reader}
87
+ RDF::Turtle::Reader.new(ttl) {|reader| graph << reader}
79
88
  end
80
- graph.count #=> 1
89
+ # => RDF::ReaderError
90
+
91
+ Note that this requires the `rdfstar` option to be set.
81
92
 
82
93
  ## Documentation
83
94
  Full documentation available on [Rubydoc.info][Turtle doc]
@@ -129,9 +140,9 @@ This version uses a hand-written parser using the Lexer from the [EBNF][] gem in
129
140
 
130
141
  ## Dependencies
131
142
 
132
- * [Ruby](https://ruby-lang.org/) (>= 2.4)
133
- * [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.1)
134
- * [EBNF][] (~> 1.1)
143
+ * [Ruby](https://ruby-lang.org/) (>= 2.6)
144
+ * [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.2)
145
+ * [EBNF][] (~> 1.2)
135
146
 
136
147
  ## Installation
137
148
 
@@ -159,7 +170,9 @@ This repository uses [Git Flow](https://github.com/nvie/gitflow) to mange develo
159
170
  list in the the `README`. Alphabetical order applies.
160
171
  * Do note that in order for us to merge any non-trivial changes (as a rule
161
172
  of thumb, additions larger than about 15 lines of code), we need an
162
- explicit [public domain dedication][PDD] on record from you.
173
+ explicit [public domain dedication][PDD] on record from you,
174
+ which you will be asked to agree to on the first commit to a repo within the organization.
175
+ Note that the agreement applies to all repos in the [Ruby RDF](https://github.com/ruby-rdf/) organization.
163
176
 
164
177
  ## License
165
178
  This is free and unencumbered public domain software. For more information,
@@ -171,13 +184,13 @@ A copy of the [Turtle EBNF][] and derived parser files are included in the repos
171
184
  [RDF]: https://www.w3.org/RDF/
172
185
  [YARD]: https://yardoc.org/
173
186
  [YARD-GS]: https://rubydoc.info/docs/yard/file/docs/GettingStarted.md
174
- [PDD]: https://lists.w3.org/Archives/Public/public-rdf-ruby/2010May/0013.html
175
- [RDF.rb]: https://rubydoc.info/github/ruby-rdf/rdf
187
+ [PDD]: https://unlicense.org/#unlicensing-contributions
188
+ [RDF.rb]: https://ruby-rdf.github.io/rdf
176
189
  [EBNF]: https://rubygems.org/gems/ebnf
177
190
  [Backports]: https://rubygems.org/gems/backports
178
191
  [N-Triples]: https://www.w3.org/TR/rdf-testcases/#ntriples
179
192
  [Turtle]: https://www.w3.org/TR/2012/WD-turtle-20120710/
180
- [RDF*]: https://lists.w3.org/Archives/Public/public-rdf-star/
181
- [Turtle doc]: https://rubydoc.info/github/ruby-rdf/rdf-turtle/master/file/README.md
193
+ [RDF-star]: https://w3c.github.io/rdf-star/rdf-star-cg-spec.html
194
+ [Turtle doc]: https://ruby-rdf.github.io/rdf-turtle/master/file/README.md
182
195
  [Turtle EBNF]: https://dvcs.w3.org/hg/rdf/file/default/rdf-turtle/turtle.bnf
183
196
  [Freebase Dumps]: https://developers.google.com/freebase/data
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.1.2
1
+ 3.2.1
@@ -18,6 +18,7 @@ module RDF::Turtle
18
18
  class Format < RDF::Format
19
19
  content_type 'text/turtle',
20
20
  extension: :ttl,
21
+ uri: 'http://www.w3.org/ns/formats/Turtle',
21
22
  aliases: %w(
22
23
  text/rdf+turtle
23
24
  application/turtle;q=0.2
@@ -25,7 +25,14 @@ module RDF::Turtle
25
25
  terminal(:STRING_LITERAL_SINGLE_QUOTE, STRING_LITERAL_SINGLE_QUOTE, unescape: true)
26
26
 
27
27
  # String terminals
28
- terminal(nil, %r([\(\),.;\[\]Aa]|\^\^|true|false|<<|>>))
28
+ terminal(nil, %r(
29
+ [\(\),.;\[\]Aa]
30
+ | \^\^
31
+ | \{\|
32
+ | \|\}
33
+ | true|false
34
+ | <<|>>
35
+ )x)
29
36
 
30
37
  terminal(:PREFIX, PREFIX)
31
38
  terminal(:BASE, BASE)
@@ -33,7 +40,7 @@ module RDF::Turtle
33
40
 
34
41
  ##
35
42
  # Reader options
36
- # @see https://www.rubydoc.info/github/ruby-rdf/rdf/RDF/Reader#options-class_method
43
+ # @see https://ruby-rdf.github.io/rdf/RDF/Reader#options-class_method
37
44
  def self.options
38
45
  super + [
39
46
  RDF::CLI::Option.new(
@@ -92,11 +99,11 @@ module RDF::Turtle
92
99
  @prod_stack = []
93
100
 
94
101
  @options[:base_uri] = RDF::URI(base_uri || "")
95
- log_debug("base IRI") {base_uri.inspect}
102
+ debug("base IRI") {base_uri.inspect}
96
103
 
97
- log_debug("validate") {validate?.inspect}
98
- log_debug("canonicalize") {canonicalize?.inspect}
99
- log_debug("intern") {intern?.inspect}
104
+ debug("validate") {validate?.inspect}
105
+ debug("canonicalize") {canonicalize?.inspect}
106
+ debug("intern") {intern?.inspect}
100
107
 
101
108
  @lexer = EBNF::LL1::Lexer.new(input, self.class.patterns, **@options)
102
109
 
@@ -185,7 +192,7 @@ module RDF::Turtle
185
192
 
186
193
  # Create a literal
187
194
  def literal(value, **options)
188
- log_debug("literal", depth: @options[:depth]) do
195
+ debug("literal", depth: @options[:depth]) do
189
196
  "value: #{value.inspect}, " +
190
197
  "options: #{options.inspect}, " +
191
198
  "validate: #{validate?.inspect}, " +
@@ -221,7 +228,7 @@ module RDF::Turtle
221
228
  ''
222
229
  end
223
230
  suffix = suffix.to_s.sub(/^\#/, "") if base.index("#")
224
- log_debug("pname", depth: options[:depth]) {"base: '#{base}', suffix: '#{suffix}'"}
231
+ debug("pname", depth: options[:depth]) {"base: '#{base}', suffix: '#{suffix}'"}
225
232
  process_iri(base + suffix.to_s)
226
233
  end
227
234
 
@@ -283,7 +290,7 @@ module RDF::Turtle
283
290
  terminated = token.value == '@prefix'
284
291
  error("Expected PNAME_NS", production: :prefix, token: pfx) unless pfx === :PNAME_NS
285
292
  error("Expected IRIREF", production: :prefix, token: iri) unless iri === :IRIREF
286
- log_debug("prefixID", depth: options[:depth]) {"Defined prefix #{pfx.inspect} mapping to #{iri.inspect}"}
293
+ debug("prefixID", depth: options[:depth]) {"Defined prefix #{pfx.inspect} mapping to #{iri.inspect}"}
287
294
  prefix(pfx.value[0..-2], process_iri(iri))
288
295
  error("prefixId", "#{token} should be downcased") if token.value.start_with?('@') && token.value != '@prefix'
289
296
 
@@ -340,6 +347,10 @@ module RDF::Turtle
340
347
  last_object = nil
341
348
  while object = prod(:_objectList_2) {read_object(subject, predicate)}
342
349
  last_object = object
350
+
351
+ # If object is followed by an annotation, read that and also emit an embedded triple.
352
+ read_annotation(subject, predicate, object)
353
+
343
354
  break unless @lexer.first === ','
344
355
  @lexer.shift while @lexer.first === ','
345
356
  end
@@ -362,7 +373,7 @@ module RDF::Turtle
362
373
  read_iri ||
363
374
  read_BlankNode ||
364
375
  read_collection ||
365
- read_rdfstar ||
376
+ read_quotedTriple ||
366
377
  error( "Expected subject", production: :subject, token: @lexer.first)
367
378
  end
368
379
  end
@@ -375,7 +386,7 @@ module RDF::Turtle
375
386
  read_collection ||
376
387
  read_blankNodePropertyList ||
377
388
  read_literal ||
378
- read_rdfstar
389
+ read_quotedTriple
379
390
 
380
391
  add_statement(:object, RDF::Statement(subject, predicate, object)) if subject && predicate
381
392
  object
@@ -383,35 +394,71 @@ module RDF::Turtle
383
394
  end
384
395
  end
385
396
 
386
- # Read an RDF* reified statement
397
+ # Read an RDF-star reified statement
387
398
  # @return [RDF::Statement]
388
- def read_rdfstar
399
+ def read_quotedTriple
389
400
  return unless @options[:rdfstar]
390
401
  if @lexer.first.value == '<<'
391
- prod(:rdfstar) do
402
+ prod(:quotedTriple) do
392
403
  @lexer.shift # eat <<
393
- subject = read_subject || error("Failed to parse subject", production: :rdfstar, token: @lexer.first)
394
- predicate = read_verb || error("Failed to parse predicate", production: :rdfstar, token: @lexer.first)
395
- object = read_object || error("Failed to parse object", production: :rdfstar, token: @lexer.first)
404
+ subject = read_qtSubject || error("Failed to parse subject", production: :quotedTriple, token: @lexer.first)
405
+ predicate = read_verb || error("Failed to parse predicate", production: :quotedTriple, token: @lexer.first)
406
+ object = read_qtObject || error("Failed to parse object", production: :quotedTriple, token: @lexer.first)
396
407
  unless @lexer.first.value == '>>'
397
- error("Failed to end of embedded triple", production: :rdfstar, token: @lexer.first)
408
+ error("Failed to end of embedded triple", production: :quotedTriple, token: @lexer.first)
398
409
  end
399
410
  @lexer.shift
400
- statement = RDF::Statement(subject, predicate, object)
401
- # Emit the statement if in Property Graph mode
402
- add_statement(:rdfstar, statement) if @options[:rdfstar] == :PG
411
+ statement = RDF::Statement(subject, predicate, object, quoted: true)
403
412
  statement
404
413
  end
405
414
  end
406
415
  end
407
416
 
417
+ # @return [RDF::Resource]
418
+ def read_qtSubject
419
+ prod(:qtSubject) do
420
+ read_iri ||
421
+ read_BlankNode ||
422
+ read_quotedTriple ||
423
+ error( "Expected embedded subject", production: :qtSubject, token: @lexer.first)
424
+ end
425
+ end
426
+
427
+ # @return [RDF::Term]
428
+ def read_qtObject(subject = nil, predicate = nil)
429
+ prod(:qtObject) do
430
+ read_iri ||
431
+ read_BlankNode ||
432
+ read_literal ||
433
+ read_quotedTriple
434
+ end
435
+ end
436
+
437
+ # Read an annotation on a triple
438
+ def read_annotation(subject, predicate, object)
439
+ error("Unexpected end of file", production: :annotation) unless token = @lexer.first
440
+ if token === '{|'
441
+ prod(:annotation, %(|})) do
442
+ @lexer.shift
443
+
444
+ # Statement becomes subject for predicateObjectList
445
+ statement = RDF::Statement(subject, predicate, object, quoted: true)
446
+ read_predicateObjectList(statement) ||
447
+ error("Expected predicateObjectList", production: :annotation, token: @lexer.first)
448
+ error("annotation", "Expected closing '|}'") unless @lexer.first === '|}'
449
+ @lexer.shift
450
+ end
451
+ end
452
+
453
+ end
454
+
408
455
  # @return [RDF::Literal]
409
456
  def read_literal
410
457
  error("Unexpected end of file", production: :literal) unless token = @lexer.first
411
458
  case token.type || token.value
412
459
  when :INTEGER then prod(:literal) {literal(@lexer.shift.value, datatype: RDF::XSD.integer)}
413
460
  when :DECIMAL
414
- prod(:litearl) do
461
+ prod(:literal) do
415
462
  value = @lexer.shift.value
416
463
  value = "0#{value}" if value.start_with?(".")
417
464
  literal(value, datatype: RDF::XSD.decimal)
@@ -455,7 +502,7 @@ module RDF::Turtle
455
502
  if token === '['
456
503
  prod(:blankNodePropertyList, %{]}) do
457
504
  @lexer.shift
458
- log_info("blankNodePropertyList", depth: options[:depth]) {"token: #{token.inspect}"}
505
+ progress("blankNodePropertyList", depth: options[:depth]) {"token: #{token.inspect}"}
459
506
  node = bnode
460
507
  read_predicateObjectList(node)
461
508
  error("blankNodePropertyList", "Expected closing ']'") unless @lexer.first === ']'
@@ -471,7 +518,7 @@ module RDF::Turtle
471
518
  prod(:collection, %{)}) do
472
519
  @lexer.shift
473
520
  token = @lexer.first
474
- log_info("collection", depth: options[:depth]) {"token: #{token.inspect}"}
521
+ progress("collection", depth: options[:depth]) {"token: #{token.inspect}"}
475
522
  objects = []
476
523
  while object = read_object
477
524
  objects << object
@@ -508,7 +555,7 @@ module RDF::Turtle
508
555
  def prod(production, recover_to = [])
509
556
  @prod_stack << {prod: production, recover_to: recover_to}
510
557
  @options[:depth] += 1
511
- log_recover("#{production}(start)", depth: options[:depth]) {"token: #{@lexer.first.inspect}"}
558
+ recover("#{production}(start)", depth: options[:depth], token: @lexer.first)
512
559
  yield
513
560
  rescue EBNF::LL1::Lexer::Error, SyntaxError, Recovery => e
514
561
  # Lexer encountered an illegal token or the parser encountered
@@ -528,13 +575,13 @@ module RDF::Turtle
528
575
  end
529
576
  end
530
577
  raise EOFError, "End of input found when recovering" if @lexer.first.nil?
531
- log_debug("recovery", "current token: #{@lexer.first.inspect}", depth: options[:depth])
578
+ debug("recovery", "current token: #{@lexer.first.inspect}", depth: options[:depth])
532
579
 
533
580
  unless e.is_a?(Recovery)
534
581
  # Get the list of follows for this sequence, this production and the stacked productions.
535
- log_debug("recovery", "stack follows:", depth: options[:depth])
582
+ debug("recovery", "stack follows:", depth: options[:depth])
536
583
  @prod_stack.reverse.each do |prod|
537
- log_debug("recovery", level: 4, depth: options[:depth]) {" #{prod[:prod]}: #{prod[:recover_to].inspect}"}
584
+ debug("recovery", level: 4, depth: options[:depth]) {" #{prod[:prod]}: #{prod[:recover_to].inspect}"}
538
585
  end
539
586
  end
540
587
 
@@ -544,9 +591,9 @@ module RDF::Turtle
544
591
  # Skip tokens until one is found in follows
545
592
  while (token = (@lexer.first rescue @lexer.recover)) && follows.none? {|t| token === t}
546
593
  skipped = @lexer.shift
547
- log_debug("recovery", depth: options[:depth]) {"skip #{skipped.inspect}"}
594
+ debug("recovery", depth: options[:depth]) {"skip #{skipped.inspect}"}
548
595
  end
549
- log_debug("recovery", depth: options[:depth]) {"found #{token.inspect} in follows"}
596
+ debug("recovery", depth: options[:depth]) {"found #{token.inspect} in follows"}
550
597
 
551
598
  # Re-raise the error unless token is a follows of this production
552
599
  raise Recovery unless Array(recover_to).any? {|t| token === t}
@@ -554,11 +601,35 @@ module RDF::Turtle
554
601
  # Skip that token to get something reasonable to start the next production with
555
602
  @lexer.shift
556
603
  ensure
557
- log_info("#{production}(finish)", depth: options[:depth])
604
+ progress("#{production}(finish)", depth: options[:depth])
558
605
  @options[:depth] -= 1
559
606
  @prod_stack.pop
560
607
  end
561
608
 
609
+ def progress(*args, &block)
610
+ lineno = (options[:token].lineno if options[:token].respond_to?(:lineno)) || (@lexer && @lexer.lineno)
611
+ opts = args.last.is_a?(Hash) ? args.pop : {}
612
+ opts[:level] ||= 1
613
+ opts[:lineno] ||= lineno
614
+ log_info(*args, **opts, &block)
615
+ end
616
+
617
+ def recover(*args, &block)
618
+ lineno = (options[:token].lineno if options[:token].respond_to?(:lineno)) || (@lexer && @lexer.lineno)
619
+ opts = args.last.is_a?(Hash) ? args.pop : {}
620
+ opts[:level] ||= 1
621
+ opts[:lineno] ||= lineno
622
+ log_recover(*args, **opts, &block)
623
+ end
624
+
625
+ def debug(*args, &block)
626
+ lineno = (options[:token].lineno if options[:token].respond_to?(:lineno)) || (@lexer && @lexer.lineno)
627
+ opts = args.last.is_a?(Hash) ? args.pop : {}
628
+ opts[:level] ||= 0
629
+ opts[:lineno] ||= lineno
630
+ log_debug(*args, **opts, &block)
631
+ end
632
+
562
633
  ##
563
634
  # Error information, used as level `0` debug messages.
564
635
  #
@@ -65,7 +65,7 @@ module RDF::Turtle
65
65
 
66
66
  ##
67
67
  # Writer options
68
- # @see https://www.rubydoc.info/github/ruby-rdf/rdf/RDF/Writer#options-class_method
68
+ # @see https://ruby-rdf.github.io/rdf/RDF/Writer#options-class_method
69
69
  def self.options
70
70
  super + [
71
71
  RDF::CLI::Option.new(
@@ -201,7 +201,7 @@ module RDF::Turtle
201
201
  super
202
202
  end
203
203
 
204
- # Return a QName for the URI, or nil. Adds namespace of QName to defined prefixes
204
+ # Return a PName for the URI, or nil. Adds namespace of PName to defined prefixes
205
205
  # @param [RDF::Resource] resource
206
206
  # @return [String, nil] value to use to identify URI
207
207
  def get_pname(resource)
@@ -223,14 +223,15 @@ module RDF::Turtle
223
223
  unless u.to_s.empty?
224
224
  prefix(prefix, u) unless u.to_s.empty?
225
225
  log_debug("get_pname") {"add prefix #{prefix.inspect} => #{u}"}
226
- uri.sub(u.to_s, "#{prefix}:")
226
+ # Escape suffix, as necessary
227
+ RDF::URI(uri).pname(prefixes: {prefix => u})
227
228
  end
228
229
  when @options[:standard_prefixes] && vocab = RDF::Vocabulary.each.to_a.detect {|v| uri.index(v.to_uri.to_s) == 0}
229
230
  prefix = vocab.__name__.to_s.split('::').last.downcase
230
231
  @uri_to_prefix[vocab.to_uri.to_s] = prefix
231
232
  prefix(prefix, vocab.to_uri) # Define for output
232
233
  log_debug("get_pname") {"add standard prefix #{prefix.inspect} => #{vocab.to_uri}"}
233
- uri.sub(vocab.to_uri.to_s, "#{prefix}:")
234
+ RDF::URI(uri).pname(prefixes: {prefix => vocab.to_uri})
234
235
  else
235
236
  nil
236
237
  end
@@ -276,10 +277,23 @@ module RDF::Turtle
276
277
  case literal
277
278
  when RDF::Literal
278
279
  case @options[:literal_shorthand] && literal.valid? ? literal.datatype : false
279
- when RDF::XSD.boolean, RDF::XSD.integer, RDF::XSD.decimal
280
- literal.canonicalize.to_s
280
+ when RDF::XSD.boolean
281
+ %w(true false).include?(literal.value) ? literal.value : literal.canonicalize.to_s
282
+ when RDF::XSD.integer
283
+ literal.value.match?(/^[\+\-]?\d+$/) && !canonicalize? ? literal.value : literal.canonicalize.to_s
284
+ when RDF::XSD.decimal
285
+ literal.value.match?(/^[\+\-]?\d+\.\d+?$/) && !canonicalize? ?
286
+ literal.value :
287
+ literal.canonicalize.to_s
281
288
  when RDF::XSD.double
282
- literal.canonicalize.to_s.sub('E', 'e') # Favor lower case exponent
289
+ in_form = case literal.value
290
+ when /[\+\-]?\d+\.\d*E[\+\-]?\d+$/i then true
291
+ when /[\+\-]?\.\d+E[\+\-]?\d+$/i then true
292
+ when /[\+\-]?\d+E[\+\-]?\d+$/i then true
293
+ else false
294
+ end && !canonicalize?
295
+
296
+ in_form ? literal.value : literal.canonicalize.to_s.sub('E', 'e').to_s
283
297
  else
284
298
  text = quoted(literal.value)
285
299
  text << "@#{literal.language}" if literal.has_language?
@@ -314,12 +328,12 @@ module RDF::Turtle
314
328
  end
315
329
 
316
330
  ##
317
- # Returns an embedded triples
331
+ # Returns an embedded triple.
318
332
  #
319
333
  # @param [RDF::Statement] statement
320
334
  # @param [Hash{Symbol => Object}] options
321
335
  # @return [String]
322
- def format_rdfstar(statement, **options)
336
+ def format_quotedTriple(statement, **options)
323
337
  log_debug("rdfstar") {"#{statement.to_ntriples}"}
324
338
  "<<%s %s %s>>" % statement.to_a.map { |value| format_term(value, **options) }
325
339
  end
@@ -374,16 +388,16 @@ module RDF::Turtle
374
388
  # Mark as seen lists that are part of another list
375
389
  @lists.values.map(&:statements).
376
390
  flatten.each do |st|
377
- seen[st.object] = true if @lists.has_key?(st.object)
391
+ seen[st.object] = true if @lists.key?(st.object)
378
392
  end
379
393
 
380
- # List elements which are bnodes should not be targets for top-level serialization
381
- list_elements = @lists.values.map(&:to_a).flatten.select(&:node?).compact
394
+ # List elements which are bnodes should not be targets for top-level serialization
395
+ list_elements = @lists.values.map(&:to_a).flatten.select(&:node?).compact
382
396
 
383
- # Sort subjects by resources over bnodes, ref_counts and the subject URI itself
397
+ # Sort subjects by resources and statements over bnodes, ref_counts and the subject URI itself
384
398
  recursable = (@subjects.keys - list_elements).
385
399
  select {|s| !seen.include?(s)}.
386
- map {|r| [r.node? ? 1 : 0, ref_count(r), r]}.
400
+ map {|r| [r.node? ? 2 : (r.statement? ? 1 : 0), ref_count(r), r]}.
387
401
  sort
388
402
 
389
403
  subjects + recursable.map{|r| r.last}
@@ -469,7 +483,7 @@ module RDF::Turtle
469
483
  # Can subject be represented as a blankNodePropertyList?
470
484
  def blankNodePropertyList?(resource, position)
471
485
  !resource.statement? && resource.node? &&
472
- !is_valid_list?(resource) &&
486
+ !collection?(resource) &&
473
487
  (!is_done?(resource) || position == :subject) &&
474
488
  ref_count(resource) == (position == :object ? 1 : 0)
475
489
  end
@@ -507,35 +521,33 @@ module RDF::Turtle
507
521
  private
508
522
 
509
523
  # Checks if l is a valid RDF list, i.e. no nodes have other properties.
510
- def is_valid_list?(l)
511
- #log_debug("is_valid_list?") {l.inspect}
512
- return @lists[l] && @lists[l].valid?
513
- end
514
-
515
- def do_list(l, position)
516
- list = @lists[l]
517
- log_debug("do_list") {list.inspect}
518
- subject_done(RDF.nil)
519
- index = 0
520
- list.each_statement do |st|
521
- next unless st.predicate == RDF.first
522
- log_debug {" list this: #{st.subject} first: #{st.object}[#{position}]"}
523
- @output.write(" ") if index > 0
524
- path(st.object, position)
525
- subject_done(st.subject)
526
- position = :object
527
- index += 1
528
- end
524
+ def collection?(l)
525
+ #log_debug("collection?") {l.inspect}
526
+ return @lists.key?(l)
529
527
  end
530
528
 
531
529
  def collection(node, position)
532
- return false if !is_valid_list?(node)
530
+ return false if !collection?(node)
533
531
  return false if position == :subject && ref_count(node) > 0
534
532
  return false if position == :object && prop_count(node) > 0
535
533
  #log_debug("collection") {"#{node.to_ntriples}, #{position}"}
536
534
 
537
535
  @output.write("(")
538
- log_depth {do_list(node, position)}
536
+ log_depth do
537
+ list = @lists[node]
538
+ log_debug("collection") {list.inspect}
539
+ subject_done(RDF.nil)
540
+ index = 0
541
+ list.each_statement do |st|
542
+ next unless st.predicate == RDF.first
543
+ log_debug {" list this: #{st.subject} first: #{st.object}[#{position}]"}
544
+ @output.write(" ") if index > 0
545
+ path(st.object, position)
546
+ subject_done(st.subject)
547
+ position = :object
548
+ index += 1
549
+ end
550
+ end
539
551
  @output.write(')')
540
552
  end
541
553
 
@@ -568,7 +580,7 @@ module RDF::Turtle
568
580
  log_debug("path") do
569
581
  "#{resource.to_ntriples}, " +
570
582
  "pos: #{position}, " +
571
- "()?: #{is_valid_list?(resource)}, " +
583
+ "()?: #{collection?(resource)}, " +
572
584
  "[]?: #{blankNodePropertyList?(resource, position)}, " +
573
585
  "rc: #{ref_count(resource)}"
574
586
  end
@@ -588,7 +600,7 @@ module RDF::Turtle
588
600
  end
589
601
 
590
602
  # Render an objectList having a common subject and predicate
591
- def objectList(objects)
603
+ def objectList(subject, predicate, objects)
592
604
  log_debug("objectList") {objects.inspect}
593
605
  return if objects.empty?
594
606
 
@@ -599,6 +611,15 @@ module RDF::Turtle
599
611
  @output.write ",\n#{indent(4)}"
600
612
  end
601
613
  path(obj, :object)
614
+
615
+ # If subject, predicate, and object are embedded, write those bits out too.
616
+ emb = RDF::Statement(subject, predicate, obj)
617
+ if !@graph.query({subject: emb}).empty?
618
+ @output.write ' {| '
619
+ predicateObjectList(emb, true)
620
+ @output.write ' |}'
621
+ subject_done(emb)
622
+ end
602
623
  end
603
624
  end
604
625
 
@@ -611,17 +632,18 @@ module RDF::Turtle
611
632
  end
612
633
 
613
634
  prop_list = sort_properties(properties)
614
- prop_list -= [RDF.first.to_s, RDF.rest.to_s] if @lists.include?(subject)
635
+ prop_list -= [RDF.first.to_s, RDF.rest.to_s] if @lists.key?(subject)
615
636
  log_debug("predicateObjectList") {prop_list.inspect}
616
637
  return 0 if prop_list.empty?
617
638
 
618
639
  @output.write("\n#{indent(2)}") if properties.keys.length > 1 && from_bpl
619
640
  prop_list.each_with_index do |prop, i|
620
641
  begin
642
+ pred = RDF::URI.intern(prop)
621
643
  @output.write(";\n#{indent(2)}") if i > 0
622
- predicate(RDF::URI.intern(prop))
644
+ predicate(pred)
623
645
  @output.write(" ")
624
- objectList(properties[prop])
646
+ objectList(subject, pred, properties[prop])
625
647
  end
626
648
  end
627
649
  properties.keys.length
data/lib/rdf/turtle.rb CHANGED
@@ -15,7 +15,7 @@ module RDF
15
15
  # end
16
16
  # end
17
17
  #
18
- # @see https://rubydoc.info/github/ruby-rdf/rdf/master/frames
18
+ # @see https://ruby-rdf.github.io/rdf/master/frames
19
19
  # @see https://dvcs.w3.org/hg/rdf/raw-file/default/rdf-turtle/index.html
20
20
  #
21
21
  # @author [Gregg Kellogg](https://greggkellogg.net/)
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.1.2
4
+ version: 3.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gregg Kellogg
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-23 00:00:00.000000000 Z
11
+ date: 2022-05-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdf
@@ -16,146 +16,140 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '3.1'
20
- - - ">="
21
- - !ruby/object:Gem::Version
22
- version: 3.1.2
19
+ version: '3.2'
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
24
  - - "~>"
28
25
  - !ruby/object:Gem::Version
29
- version: '3.1'
30
- - - ">="
31
- - !ruby/object:Gem::Version
32
- version: 3.1.2
26
+ version: '3.2'
33
27
  - !ruby/object:Gem::Dependency
34
28
  name: ebnf
35
29
  requirement: !ruby/object:Gem::Requirement
36
30
  requirements:
37
31
  - - "~>"
38
32
  - !ruby/object:Gem::Version
39
- version: '2.0'
33
+ version: '2.3'
40
34
  type: :runtime
41
35
  prerelease: false
42
36
  version_requirements: !ruby/object:Gem::Requirement
43
37
  requirements:
44
38
  - - "~>"
45
39
  - !ruby/object:Gem::Version
46
- version: '2.0'
40
+ version: '2.3'
47
41
  - !ruby/object:Gem::Dependency
48
- name: rspec
42
+ name: erubis
49
43
  requirement: !ruby/object:Gem::Requirement
50
44
  requirements:
51
45
  - - "~>"
52
46
  - !ruby/object:Gem::Version
53
- version: '3.9'
47
+ version: '2.7'
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
51
  requirements:
58
52
  - - "~>"
59
53
  - !ruby/object:Gem::Version
60
- version: '3.9'
54
+ version: '2.7'
61
55
  - !ruby/object:Gem::Dependency
62
- name: rspec-its
56
+ name: htmlentities
63
57
  requirement: !ruby/object:Gem::Requirement
64
58
  requirements:
65
59
  - - "~>"
66
60
  - !ruby/object:Gem::Version
67
- version: '1.3'
61
+ version: '4.3'
68
62
  type: :development
69
63
  prerelease: false
70
64
  version_requirements: !ruby/object:Gem::Requirement
71
65
  requirements:
72
66
  - - "~>"
73
67
  - !ruby/object:Gem::Version
74
- version: '1.3'
68
+ version: '4.3'
75
69
  - !ruby/object:Gem::Dependency
76
- name: rdf-isomorphic
70
+ name: rspec
77
71
  requirement: !ruby/object:Gem::Requirement
78
72
  requirements:
79
73
  - - "~>"
80
74
  - !ruby/object:Gem::Version
81
- version: '3.1'
75
+ version: '3.10'
82
76
  type: :development
83
77
  prerelease: false
84
78
  version_requirements: !ruby/object:Gem::Requirement
85
79
  requirements:
86
80
  - - "~>"
87
81
  - !ruby/object:Gem::Version
88
- version: '3.1'
82
+ version: '3.10'
89
83
  - !ruby/object:Gem::Dependency
90
- name: json-ld
84
+ name: rspec-its
91
85
  requirement: !ruby/object:Gem::Requirement
92
86
  requirements:
93
87
  - - "~>"
94
88
  - !ruby/object:Gem::Version
95
- version: '3.1'
89
+ version: '1.3'
96
90
  type: :development
97
91
  prerelease: false
98
92
  version_requirements: !ruby/object:Gem::Requirement
99
93
  requirements:
100
94
  - - "~>"
101
95
  - !ruby/object:Gem::Version
102
- version: '3.1'
96
+ version: '1.3'
103
97
  - !ruby/object:Gem::Dependency
104
- name: rdf-spec
98
+ name: rdf-isomorphic
105
99
  requirement: !ruby/object:Gem::Requirement
106
100
  requirements:
107
101
  - - "~>"
108
102
  - !ruby/object:Gem::Version
109
- version: '3.1'
103
+ version: '3.2'
110
104
  type: :development
111
105
  prerelease: false
112
106
  version_requirements: !ruby/object:Gem::Requirement
113
107
  requirements:
114
108
  - - "~>"
115
109
  - !ruby/object:Gem::Version
116
- version: '3.1'
110
+ version: '3.2'
117
111
  - !ruby/object:Gem::Dependency
118
- name: rdf-vocab
112
+ name: json-ld
119
113
  requirement: !ruby/object:Gem::Requirement
120
114
  requirements:
121
115
  - - "~>"
122
116
  - !ruby/object:Gem::Version
123
- version: '3.1'
117
+ version: '3.2'
124
118
  type: :development
125
119
  prerelease: false
126
120
  version_requirements: !ruby/object:Gem::Requirement
127
121
  requirements:
128
122
  - - "~>"
129
123
  - !ruby/object:Gem::Version
130
- version: '3.1'
124
+ version: '3.2'
131
125
  - !ruby/object:Gem::Dependency
132
- name: rake
126
+ name: rdf-spec
133
127
  requirement: !ruby/object:Gem::Requirement
134
128
  requirements:
135
129
  - - "~>"
136
130
  - !ruby/object:Gem::Version
137
- version: '13.0'
131
+ version: '3.2'
138
132
  type: :development
139
133
  prerelease: false
140
134
  version_requirements: !ruby/object:Gem::Requirement
141
135
  requirements:
142
136
  - - "~>"
143
137
  - !ruby/object:Gem::Version
144
- version: '13.0'
138
+ version: '3.2'
145
139
  - !ruby/object:Gem::Dependency
146
- name: yard
140
+ name: rdf-vocab
147
141
  requirement: !ruby/object:Gem::Requirement
148
142
  requirements:
149
143
  - - "~>"
150
144
  - !ruby/object:Gem::Version
151
- version: 0.9.20
145
+ version: '3.2'
152
146
  type: :development
153
147
  prerelease: false
154
148
  version_requirements: !ruby/object:Gem::Requirement
155
149
  requirements:
156
150
  - - "~>"
157
151
  - !ruby/object:Gem::Version
158
- version: 0.9.20
152
+ version: '3.2'
159
153
  description: RDF::Turtle is an Turtle reader/writer for the RDF.rb library suite.
160
154
  email: public-rdf-ruby@w3.org
161
155
  executables: []
@@ -178,8 +172,13 @@ files:
178
172
  homepage: https://github.com/ruby-rdf/rdf-turtle
179
173
  licenses:
180
174
  - Unlicense
181
- metadata: {}
182
- post_install_message:
175
+ metadata:
176
+ documentation_uri: https://ruby-rdf.github.io/rdf-turtle
177
+ bug_tracker_uri: https://github.com/ruby-rdf/rdf-turtle/issues
178
+ homepage_uri: https://github.com/ruby-rdf/rdf-turtle
179
+ mailing_list_uri: https://lists.w3.org/Archives/Public/public-rdf-ruby/
180
+ source_code_uri: https://github.com/ruby-rdf/rdf-turtle
181
+ post_install_message:
183
182
  rdoc_options: []
184
183
  require_paths:
185
184
  - lib
@@ -187,15 +186,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
187
186
  requirements:
188
187
  - - ">="
189
188
  - !ruby/object:Gem::Version
190
- version: '2.4'
189
+ version: '2.6'
191
190
  required_rubygems_version: !ruby/object:Gem::Requirement
192
191
  requirements:
193
192
  - - ">="
194
193
  - !ruby/object:Gem::Version
195
194
  version: '0'
196
195
  requirements: []
197
- rubygems_version: 3.1.3
198
- signing_key:
196
+ rubygems_version: 3.3.3
197
+ signing_key:
199
198
  specification_version: 4
200
199
  summary: Turtle reader/writer for Ruby.
201
200
  test_files: []