rdf-turtle 3.0.5 → 3.1.3

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: 42fd402701c100deb4335bf42ef55682de098f3c1967063a42c5a67d7cbd5282
4
- data.tar.gz: 390e3920be8a0a7fc722f08e670a7f45a99982085795df4badca0334a5df27b5
3
+ metadata.gz: 105a5880b1227824c5a05c14639512dad99a1501eb8e4a2590f8c02ac716aa32
4
+ data.tar.gz: 76b28dd1fb554b09fd0bd34ecea9e62cdd510748ac8efc5eee9a2368b6c18fa3
5
5
  SHA512:
6
- metadata.gz: 40bdf89cc4dc83e8dc8f032912772a91c446759f1f842022ecfd5d159cf84a5c9fce0f48d51a4a1220f769398f06e297e1f3fea99c2da654bd01cc20c9863db0
7
- data.tar.gz: 4a243b9d8426f08ee16e1d31c634d6dbf3d8ce9f5c5f6f9816a8cc04a3ad92dcc1409df91ce8c365677faf0fbf6503250a28a224e903089995e9c367fdb60d41
6
+ metadata.gz: 0f0ff42a2229ef95aa8b0473f39f5341ee9dc6d05a9006eca3a0b7653b661e75481a859f7d0cb3cba2fd6a58e0d1108ec9212185bec63b979cd6f071d08c0006
7
+ data.tar.gz: e866f62804abda425c13145304443fd385632c9f1a97666614b339bf4a2678149c2966e79d5dfd7629f326fa4c515aac756b808870eb3d64e13b3e5798b0fab8
data/History CHANGED
@@ -30,7 +30,7 @@
30
30
  * Replace remaining uses of SPARQL with RDF::Turtle or RDF::LL1
31
31
 
32
32
  ### 0.0.3
33
- * Completed RDF 1.1 Turtle based on http://www.w3.org/TR/2011/WD-turtle-20110809/
33
+ * Completed RDF 1.1 Turtle based on https://www.w3.org/TR/2011/WD-turtle-20110809/
34
34
  * Reader
35
35
  * Writer
36
36
  * Issues:
data/README.md CHANGED
@@ -2,10 +2,10 @@
2
2
 
3
3
  [Turtle][] reader/writer for [RDF.rb][RDF.rb] .
4
4
 
5
- [![Gem Version](https://badge.fury.io/rb/rdf-turtle.png)](http://badge.fury.io/rb/rdf-turtle)
6
- [![Build Status](https://travis-ci.org/ruby-rdf/rdf-turtle.png?branch=master)](http://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)
8
- [![Dependency Status](https://gemnasium.com/ruby-rdf/rdf-turtle.png)](https://gemnasium.com/ruby-rdf/rdf-turtle)
5
+ [![Gem Version](https://badge.fury.io/rb/rdf-turtle.png)](https://badge.fury.io/rb/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)](https://coveralls.io/github/ruby-rdf/rdf-turtle)
8
+ [![Gitter chat](https://badges.gitter.im/ruby-rdf/rdf.png)](https://gitter.im/ruby-rdf/rdf)
9
9
 
10
10
  ## Description
11
11
  This is a [Ruby][] implementation of a [Turtle][] parser for [RDF.rb][].
@@ -15,10 +15,11 @@ RDF::Turtle parses [Turtle][Turtle] and [N-Triples][N-Triples] into statements o
15
15
 
16
16
  Install with `gem install rdf-turtle`
17
17
 
18
- * 100% free and unencumbered [public domain](http://unlicense.org/) software.
18
+ * 100% free and unencumbered [public domain](https://unlicense.org/) software.
19
19
  * Implements a complete parser for [Turtle][].
20
20
  * Compatible with Ruby >= 2.2.2.
21
21
  * Optional streaming writer, to serialize large graphs
22
+ * Provisional support for [Turtle*][RDF*].
22
23
 
23
24
  ## Usage
24
25
  Instantiate a reader from a local file:
@@ -35,6 +36,60 @@ Write a graph to a file:
35
36
  writer << graph
36
37
  end
37
38
 
39
+ ## Turtle* (RDFStar)
40
+
41
+ Both reader and writer include provisional support for [Turtle*][RDF*].
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`.
44
+
45
+ **Note: This feature is subject to change or elimination as the standards process progresses.**
46
+
47
+ ### Serializing a Graph containing embedded statements
48
+
49
+ require 'rdf/turtle'
50
+ statement = RDF::Statement(RDF::URI('bob'), RDF::Vocab::FOAF.age, RDF::Literal(23))
51
+ graph = RDF::Graph.new << [statement, RDF::URI("ex:certainty"), RDF::Literal(0.9)]
52
+ graph.dump(:ttl, validate: false, standard_prefixes: true)
53
+ # => '<<<bob> foaf:age 23>> <ex:certainty> 9.0e-1 .'
54
+
55
+ ### Reading a Graph containing embedded statements
56
+
57
+ By default, the Turtle reader will reject a document containing a subject resource.
58
+
59
+ ttl = %(
60
+ @prefix foaf: <http://xmlns.com/foaf/0.1/> .
61
+ @prefix ex: <http://example.com/> .
62
+ <<<bob> foaf:age 23>> ex:certainty 9.0e-1 .
63
+ )
64
+ graph = RDF::Graph.new do |graph|
65
+ RDF::Turtle::Reader.new(ttl) {|reader| graph << reader}
66
+ end
67
+ # => RDF::ReaderError
68
+
69
+ Readers support a boolean valued `rdfstar` option; only one statement is asserted, although the reified statement is contained within the graph.
70
+
71
+ graph = RDF::Graph.new do |graph|
72
+ RDF::Turtle::Reader.new(ttl, rdfstar: true) {|reader| graph << reader}
73
+ end
74
+ graph.count #=> 1
75
+
76
+ ### Reading a Graph containing statement annotations
77
+
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.
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
+ )
86
+ graph = RDF::Graph.new do |graph|
87
+ RDF::Turtle::Reader.new(ttl) {|reader| graph << reader}
88
+ end
89
+ # => RDF::ReaderError
90
+
91
+ Note that this requires the `rdfstar` option to be se.
92
+
38
93
  ## Documentation
39
94
  Full documentation available on [Rubydoc.info][Turtle doc]
40
95
 
@@ -85,22 +140,22 @@ This version uses a hand-written parser using the Lexer from the [EBNF][] gem in
85
140
 
86
141
  ## Dependencies
87
142
 
88
- * [Ruby](http://ruby-lang.org/) (>= 2.2)
89
- * [RDF.rb](http://rubygems.org/gems/rdf) (~> 3.0)
143
+ * [Ruby](https://ruby-lang.org/) (>= 2.4)
144
+ * [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.1)
90
145
  * [EBNF][] (~> 1.1)
91
146
 
92
147
  ## Installation
93
148
 
94
- The recommended installation method is via [RubyGems](http://rubygems.org/).
149
+ The recommended installation method is via [RubyGems](https://rubygems.org/).
95
150
  To install the latest official release of the `RDF::Turtle` gem, do:
96
151
 
97
152
  % [sudo] gem install rdf-turtle
98
153
 
99
154
  ## Mailing List
100
- * <http://lists.w3.org/Archives/Public/public-rdf-ruby/>
155
+ * <https://lists.w3.org/Archives/Public/public-rdf-ruby/>
101
156
 
102
157
  ## Author
103
- * [Gregg Kellogg](http://github.com/gkellogg) - <http://greggkellogg.net/>
158
+ * [Gregg Kellogg](https://github.com/gkellogg) - <https://greggkellogg.net/>
104
159
 
105
160
  ## Contributing
106
161
  This repository uses [Git Flow](https://github.com/nvie/gitflow) to mange development and release activity. All submissions _must_ be on a feature branch based on the _develop_ branch to ease staging and integration.
@@ -115,24 +170,27 @@ This repository uses [Git Flow](https://github.com/nvie/gitflow) to mange develo
115
170
  list in the the `README`. Alphabetical order applies.
116
171
  * Do note that in order for us to merge any non-trivial changes (as a rule
117
172
  of thumb, additions larger than about 15 lines of code), we need an
118
- 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.
119
176
 
120
177
  ## License
121
178
  This is free and unencumbered public domain software. For more information,
122
- see <http://unlicense.org/> or the accompanying {file:UNLICENSE} file.
123
-
124
- A copy of the [Turtle EBNF][] and derived parser files are included in the repository, which are not covered under the UNLICENSE. These files are covered via the [W3C Document License](http://www.w3.org/Consortium/Legal/2002/copyright-documents-20021231).
125
-
126
- [Ruby]: http://ruby-lang.org/
127
- [RDF]: http://www.w3.org/RDF/
128
- [YARD]: http://yardoc.org/
129
- [YARD-GS]: http://rubydoc.info/docs/yard/file/docs/GettingStarted.md
130
- [PDD]: http://lists.w3.org/Archives/Public/public-rdf-ruby/2010May/0013.html
131
- [RDF.rb]: http://rubydoc.info/github/ruby-rdf/rdf
132
- [EBNF]: http://rubygems.org/gems/ebnf
133
- [Backports]: http://rubygems.org/gems/backports
134
- [N-Triples]: http://www.w3.org/TR/rdf-testcases/#ntriples
135
- [Turtle]: http://www.w3.org/TR/2012/WD-turtle-20120710/
136
- [Turtle doc]: http://rubydoc.info/github/ruby-rdf/rdf-turtle/master/file/README.md
137
- [Turtle EBNF]: http://dvcs.w3.org/hg/rdf/file/default/rdf-turtle/turtle.bnf
179
+ see <https://unlicense.org/> or the accompanying {file:UNLICENSE} file.
180
+
181
+ A copy of the [Turtle EBNF][] and derived parser files are included in the repository, which are not covered under the UNLICENSE. These files are covered via the [W3C Document License](https://www.w3.org/Consortium/Legal/2002/copyright-documents-20021231).
182
+
183
+ [Ruby]: https://ruby-lang.org/
184
+ [RDF]: https://www.w3.org/RDF/
185
+ [YARD]: https://yardoc.org/
186
+ [YARD-GS]: https://rubydoc.info/docs/yard/file/docs/GettingStarted.md
187
+ [PDD]: https://unlicense.org/#unlicensing-contributions
188
+ [RDF.rb]: https://rubydoc.info/github/ruby-rdf/rdf
189
+ [EBNF]: https://rubygems.org/gems/ebnf
190
+ [Backports]: https://rubygems.org/gems/backports
191
+ [N-Triples]: https://www.w3.org/TR/rdf-testcases/#ntriples
192
+ [Turtle]: https://www.w3.org/TR/2012/WD-turtle-20120710/
193
+ [RDF*]: https://w3c.github.io/rdf-star/rdf-star-cg-spec.html
194
+ [Turtle doc]: https://rubydoc.info/github/ruby-rdf/rdf-turtle/master/file/README.md
195
+ [Turtle EBNF]: https://dvcs.w3.org/hg/rdf/file/default/rdf-turtle/turtle.bnf
138
196
  [Freebase Dumps]: https://developers.google.com/freebase/data
data/UNLICENSE CHANGED
@@ -21,4 +21,4 @@ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
21
  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
22
  OTHER DEALINGS IN THE SOFTWARE.
23
23
 
24
- For more information, please refer to <http://unlicense.org/>
24
+ For more information, please refer to <https://unlicense.org/>
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.0.5
1
+ 3.1.3
@@ -15,10 +15,10 @@ module RDF
15
15
  # end
16
16
  # end
17
17
  #
18
- # @see http://rubydoc.info/github/ruby-rdf/rdf/master/frames
19
- # @see http://dvcs.w3.org/hg/rdf/raw-file/default/rdf-turtle/index.html
18
+ # @see https://rubydoc.info/github/ruby-rdf/rdf/master/frames
19
+ # @see https://dvcs.w3.org/hg/rdf/raw-file/default/rdf-turtle/index.html
20
20
  #
21
- # @author [Gregg Kellogg](http://greggkellogg.net/)
21
+ # @author [Gregg Kellogg](https://greggkellogg.net/)
22
22
  module Turtle
23
23
  require 'rdf/turtle/format'
24
24
  autoload :Reader, 'rdf/turtle/reader'
@@ -14,7 +14,7 @@ module RDF::Turtle
14
14
  # @example Obtaining serialization format file extension mappings
15
15
  # RDF::Format.file_extensions #=> {ttl: "text/turtle"}
16
16
  #
17
- # @see http://www.w3.org/TR/rdf-testcases/#ntriples
17
+ # @see https://www.w3.org/TR/rdf-testcases/#ntriples
18
18
  class Format < RDF::Format
19
19
  content_type 'text/turtle',
20
20
  extension: :ttl,
@@ -55,7 +55,7 @@ module RDF::Turtle
55
55
  ##
56
56
  # Read a PNAME of the form `prefix:suffix`.
57
57
  # @return [RDF::URI]
58
- def read_pname(options = {})
58
+ def read_pname(**options)
59
59
  if pname_str = match(/^(\w+:\S+)/)
60
60
  ns, suffix = pname_str.split(':', 2)
61
61
  if suffix[-1,1] == "."
@@ -74,7 +74,7 @@ module RDF::Turtle
74
74
 
75
75
  ##
76
76
  # @return [RDF::Literal]
77
- # @see http://www.w3.org/TR/rdf-testcases/#ntrip_grammar (literal)
77
+ # @see https://www.w3.org/TR/rdf-testcases/#ntrip_grammar (literal)
78
78
  def read_literal
79
79
  if literal_str = match(LITERAL_PLAIN)
80
80
  literal_str = self.class.unescape(literal_str)
@@ -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 http://www.rubydoc.info/github/ruby-rdf/rdf/RDF/Reader#options-class_method
43
+ # @see https://www.rubydoc.info/github/ruby-rdf/rdf/RDF/Reader#options-class_method
37
44
  def self.options
38
45
  super + [
39
46
  RDF::CLI::Option.new(
@@ -48,14 +55,14 @@ module RDF::Turtle
48
55
  # Redirect for Freebase Reader
49
56
  #
50
57
  # @private
51
- def self.new(input = nil, options = {}, &block)
58
+ def self.new(input = nil, **options, &block)
52
59
  klass = if options[:freebase]
53
60
  FreebaseReader
54
61
  else
55
62
  self
56
63
  end
57
64
  reader = klass.allocate
58
- reader.send(:initialize, input, options, &block)
65
+ reader.send(:initialize, input, **options, &block)
59
66
  reader
60
67
  end
61
68
 
@@ -82,23 +89,23 @@ module RDF::Turtle
82
89
  # @option options [Boolean] :freebase (false)
83
90
  # Use optimized Freebase reader
84
91
  # @return [RDF::Turtle::Reader]
85
- def initialize(input = nil, options = {}, &block)
92
+ def initialize(input = nil, **options, &block)
86
93
  super do
87
94
  @options = {
88
95
  anon_base: "b0",
89
96
  whitespace: WS,
90
- log_depth: 0,
97
+ depth: 0,
91
98
  }.merge(@options)
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
- @lexer = EBNF::LL1::Lexer.new(input, self.class.patterns, @options)
108
+ @lexer = EBNF::LL1::Lexer.new(input, self.class.patterns, **@options)
102
109
 
103
110
  if block_given?
104
111
  case block.arity
@@ -163,7 +170,7 @@ module RDF::Turtle
163
170
  # @return [RDF::Statement] Added statement
164
171
  # @raise [RDF::ReaderError] Checks parameter types and raises if they are incorrect if parsing mode is _validate_.
165
172
  def add_statement(production, statement)
166
- error("Statement is invalid: #{statement.inspect.inspect}", production: produciton) if validate? && statement.invalid?
173
+ error("Statement is invalid: #{statement.inspect}", production: produciton) if validate? && statement.invalid?
167
174
  @callback.call(statement) if statement.subject &&
168
175
  statement.predicate &&
169
176
  statement.object &&
@@ -184,14 +191,14 @@ module RDF::Turtle
184
191
  end
185
192
 
186
193
  # Create a literal
187
- def literal(value, options = {})
188
- log_debug("literal") do
194
+ def literal(value, **options)
195
+ debug("literal", depth: @options[:depth]) do
189
196
  "value: #{value.inspect}, " +
190
197
  "options: #{options.inspect}, " +
191
198
  "validate: #{validate?.inspect}, " +
192
199
  "c14n?: #{canonicalize?.inspect}"
193
200
  end
194
- RDF::Literal.new(value, options.merge(validate: validate?, canonicalize: canonicalize?))
201
+ RDF::Literal.new(value, validate: validate?, canonicalize: canonicalize?, **options)
195
202
  rescue ArgumentError => e
196
203
  error("Argument Error #{e.message}", production: :literal, token: @lexer.first)
197
204
  end
@@ -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") {"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") {"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,6 +373,7 @@ module RDF::Turtle
362
373
  read_iri ||
363
374
  read_BlankNode ||
364
375
  read_collection ||
376
+ read_embTriple ||
365
377
  error( "Expected subject", production: :subject, token: @lexer.first)
366
378
  end
367
379
  end
@@ -373,7 +385,8 @@ module RDF::Turtle
373
385
  read_BlankNode ||
374
386
  read_collection ||
375
387
  read_blankNodePropertyList ||
376
- read_literal
388
+ read_literal ||
389
+ read_embTriple
377
390
 
378
391
  add_statement(:object, RDF::Statement(subject, predicate, object)) if subject && predicate
379
392
  object
@@ -381,13 +394,71 @@ module RDF::Turtle
381
394
  end
382
395
  end
383
396
 
397
+ # Read an RDF* reified statement
398
+ # @return [RDF::Statement]
399
+ def read_embTriple
400
+ return unless @options[:rdfstar]
401
+ if @lexer.first.value == '<<'
402
+ prod(:embTriple) do
403
+ @lexer.shift # eat <<
404
+ subject = read_embSubject || error("Failed to parse subject", production: :embTriple, token: @lexer.first)
405
+ predicate = read_verb || error("Failed to parse predicate", production: :embTriple, token: @lexer.first)
406
+ object = read_embObject || error("Failed to parse object", production: :embTriple, token: @lexer.first)
407
+ unless @lexer.first.value == '>>'
408
+ error("Failed to end of embedded triple", production: :embTriple, token: @lexer.first)
409
+ end
410
+ @lexer.shift
411
+ statement = RDF::Statement(subject, predicate, object)
412
+ statement
413
+ end
414
+ end
415
+ end
416
+
417
+ # @return [RDF::Resource]
418
+ def read_embSubject
419
+ prod(:embSubject) do
420
+ read_iri ||
421
+ read_BlankNode ||
422
+ read_embTriple ||
423
+ error( "Expected embedded subject", production: :embSubject, token: @lexer.first)
424
+ end
425
+ end
426
+
427
+ # @return [RDF::Term]
428
+ def read_embObject(subject = nil, predicate = nil)
429
+ prod(:embObject) do
430
+ read_iri ||
431
+ read_BlankNode ||
432
+ read_literal ||
433
+ read_embTriple
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)
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
+
384
455
  # @return [RDF::Literal]
385
456
  def read_literal
386
457
  error("Unexpected end of file", production: :literal) unless token = @lexer.first
387
458
  case token.type || token.value
388
459
  when :INTEGER then prod(:literal) {literal(@lexer.shift.value, datatype: RDF::XSD.integer)}
389
460
  when :DECIMAL
390
- prod(:litearl) do
461
+ prod(:literal) do
391
462
  value = @lexer.shift.value
392
463
  value = "0#{value}" if value.start_with?(".")
393
464
  literal(value, datatype: RDF::XSD.decimal)
@@ -431,7 +502,7 @@ module RDF::Turtle
431
502
  if token === '['
432
503
  prod(:blankNodePropertyList, %{]}) do
433
504
  @lexer.shift
434
- log_info("blankNodePropertyList") {"token: #{token.inspect}"}
505
+ progress("blankNodePropertyList", depth: options[:depth]) {"token: #{token.inspect}"}
435
506
  node = bnode
436
507
  read_predicateObjectList(node)
437
508
  error("blankNodePropertyList", "Expected closing ']'") unless @lexer.first === ']'
@@ -447,7 +518,7 @@ module RDF::Turtle
447
518
  prod(:collection, %{)}) do
448
519
  @lexer.shift
449
520
  token = @lexer.first
450
- log_info("collection") {"token: #{token.inspect}"}
521
+ progress("collection", depth: options[:depth]) {"token: #{token.inspect}"}
451
522
  objects = []
452
523
  while object = read_object
453
524
  objects << object
@@ -483,8 +554,8 @@ module RDF::Turtle
483
554
 
484
555
  def prod(production, recover_to = [])
485
556
  @prod_stack << {prod: production, recover_to: recover_to}
486
- @options[:log_depth] += 1
487
- log_recover("#{production}(start)") {"token: #{@lexer.first.inspect}"}
557
+ @options[:depth] += 1
558
+ recover("#{production}(start)", depth: options[:depth], token: @lexer.first)
488
559
  yield
489
560
  rescue EBNF::LL1::Lexer::Error, SyntaxError, Recovery => e
490
561
  # Lexer encountered an illegal token or the parser encountered
@@ -504,13 +575,13 @@ module RDF::Turtle
504
575
  end
505
576
  end
506
577
  raise EOFError, "End of input found when recovering" if @lexer.first.nil?
507
- log_debug("recovery", "current token: #{@lexer.first.inspect}")
578
+ debug("recovery", "current token: #{@lexer.first.inspect}", depth: options[:depth])
508
579
 
509
580
  unless e.is_a?(Recovery)
510
581
  # Get the list of follows for this sequence, this production and the stacked productions.
511
- log_debug("recovery", "stack follows:")
582
+ debug("recovery", "stack follows:", depth: options[:depth])
512
583
  @prod_stack.reverse.each do |prod|
513
- log_debug("recovery", level: 4) {" #{prod[:prod]}: #{prod[:recover_to].inspect}"}
584
+ debug("recovery", level: 4, depth: options[:depth]) {" #{prod[:prod]}: #{prod[:recover_to].inspect}"}
514
585
  end
515
586
  end
516
587
 
@@ -520,9 +591,9 @@ module RDF::Turtle
520
591
  # Skip tokens until one is found in follows
521
592
  while (token = (@lexer.first rescue @lexer.recover)) && follows.none? {|t| token === t}
522
593
  skipped = @lexer.shift
523
- log_debug("recovery") {"skip #{skipped.inspect}"}
594
+ debug("recovery", depth: options[:depth]) {"skip #{skipped.inspect}"}
524
595
  end
525
- log_debug("recovery") {"found #{token.inspect} in follows"}
596
+ debug("recovery", depth: options[:depth]) {"found #{token.inspect} in follows"}
526
597
 
527
598
  # Re-raise the error unless token is a follows of this production
528
599
  raise Recovery unless Array(recover_to).any? {|t| token === t}
@@ -530,11 +601,35 @@ module RDF::Turtle
530
601
  # Skip that token to get something reasonable to start the next production with
531
602
  @lexer.shift
532
603
  ensure
533
- log_info("#{production}(finish)")
534
- @options[:log_depth] -= 1
604
+ progress("#{production}(finish)", depth: options[:depth])
605
+ @options[:depth] -= 1
535
606
  @prod_stack.pop
536
607
  end
537
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
+
538
633
  ##
539
634
  # Error information, used as level `0` debug messages.
540
635
  #
@@ -554,7 +649,8 @@ module RDF::Turtle
554
649
  lineno: lineno,
555
650
  token: options[:token],
556
651
  production: options[:production],
557
- exception: SyntaxError)
652
+ depth: options[:depth],
653
+ exception: SyntaxError,)
558
654
  end
559
655
 
560
656
  # Used for internal error recovery
@@ -587,7 +683,7 @@ module RDF::Turtle
587
683
  # @option options [Symbol] :production (nil)
588
684
  # @option options [String] :token (nil)
589
685
  # @option options [Integer] :lineno (nil)
590
- def initialize(message, options = {})
686
+ def initialize(message, **options)
591
687
  @production = options[:production]
592
688
  @token = options[:token]
593
689
  @lineno = options[:lineno] || (@token.lineno if @token.respond_to?(:lineno))
@@ -3,7 +3,7 @@ require 'rdf/turtle/terminals'
3
3
  module RDF::Turtle
4
4
  ##
5
5
  # Streaming writer interface
6
- # @author [Gregg Kellogg](http://greggkellogg.net/)
6
+ # @author [Gregg Kellogg](https://greggkellogg.net/)
7
7
  module StreamingWriter
8
8
  ##
9
9
  # Write out declarations
@@ -28,15 +28,15 @@ module RDF::Turtle
28
28
  if statement.subject != @streaming_subject
29
29
  @output.puts ' .' if @streaming_subject
30
30
  @streaming_subject, @streaming_predicate = statement.subject, statement.predicate
31
- @output.write "#{format_term(statement.subject, options)} "
32
- @output.write "#{format_term(statement.predicate, options)} "
31
+ @output.write "#{format_term(statement.subject, **options)} "
32
+ @output.write "#{format_term(statement.predicate, **options)} "
33
33
  elsif statement.predicate != @streaming_predicate
34
34
  @streaming_predicate = statement.predicate
35
- @output.write ";\n#{indent(1)}#{format_term(statement.predicate, options)} "
35
+ @output.write ";\n#{indent(1)}#{format_term(statement.predicate, **options)} "
36
36
  else
37
37
  @output.write ",\n#{indent(2)}"
38
38
  end
39
- @output.write("#{format_term(statement.object, options)}")
39
+ @output.write("#{format_term(statement.object, **options)}")
40
40
  end
41
41
 
42
42
  ##
@@ -1,9 +1,9 @@
1
+ # encoding: utf-8
1
2
  require 'ebnf/ll1/lexer'
2
3
 
3
4
  module RDF::Turtle
4
5
  module Terminals
5
6
  # Definitions of token regular expressions used for lexical analysis
6
-
7
7
  ##
8
8
  # Unicode regular expressions for Ruby 1.9+ with the Oniguruma engine.
9
9
  U_CHARS1 = Regexp.compile(<<-EOS.gsub(/\s+/, ''))
@@ -12,66 +12,66 @@ module RDF::Turtle
12
12
  [\\u2070-\\u218F]|[\\u2C00-\\u2FEF]|[\\u3001-\\uD7FF]|
13
13
  [\\uF900-\\uFDCF]|[\\uFDF0-\\uFFFD]|[\\u{10000}-\\u{EFFFF}]
14
14
  EOS
15
- U_CHARS2 = Regexp.compile("\\u00B7|[\\u0300-\\u036F]|[\\u203F-\\u2040]").freeze
16
- IRI_RANGE = Regexp.compile("[[^<>\"{}|^`\\\\]&&[^\\x00-\\x20]]").freeze
15
+ U_CHARS2 = Regexp.compile("\\u00B7|[\\u0300-\\u036F]|[\\u203F-\\u2040]", Regexp::FIXEDENCODING).freeze
16
+ IRI_RANGE = Regexp.compile("[[^<>\"{}|^`\\\\]&&[^\\x00-\\x20]]", Regexp::FIXEDENCODING).freeze
17
17
 
18
18
  # 26
19
19
  UCHAR = EBNF::LL1::Lexer::UCHAR
20
20
  # 170s
21
- PERCENT = /%[0-9A-Fa-f]{2}/.freeze
21
+ PERCENT = /%[0-9A-Fa-f]{2}/u.freeze
22
22
  # 172s
23
- PN_LOCAL_ESC = /\\[_~\.\-\!$\&'\(\)\*\+,;=\/\?\#@%]/.freeze
23
+ PN_LOCAL_ESC = /\\[_~\.\-\!$\&'\(\)\*\+,;=\/\?\#@%]/u.freeze
24
24
  # 169s
25
- PLX = /#{PERCENT}|#{PN_LOCAL_ESC}/.freeze.freeze
25
+ PLX = /#{PERCENT}|#{PN_LOCAL_ESC}/u.freeze
26
26
  # 163s
27
- PN_CHARS_BASE = /[A-Z]|[a-z]|#{U_CHARS1}/.freeze
27
+ PN_CHARS_BASE = /[A-Z]|[a-z]|#{U_CHARS1}/u.freeze
28
28
  # 164s
29
- PN_CHARS_U = /_|#{PN_CHARS_BASE}/.freeze
29
+ PN_CHARS_U = /_|#{PN_CHARS_BASE}/u.freeze
30
30
  # 166s
31
- PN_CHARS = /-|[0-9]|#{PN_CHARS_U}|#{U_CHARS2}/.freeze
32
- PN_LOCAL_BODY = /(?:(?:\.|:|#{PN_CHARS}|#{PLX})*(?:#{PN_CHARS}|:|#{PLX}))?/.freeze
33
- PN_CHARS_BODY = /(?:(?:\.|#{PN_CHARS})*#{PN_CHARS})?/.freeze
31
+ PN_CHARS = /-|[0-9]|#{PN_CHARS_U}|#{U_CHARS2}/u.freeze
32
+ PN_LOCAL_BODY = /(?:(?:\.|:|#{PN_CHARS}|#{PLX})*(?:#{PN_CHARS}|:|#{PLX}))?/u.freeze
33
+ PN_CHARS_BODY = /(?:(?:\.|#{PN_CHARS})*#{PN_CHARS})?/u.freeze
34
34
  # 167s
35
- PN_PREFIX = /#{PN_CHARS_BASE}#{PN_CHARS_BODY}/.freeze
35
+ PN_PREFIX = /#{PN_CHARS_BASE}#{PN_CHARS_BODY}/u.freeze
36
36
  # 168s
37
- PN_LOCAL = /(?:[0-9]|:|#{PN_CHARS_U}|#{PLX})#{PN_LOCAL_BODY}/.freeze
37
+ PN_LOCAL = /(?:[0-9]|:|#{PN_CHARS_U}|#{PLX})#{PN_LOCAL_BODY}/u.freeze
38
38
  # 154s
39
- EXPONENT = /[eE][+-]?[0-9]+/
39
+ EXPONENT = /[eE][+-]?[0-9]+/u.freeze
40
40
  # 159s
41
- ECHAR = /\\[tbnrf\\"']/
41
+ ECHAR = /\\[tbnrf\\"']/u.freeze
42
42
  # 18
43
- IRIREF = /<(?:#{IRI_RANGE}|#{UCHAR})*>/.freeze
43
+ IRIREF = /<(?:#{IRI_RANGE}|#{UCHAR})*>/u.freeze
44
44
  # 139s
45
- PNAME_NS = /#{PN_PREFIX}?:/.freeze
45
+ PNAME_NS = /#{PN_PREFIX}?:/u.freeze
46
46
  # 140s
47
- PNAME_LN = /#{PNAME_NS}#{PN_LOCAL}/.freeze
47
+ PNAME_LN = /#{PNAME_NS}#{PN_LOCAL}/u.freeze
48
48
  # 141s
49
- BLANK_NODE_LABEL = /_:(?:[0-9]|#{PN_CHARS_U})(?:(?:#{PN_CHARS}|\.)*#{PN_CHARS})?/.freeze
49
+ BLANK_NODE_LABEL = /_:(?:[0-9]|#{PN_CHARS_U})(?:(?:#{PN_CHARS}|\.)*#{PN_CHARS})?/u.freeze
50
50
  # 144s
51
- LANGTAG = /@[a-zA-Z]+(?:-[a-zA-Z0-9]+)*/.freeze
51
+ LANGTAG = /@[a-zA-Z]+(?:-[a-zA-Z0-9]+)*/u.freeze
52
52
  # 19
53
- INTEGER = /[+-]?[0-9]+/.freeze
53
+ INTEGER = /[+-]?[0-9]+/u.freeze
54
54
  # 20
55
- DECIMAL = /[+-]?(?:[0-9]*\.[0-9]+)/.freeze
55
+ DECIMAL = /[+-]?(?:[0-9]*\.[0-9]+)/u.freeze
56
56
  # 21
57
- DOUBLE = /[+-]?(?:[0-9]+\.[0-9]*#{EXPONENT}|\.?[0-9]+#{EXPONENT})/.freeze
57
+ DOUBLE = /[+-]?(?:[0-9]+\.[0-9]*#{EXPONENT}|\.?[0-9]+#{EXPONENT})/u.freeze
58
58
  # 22
59
- STRING_LITERAL_SINGLE_QUOTE = /'(?:[^\'\\\n\r]|#{ECHAR}|#{UCHAR})*'/.freeze
59
+ STRING_LITERAL_SINGLE_QUOTE = /'(?:[^\'\\\n\r]|#{ECHAR}|#{UCHAR})*'/u.freeze
60
60
  # 23
61
- STRING_LITERAL_QUOTE = /"(?:[^\"\\\n\r]|#{ECHAR}|#{UCHAR})*"/.freeze
61
+ STRING_LITERAL_QUOTE = /"(?:[^\"\\\n\r]|#{ECHAR}|#{UCHAR})*"/u.freeze
62
62
  # 24
63
- STRING_LITERAL_LONG_SINGLE_QUOTE = /'''(?:(?:'|'')?(?:[^'\\]|#{ECHAR}|#{UCHAR}))*'''/m.freeze
63
+ STRING_LITERAL_LONG_SINGLE_QUOTE = /'''(?:(?:'|'')?(?:[^'\\]|#{ECHAR}|#{UCHAR}))*'''/um.freeze
64
64
  # 25
65
- STRING_LITERAL_LONG_QUOTE = /"""(?:(?:"|"")?(?:[^"\\]|#{ECHAR}|#{UCHAR}))*"""/m.freeze
65
+ STRING_LITERAL_LONG_QUOTE = /"""(?:(?:"|"")?(?:[^"\\]|#{ECHAR}|#{UCHAR}))*"""/um.freeze
66
66
 
67
67
  # 161s
68
- WS = /(?:\s|(?:#[^\n\r]*))+/m.freeze
68
+ WS = /(?:\s|(?:#[^\n\r]*))+/um.freeze
69
69
  # 162s
70
- ANON = /\[#{WS}*\]/m.freeze
70
+ ANON = /\[#{WS}*\]/um.freeze
71
71
  # 28t
72
- PREFIX = /@?prefix/i.freeze
72
+ PREFIX = /@?prefix/ui.freeze
73
73
  # 29t
74
- BASE = /@?base/i.freeze
74
+ BASE = /@?base/ui.freeze
75
75
 
76
76
  end
77
77
  end
@@ -54,7 +54,7 @@ module RDF::Turtle
54
54
  # end
55
55
  # end
56
56
  #
57
- # @author [Gregg Kellogg](http://greggkellogg.net/)
57
+ # @author [Gregg Kellogg](https://greggkellogg.net/)
58
58
  class Writer < RDF::Writer
59
59
  include StreamingWriter
60
60
  include RDF::Util::Logger
@@ -65,7 +65,7 @@ module RDF::Turtle
65
65
 
66
66
  ##
67
67
  # Writer options
68
- # @see http://www.rubydoc.info/github/ruby-rdf/rdf/RDF/Writer#options-class_method
68
+ # @see https://www.rubydoc.info/github/ruby-rdf/rdf/RDF/Writer#options-class_method
69
69
  def self.options
70
70
  super + [
71
71
  RDF::CLI::Option.new(
@@ -123,7 +123,7 @@ module RDF::Turtle
123
123
  # @yieldreturn [void]
124
124
  # @yield [writer]
125
125
  # @yieldparam [RDF::Writer] writer
126
- def initialize(output = $stdout, options = {}, &block)
126
+ def initialize(output = $stdout, **options, &block)
127
127
  @graph = RDF::Graph.new
128
128
  @uri_to_pname = {}
129
129
  @uri_to_prefix = {}
@@ -272,7 +272,7 @@ module RDF::Turtle
272
272
  # @param [RDF::Literal, String, #to_s] literal
273
273
  # @param [Hash{Symbol => Object}] options
274
274
  # @return [String]
275
- def format_literal(literal, options = {})
275
+ def format_literal(literal, **options)
276
276
  case literal
277
277
  when RDF::Literal
278
278
  case @options[:literal_shorthand] && literal.valid? ? literal.datatype : false
@@ -297,7 +297,7 @@ module RDF::Turtle
297
297
  # @param [RDF::URI] uri
298
298
  # @param [Hash{Symbol => Object}] options
299
299
  # @return [String]
300
- def format_uri(uri, options = {})
300
+ def format_uri(uri, **options)
301
301
  md = uri.relativize(base_uri)
302
302
  log_debug("relativize") {"#{uri.to_ntriples} => #{md.inspect}"} if md != uri.to_s
303
303
  md != uri.to_s ? "<#{md}>" : (get_pname(uri) || "<#{uri}>")
@@ -309,10 +309,21 @@ module RDF::Turtle
309
309
  # @param [RDF::Node] node
310
310
  # @param [Hash{Symbol => Object}] options
311
311
  # @return [String]
312
- def format_node(node, options = {})
312
+ def format_node(node, **options)
313
313
  options[:unique_bnodes] ? node.to_unique_base : node.to_base
314
314
  end
315
315
 
316
+ ##
317
+ # Returns an embedded triple.
318
+ #
319
+ # @param [RDF::Statement] statement
320
+ # @param [Hash{Symbol => Object}] options
321
+ # @return [String]
322
+ def format_embTriple(statement, **options)
323
+ log_debug("rdfstar") {"#{statement.to_ntriples}"}
324
+ "<<%s %s %s>>" % statement.to_a.map { |value| format_term(value, **options) }
325
+ end
326
+
316
327
  protected
317
328
  # Output @base and @prefix definitions
318
329
  def start_document
@@ -349,7 +360,7 @@ module RDF::Turtle
349
360
 
350
361
  # Add distinguished classes
351
362
  top_classes.each do |class_uri|
352
- graph.query(predicate: RDF.type, object: class_uri).
363
+ graph.query({predicate: RDF.type, object: class_uri}).
353
364
  map {|st| st.subject}.
354
365
  sort.
355
366
  uniq.
@@ -363,16 +374,16 @@ module RDF::Turtle
363
374
  # Mark as seen lists that are part of another list
364
375
  @lists.values.map(&:statements).
365
376
  flatten.each do |st|
366
- seen[st.object] if @lists.has_key?(st.object)
377
+ seen[st.object] = true if @lists.key?(st.object)
367
378
  end
368
379
 
369
- # List elements which are bnodes should not be targets for top-level serialization
370
- list_elements = @lists.values.map(&:to_a).flatten.select(&:node?).compact
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
371
382
 
372
- # Sort subjects by resources over bnodes, ref_counts and the subject URI itself
383
+ # Sort subjects by resources and statements over bnodes, ref_counts and the subject URI itself
373
384
  recursable = (@subjects.keys - list_elements).
374
385
  select {|s| !seen.include?(s)}.
375
- map {|r| [r.node? ? 1 : 0, ref_count(r), r]}.
386
+ map {|r| [r.node? ? 2 : (r.statement? ? 1 : 0), ref_count(r), r]}.
376
387
  sort
377
388
 
378
389
  subjects + recursable.map{|r| r.last}
@@ -457,8 +468,8 @@ module RDF::Turtle
457
468
 
458
469
  # Can subject be represented as a blankNodePropertyList?
459
470
  def blankNodePropertyList?(resource, position)
460
- resource.node? &&
461
- !is_valid_list?(resource) &&
471
+ !resource.statement? && resource.node? &&
472
+ !collection?(resource) &&
462
473
  (!is_done?(resource) || position == :subject) &&
463
474
  ref_count(resource) == (position == :object ? 1 : 0)
464
475
  end
@@ -496,35 +507,33 @@ module RDF::Turtle
496
507
  private
497
508
 
498
509
  # Checks if l is a valid RDF list, i.e. no nodes have other properties.
499
- def is_valid_list?(l)
500
- #log_debug("is_valid_list?") {l.inspect}
501
- return @lists[l] && @lists[l].valid?
502
- end
503
-
504
- def do_list(l, position)
505
- list = @lists[l]
506
- log_debug("do_list") {list.inspect}
507
- subject_done(RDF.nil)
508
- index = 0
509
- list.each_statement do |st|
510
- next unless st.predicate == RDF.first
511
- log_debug {" list this: #{st.subject} first: #{st.object}[#{position}]"}
512
- @output.write(" ") if index > 0
513
- path(st.object, position)
514
- subject_done(st.subject)
515
- position = :object
516
- index += 1
517
- end
510
+ def collection?(l)
511
+ #log_debug("collection?") {l.inspect}
512
+ return @lists.key?(l)
518
513
  end
519
514
 
520
515
  def collection(node, position)
521
- return false if !is_valid_list?(node)
516
+ return false if !collection?(node)
522
517
  return false if position == :subject && ref_count(node) > 0
523
518
  return false if position == :object && prop_count(node) > 0
524
519
  #log_debug("collection") {"#{node.to_ntriples}, #{position}"}
525
520
 
526
521
  @output.write("(")
527
- log_depth {do_list(node, position)}
522
+ log_depth do
523
+ list = @lists[node]
524
+ log_debug("collection") {list.inspect}
525
+ subject_done(RDF.nil)
526
+ index = 0
527
+ list.each_statement do |st|
528
+ next unless st.predicate == RDF.first
529
+ log_debug {" list this: #{st.subject} first: #{st.object}[#{position}]"}
530
+ @output.write(" ") if index > 0
531
+ path(st.object, position)
532
+ subject_done(st.subject)
533
+ position = :object
534
+ index += 1
535
+ end
536
+ end
528
537
  @output.write(')')
529
538
  end
530
539
 
@@ -546,7 +555,7 @@ module RDF::Turtle
546
555
  l = if resource == RDF.nil
547
556
  "()"
548
557
  else
549
- format_term(resource, options)
558
+ format_term(resource, **options)
550
559
  end
551
560
  @output.write(l)
552
561
  end
@@ -557,7 +566,7 @@ module RDF::Turtle
557
566
  log_debug("path") do
558
567
  "#{resource.to_ntriples}, " +
559
568
  "pos: #{position}, " +
560
- "()?: #{is_valid_list?(resource)}, " +
569
+ "()?: #{collection?(resource)}, " +
561
570
  "[]?: #{blankNodePropertyList?(resource, position)}, " +
562
571
  "rc: #{ref_count(resource)}"
563
572
  end
@@ -577,7 +586,7 @@ module RDF::Turtle
577
586
  end
578
587
 
579
588
  # Render an objectList having a common subject and predicate
580
- def objectList(objects)
589
+ def objectList(subject, predicate, objects)
581
590
  log_debug("objectList") {objects.inspect}
582
591
  return if objects.empty?
583
592
 
@@ -588,6 +597,15 @@ module RDF::Turtle
588
597
  @output.write ",\n#{indent(4)}"
589
598
  end
590
599
  path(obj, :object)
600
+
601
+ # If subject, predicate, and object are embedded, write those bits out too.
602
+ emb = RDF::Statement(subject, predicate, obj)
603
+ if !@graph.query({subject: emb}).empty?
604
+ @output.write ' {| '
605
+ predicateObjectList(emb, true)
606
+ @output.write ' |}'
607
+ subject_done(emb)
608
+ end
591
609
  end
592
610
  end
593
611
 
@@ -595,22 +613,23 @@ module RDF::Turtle
595
613
  # @return [Integer] the number of properties serialized
596
614
  def predicateObjectList(subject, from_bpl = false)
597
615
  properties = {}
598
- @graph.query(subject: subject) do |st|
616
+ @graph.query({subject: subject}) do |st|
599
617
  (properties[st.predicate.to_s] ||= []) << st.object
600
618
  end
601
619
 
602
620
  prop_list = sort_properties(properties)
603
- prop_list -= [RDF.first.to_s, RDF.rest.to_s] if @lists.include?(subject)
621
+ prop_list -= [RDF.first.to_s, RDF.rest.to_s] if @lists.key?(subject)
604
622
  log_debug("predicateObjectList") {prop_list.inspect}
605
623
  return 0 if prop_list.empty?
606
624
 
607
625
  @output.write("\n#{indent(2)}") if properties.keys.length > 1 && from_bpl
608
626
  prop_list.each_with_index do |prop, i|
609
627
  begin
628
+ pred = RDF::URI.intern(prop)
610
629
  @output.write(";\n#{indent(2)}") if i > 0
611
- predicate(RDF::URI.intern(prop))
630
+ predicate(pred)
612
631
  @output.write(" ")
613
- objectList(properties[prop])
632
+ objectList(subject, pred, properties[prop])
614
633
  end
615
634
  end
616
635
  properties.keys.length
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.5
4
+ version: 3.1.3
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: 2019-02-10 00:00:00.000000000 Z
11
+ date: 2020-12-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdf
@@ -16,146 +16,146 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '3.0'
19
+ version: '3.1'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 3.1.8
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
27
  - - "~>"
25
28
  - !ruby/object:Gem::Version
26
- version: '3.0'
29
+ version: '3.1'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 3.1.8
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: ebnf
29
35
  requirement: !ruby/object:Gem::Requirement
30
36
  requirements:
31
37
  - - "~>"
32
38
  - !ruby/object:Gem::Version
33
- version: '1.1'
39
+ version: '2.1'
34
40
  type: :runtime
35
41
  prerelease: false
36
42
  version_requirements: !ruby/object:Gem::Requirement
37
43
  requirements:
38
44
  - - "~>"
39
45
  - !ruby/object:Gem::Version
40
- version: '1.1'
46
+ version: '2.1'
41
47
  - !ruby/object:Gem::Dependency
42
- name: rspec
48
+ name: erubis
43
49
  requirement: !ruby/object:Gem::Requirement
44
50
  requirements:
45
51
  - - "~>"
46
52
  - !ruby/object:Gem::Version
47
- version: '3.7'
53
+ version: '2.7'
48
54
  type: :development
49
55
  prerelease: false
50
56
  version_requirements: !ruby/object:Gem::Requirement
51
57
  requirements:
52
58
  - - "~>"
53
59
  - !ruby/object:Gem::Version
54
- version: '3.7'
60
+ version: '2.7'
55
61
  - !ruby/object:Gem::Dependency
56
- name: rspec-its
62
+ name: htmlentities
57
63
  requirement: !ruby/object:Gem::Requirement
58
64
  requirements:
59
65
  - - "~>"
60
66
  - !ruby/object:Gem::Version
61
- version: '1.2'
67
+ version: '4.3'
62
68
  type: :development
63
69
  prerelease: false
64
70
  version_requirements: !ruby/object:Gem::Requirement
65
71
  requirements:
66
72
  - - "~>"
67
73
  - !ruby/object:Gem::Version
68
- version: '1.2'
74
+ version: '4.3'
69
75
  - !ruby/object:Gem::Dependency
70
- name: rdf-isomorphic
76
+ name: rspec
71
77
  requirement: !ruby/object:Gem::Requirement
72
78
  requirements:
73
79
  - - "~>"
74
80
  - !ruby/object:Gem::Version
75
- version: '3.0'
81
+ version: '3.10'
76
82
  type: :development
77
83
  prerelease: false
78
84
  version_requirements: !ruby/object:Gem::Requirement
79
85
  requirements:
80
86
  - - "~>"
81
87
  - !ruby/object:Gem::Version
82
- version: '3.0'
88
+ version: '3.10'
83
89
  - !ruby/object:Gem::Dependency
84
- name: rdf-spec
90
+ name: rspec-its
85
91
  requirement: !ruby/object:Gem::Requirement
86
92
  requirements:
87
93
  - - "~>"
88
94
  - !ruby/object:Gem::Version
89
- version: '3.0'
95
+ version: '1.3'
90
96
  type: :development
91
97
  prerelease: false
92
98
  version_requirements: !ruby/object:Gem::Requirement
93
99
  requirements:
94
100
  - - "~>"
95
101
  - !ruby/object:Gem::Version
96
- version: '3.0'
102
+ version: '1.3'
97
103
  - !ruby/object:Gem::Dependency
98
- name: rdf-vocab
104
+ name: rdf-isomorphic
99
105
  requirement: !ruby/object:Gem::Requirement
100
106
  requirements:
101
107
  - - "~>"
102
108
  - !ruby/object:Gem::Version
103
- version: '3.0'
109
+ version: '3.1'
104
110
  type: :development
105
111
  prerelease: false
106
112
  version_requirements: !ruby/object:Gem::Requirement
107
113
  requirements:
108
114
  - - "~>"
109
115
  - !ruby/object:Gem::Version
110
- version: '3.0'
116
+ version: '3.1'
111
117
  - !ruby/object:Gem::Dependency
112
118
  name: json-ld
113
119
  requirement: !ruby/object:Gem::Requirement
114
120
  requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '2.1'
118
- - - "<"
121
+ - - "~>"
119
122
  - !ruby/object:Gem::Version
120
- version: '4.0'
123
+ version: '3.1'
121
124
  type: :development
122
125
  prerelease: false
123
126
  version_requirements: !ruby/object:Gem::Requirement
124
127
  requirements:
125
- - - ">="
126
- - !ruby/object:Gem::Version
127
- version: '2.1'
128
- - - "<"
128
+ - - "~>"
129
129
  - !ruby/object:Gem::Version
130
- version: '4.0'
130
+ version: '3.1'
131
131
  - !ruby/object:Gem::Dependency
132
- name: rake
132
+ name: rdf-spec
133
133
  requirement: !ruby/object:Gem::Requirement
134
134
  requirements:
135
135
  - - "~>"
136
136
  - !ruby/object:Gem::Version
137
- version: '12.0'
137
+ version: '3.1'
138
138
  type: :development
139
139
  prerelease: false
140
140
  version_requirements: !ruby/object:Gem::Requirement
141
141
  requirements:
142
142
  - - "~>"
143
143
  - !ruby/object:Gem::Version
144
- version: '12.0'
144
+ version: '3.1'
145
145
  - !ruby/object:Gem::Dependency
146
- name: yard
146
+ name: rdf-vocab
147
147
  requirement: !ruby/object:Gem::Requirement
148
148
  requirements:
149
149
  - - "~>"
150
150
  - !ruby/object:Gem::Version
151
- version: 0.9.12
151
+ version: '3.1'
152
152
  type: :development
153
153
  prerelease: false
154
154
  version_requirements: !ruby/object:Gem::Requirement
155
155
  requirements:
156
156
  - - "~>"
157
157
  - !ruby/object:Gem::Version
158
- version: 0.9.12
158
+ version: '3.1'
159
159
  description: RDF::Turtle is an Turtle reader/writer for the RDF.rb library suite.
160
160
  email: public-rdf-ruby@w3.org
161
161
  executables: []
@@ -175,11 +175,11 @@ files:
175
175
  - lib/rdf/turtle/terminals.rb
176
176
  - lib/rdf/turtle/version.rb
177
177
  - lib/rdf/turtle/writer.rb
178
- homepage: http://ruby-rdf.github.com/rdf-turtle
178
+ homepage: https://github.com/ruby-rdf/rdf-turtle
179
179
  licenses:
180
180
  - Unlicense
181
181
  metadata: {}
182
- post_install_message:
182
+ post_install_message:
183
183
  rdoc_options: []
184
184
  require_paths:
185
185
  - lib
@@ -187,15 +187,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
187
187
  requirements:
188
188
  - - ">="
189
189
  - !ruby/object:Gem::Version
190
- version: 2.2.2
190
+ version: '2.4'
191
191
  required_rubygems_version: !ruby/object:Gem::Requirement
192
192
  requirements:
193
193
  - - ">="
194
194
  - !ruby/object:Gem::Version
195
195
  version: '0'
196
196
  requirements: []
197
- rubygems_version: 3.0.2
198
- signing_key:
197
+ rubygems_version: 3.2.3
198
+ signing_key:
199
199
  specification_version: 4
200
200
  summary: Turtle reader/writer for Ruby.
201
201
  test_files: []