rdf-turtle 3.1.0 → 3.1.1
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/README.md +46 -0
- data/VERSION +1 -1
- data/lib/rdf/turtle/reader.rb +43 -18
- data/lib/rdf/turtle/writer.rb +12 -1
- metadata +10 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a527c2357a49551b152847f83943ac2e215ac10b2c4c76d0727fd42a85026cd
|
4
|
+
data.tar.gz: 0d8fa400deaf2bbc4c8ea996b0a37d5ead4fbb00519cc95ac84dad58052125e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2493ae5d441f97c947249a58a7fd8a49ce8aca6f675b08fc5b223a8f3bab2037d2004416ddca6f0ea78ad4dca9199b5c31c92f14b7068085222a7b191de44deb
|
7
|
+
data.tar.gz: c4db12c8fe5e8401f82ae472ee343474704bb19a1bf202b1e551f29be6b2a874697e046a0c6bd4a91fe0a29c3428a02fe2e7fd2dff249c44a783ee17bdc9481c
|
data/README.md
CHANGED
@@ -19,6 +19,7 @@ Install with `gem install rdf-turtle`
|
|
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,50 @@ 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 `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:
|
70
|
+
|
71
|
+
graph = RDF::Graph.new do |graph|
|
72
|
+
RDF::Turtle::Reader.new(ttl, rdfstar: :PG) {|reader| graph << reader}
|
73
|
+
end
|
74
|
+
graph.count #=> 2
|
75
|
+
|
76
|
+
When using the `:SA` mode, only one statement is asserted, although the reified statement is contained within the graph.
|
77
|
+
|
78
|
+
graph = RDF::Graph.new do |graph|
|
79
|
+
RDF::Turtle::Reader.new(ttl, rdfstar: :SA) {|reader| graph << reader}
|
80
|
+
end
|
81
|
+
graph.count #=> 1
|
82
|
+
|
38
83
|
## Documentation
|
39
84
|
Full documentation available on [Rubydoc.info][Turtle doc]
|
40
85
|
|
@@ -133,6 +178,7 @@ A copy of the [Turtle EBNF][] and derived parser files are included in the repos
|
|
133
178
|
[Backports]: https://rubygems.org/gems/backports
|
134
179
|
[N-Triples]: https://www.w3.org/TR/rdf-testcases/#ntriples
|
135
180
|
[Turtle]: https://www.w3.org/TR/2012/WD-turtle-20120710/
|
181
|
+
[RDF*]: https://lists.w3.org/Archives/Public/public-rdf-star/
|
136
182
|
[Turtle doc]: https://rubydoc.info/github/ruby-rdf/rdf-turtle/master/file/README.md
|
137
183
|
[Turtle EBNF]: https://dvcs.w3.org/hg/rdf/file/default/rdf-turtle/turtle.bnf
|
138
184
|
[Freebase Dumps]: https://developers.google.com/freebase/data
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.1.
|
1
|
+
3.1.1
|
data/lib/rdf/turtle/reader.rb
CHANGED
@@ -25,7 +25,7 @@ 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([\(\),.;\[\]Aa]|\^\^|true|false|<<|>>))
|
29
29
|
|
30
30
|
terminal(:PREFIX, PREFIX)
|
31
31
|
terminal(:BASE, BASE)
|
@@ -87,7 +87,7 @@ module RDF::Turtle
|
|
87
87
|
@options = {
|
88
88
|
anon_base: "b0",
|
89
89
|
whitespace: WS,
|
90
|
-
|
90
|
+
depth: 0,
|
91
91
|
}.merge(@options)
|
92
92
|
@prod_stack = []
|
93
93
|
|
@@ -185,7 +185,7 @@ module RDF::Turtle
|
|
185
185
|
|
186
186
|
# Create a literal
|
187
187
|
def literal(value, **options)
|
188
|
-
log_debug("literal") do
|
188
|
+
log_debug("literal", depth: @options[:depth]) do
|
189
189
|
"value: #{value.inspect}, " +
|
190
190
|
"options: #{options.inspect}, " +
|
191
191
|
"validate: #{validate?.inspect}, " +
|
@@ -221,7 +221,7 @@ module RDF::Turtle
|
|
221
221
|
''
|
222
222
|
end
|
223
223
|
suffix = suffix.to_s.sub(/^\#/, "") if base.index("#")
|
224
|
-
log_debug("pname") {"base: '#{base}', suffix: '#{suffix}'"}
|
224
|
+
log_debug("pname", depth: options[:depth]) {"base: '#{base}', suffix: '#{suffix}'"}
|
225
225
|
process_iri(base + suffix.to_s)
|
226
226
|
end
|
227
227
|
|
@@ -283,7 +283,7 @@ module RDF::Turtle
|
|
283
283
|
terminated = token.value == '@prefix'
|
284
284
|
error("Expected PNAME_NS", production: :prefix, token: pfx) unless pfx === :PNAME_NS
|
285
285
|
error("Expected IRIREF", production: :prefix, token: iri) unless iri === :IRIREF
|
286
|
-
log_debug("prefixID") {"Defined prefix #{pfx.inspect} mapping to #{iri.inspect}"}
|
286
|
+
log_debug("prefixID", depth: options[:depth]) {"Defined prefix #{pfx.inspect} mapping to #{iri.inspect}"}
|
287
287
|
prefix(pfx.value[0..-2], process_iri(iri))
|
288
288
|
error("prefixId", "#{token} should be downcased") if token.value.start_with?('@') && token.value != '@prefix'
|
289
289
|
|
@@ -362,6 +362,7 @@ module RDF::Turtle
|
|
362
362
|
read_iri ||
|
363
363
|
read_BlankNode ||
|
364
364
|
read_collection ||
|
365
|
+
read_rdfstar ||
|
365
366
|
error( "Expected subject", production: :subject, token: @lexer.first)
|
366
367
|
end
|
367
368
|
end
|
@@ -373,7 +374,8 @@ module RDF::Turtle
|
|
373
374
|
read_BlankNode ||
|
374
375
|
read_collection ||
|
375
376
|
read_blankNodePropertyList ||
|
376
|
-
read_literal
|
377
|
+
read_literal ||
|
378
|
+
read_rdfstar
|
377
379
|
|
378
380
|
add_statement(:object, RDF::Statement(subject, predicate, object)) if subject && predicate
|
379
381
|
object
|
@@ -381,6 +383,28 @@ module RDF::Turtle
|
|
381
383
|
end
|
382
384
|
end
|
383
385
|
|
386
|
+
# Read an RDF* reified statement
|
387
|
+
# @return [RDF::Statement]
|
388
|
+
def read_rdfstar
|
389
|
+
return unless @options[:rdfstar]
|
390
|
+
if @lexer.first.value == '<<'
|
391
|
+
prod(:rdfstar) do
|
392
|
+
@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)
|
396
|
+
unless @lexer.first.value == '>>'
|
397
|
+
error("Failed to end of embedded triple", production: :rdfstar, token: @lexer.first)
|
398
|
+
end
|
399
|
+
@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
|
403
|
+
statement
|
404
|
+
end
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
384
408
|
# @return [RDF::Literal]
|
385
409
|
def read_literal
|
386
410
|
error("Unexpected end of file", production: :literal) unless token = @lexer.first
|
@@ -431,7 +455,7 @@ module RDF::Turtle
|
|
431
455
|
if token === '['
|
432
456
|
prod(:blankNodePropertyList, %{]}) do
|
433
457
|
@lexer.shift
|
434
|
-
log_info("blankNodePropertyList") {"token: #{token.inspect}"}
|
458
|
+
log_info("blankNodePropertyList", depth: options[:depth]) {"token: #{token.inspect}"}
|
435
459
|
node = bnode
|
436
460
|
read_predicateObjectList(node)
|
437
461
|
error("blankNodePropertyList", "Expected closing ']'") unless @lexer.first === ']'
|
@@ -447,7 +471,7 @@ module RDF::Turtle
|
|
447
471
|
prod(:collection, %{)}) do
|
448
472
|
@lexer.shift
|
449
473
|
token = @lexer.first
|
450
|
-
log_info("collection") {"token: #{token.inspect}"}
|
474
|
+
log_info("collection", depth: options[:depth]) {"token: #{token.inspect}"}
|
451
475
|
objects = []
|
452
476
|
while object = read_object
|
453
477
|
objects << object
|
@@ -483,8 +507,8 @@ module RDF::Turtle
|
|
483
507
|
|
484
508
|
def prod(production, recover_to = [])
|
485
509
|
@prod_stack << {prod: production, recover_to: recover_to}
|
486
|
-
@options[:
|
487
|
-
log_recover("#{production}(start)") {"token: #{@lexer.first.inspect}"}
|
510
|
+
@options[:depth] += 1
|
511
|
+
log_recover("#{production}(start)", depth: options[:depth]) {"token: #{@lexer.first.inspect}"}
|
488
512
|
yield
|
489
513
|
rescue EBNF::LL1::Lexer::Error, SyntaxError, Recovery => e
|
490
514
|
# Lexer encountered an illegal token or the parser encountered
|
@@ -504,13 +528,13 @@ module RDF::Turtle
|
|
504
528
|
end
|
505
529
|
end
|
506
530
|
raise EOFError, "End of input found when recovering" if @lexer.first.nil?
|
507
|
-
log_debug("recovery", "current token: #{@lexer.first.inspect}")
|
531
|
+
log_debug("recovery", "current token: #{@lexer.first.inspect}", depth: options[:depth])
|
508
532
|
|
509
533
|
unless e.is_a?(Recovery)
|
510
534
|
# Get the list of follows for this sequence, this production and the stacked productions.
|
511
|
-
log_debug("recovery", "stack follows:")
|
535
|
+
log_debug("recovery", "stack follows:", depth: options[:depth])
|
512
536
|
@prod_stack.reverse.each do |prod|
|
513
|
-
log_debug("recovery", level: 4) {" #{prod[:prod]}: #{prod[:recover_to].inspect}"}
|
537
|
+
log_debug("recovery", level: 4, depth: options[:depth]) {" #{prod[:prod]}: #{prod[:recover_to].inspect}"}
|
514
538
|
end
|
515
539
|
end
|
516
540
|
|
@@ -520,9 +544,9 @@ module RDF::Turtle
|
|
520
544
|
# Skip tokens until one is found in follows
|
521
545
|
while (token = (@lexer.first rescue @lexer.recover)) && follows.none? {|t| token === t}
|
522
546
|
skipped = @lexer.shift
|
523
|
-
log_debug("recovery") {"skip #{skipped.inspect}"}
|
547
|
+
log_debug("recovery", depth: options[:depth]) {"skip #{skipped.inspect}"}
|
524
548
|
end
|
525
|
-
log_debug("recovery") {"found #{token.inspect} in follows"}
|
549
|
+
log_debug("recovery", depth: options[:depth]) {"found #{token.inspect} in follows"}
|
526
550
|
|
527
551
|
# Re-raise the error unless token is a follows of this production
|
528
552
|
raise Recovery unless Array(recover_to).any? {|t| token === t}
|
@@ -530,8 +554,8 @@ module RDF::Turtle
|
|
530
554
|
# Skip that token to get something reasonable to start the next production with
|
531
555
|
@lexer.shift
|
532
556
|
ensure
|
533
|
-
log_info("#{production}(finish)")
|
534
|
-
@options[:
|
557
|
+
log_info("#{production}(finish)", depth: options[:depth])
|
558
|
+
@options[:depth] -= 1
|
535
559
|
@prod_stack.pop
|
536
560
|
end
|
537
561
|
|
@@ -554,7 +578,8 @@ module RDF::Turtle
|
|
554
578
|
lineno: lineno,
|
555
579
|
token: options[:token],
|
556
580
|
production: options[:production],
|
557
|
-
|
581
|
+
depth: options[:depth],
|
582
|
+
exception: SyntaxError,)
|
558
583
|
end
|
559
584
|
|
560
585
|
# Used for internal error recovery
|
data/lib/rdf/turtle/writer.rb
CHANGED
@@ -313,6 +313,17 @@ module RDF::Turtle
|
|
313
313
|
options[:unique_bnodes] ? node.to_unique_base : node.to_base
|
314
314
|
end
|
315
315
|
|
316
|
+
##
|
317
|
+
# Returns an embedded triples
|
318
|
+
#
|
319
|
+
# @param [RDF::Statement] statement
|
320
|
+
# @param [Hash{Symbol => Object}] options
|
321
|
+
# @return [String]
|
322
|
+
def format_rdfstar(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
|
@@ -457,7 +468,7 @@ module RDF::Turtle
|
|
457
468
|
|
458
469
|
# Can subject be represented as a blankNodePropertyList?
|
459
470
|
def blankNodePropertyList?(resource, position)
|
460
|
-
resource.node? &&
|
471
|
+
!resource.statement? && resource.node? &&
|
461
472
|
!is_valid_list?(resource) &&
|
462
473
|
(!is_done?(resource) || position == :subject) &&
|
463
474
|
ref_count(resource) == (position == :object ? 1 : 0)
|
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.
|
4
|
+
version: 3.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gregg Kellogg
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-05-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rdf
|
@@ -17,6 +17,9 @@ dependencies:
|
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '3.1'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 3.1.2
|
20
23
|
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -24,6 +27,9 @@ dependencies:
|
|
24
27
|
- - "~>"
|
25
28
|
- !ruby/object:Gem::Version
|
26
29
|
version: '3.1'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 3.1.2
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
34
|
name: ebnf
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -169,7 +175,7 @@ files:
|
|
169
175
|
- lib/rdf/turtle/terminals.rb
|
170
176
|
- lib/rdf/turtle/version.rb
|
171
177
|
- lib/rdf/turtle/writer.rb
|
172
|
-
homepage: https://
|
178
|
+
homepage: https://github.com/ruby-rdf/rdf-turtle
|
173
179
|
licenses:
|
174
180
|
- Unlicense
|
175
181
|
metadata: {}
|
@@ -188,7 +194,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
188
194
|
- !ruby/object:Gem::Version
|
189
195
|
version: '0'
|
190
196
|
requirements: []
|
191
|
-
rubygems_version: 3.
|
197
|
+
rubygems_version: 3.1.3
|
192
198
|
signing_key:
|
193
199
|
specification_version: 4
|
194
200
|
summary: Turtle reader/writer for Ruby.
|