Skip to content

Commit e139083

Browse files
committed
Finish 3.3.0
2 parents 8dbd85e + 260fd6f commit e139083

22 files changed

+239
-257
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,10 @@ jobs:
1919
strategy:
2020
fail-fast: false
2121
matrix:
22-
ruby:
23-
- 2.6
24-
- 2.7
25-
- "3.0"
26-
- 3.1
27-
- ruby-head
28-
- jruby
22+
ruby: ['3.0', 3.1, 3.2, ruby-head, jruby]
2923
steps:
3024
- name: Clone repository
31-
uses: actions/checkout@v2
25+
uses: actions/checkout@v3
3226
- name: Set up Ruby
3327
uses: ruby/setup-ruby@v1
3428
with:
@@ -38,7 +32,7 @@ jobs:
3832
- name: Run tests
3933
run: ruby --version; bundle exec rspec spec || $ALLOW_FAILURES
4034
- name: Coveralls GitHub Action
41-
uses: coverallsapp/github-action@v1.1.2
42-
if: "matrix.ruby == '3.0'"
35+
uses: coverallsapp/github-action@v2
36+
if: "matrix.ruby == '3.2'"
4337
with:
4438
github-token: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/generate-docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
name: Update gh-pages with docs
1111
steps:
1212
- name: Clone repository
13-
uses: actions/checkout@v2
13+
uses: actions/checkout@v3
1414
- name: Set up Ruby
1515
uses: ruby/setup-ruby@v1
1616
with:

Gemfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ group :development, :test do
1717
gem 'rdf-xsd', git: "https://github.com/ruby-rdf/rdf-xsd", branch: "develop"
1818
gem 'sxp', git: "https://github.com/dryruby/sxp.rb", branch: "develop"
1919
gem "redcarpet", platforms: :ruby
20-
gem 'simplecov', '~> 0.21', platforms: :mri
20+
gem 'simplecov', '~> 0.22', platforms: :mri
2121
gem 'simplecov-lcov', '~> 0.8', platforms: :mri
2222
end

README.md

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[Turtle][] reader/writer for [RDF.rb][RDF.rb] .
44

5-
[![Gem Version](https://badge.fury.io/rb/rdf-turtle.png)](https://badge.fury.io/rb/rdf-turtle)
5+
[![Gem Version](https://badge.fury.io/rb/rdf-turtle.svg)](https://badge.fury.io/rb/rdf-turtle)
66
[![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)
77
[![Coverage Status](https://coveralls.io/repos/ruby-rdf/rdf-turtle/badge.svg?branch=develop)](https://coveralls.io/github/ruby-rdf/rdf-turtle?branch=develop)
88
[![Gitter chat](https://badges.gitter.im/ruby-rdf/rdf.png)](https://gitter.im/ruby-rdf/rdf)
@@ -17,9 +17,9 @@ Install with `gem install rdf-turtle`
1717

1818
* 100% free and unencumbered [public domain](https://unlicense.org/) software.
1919
* Implements a complete parser for [Turtle][].
20-
* Compatible with Ruby >= 2.6.
20+
* Compatible with Ruby >= 3.0.
2121
* Optional streaming writer, to serialize large graphs
22-
* Provisional support for [Turtle-star][RDF-star].
22+
* Provisional support for [RDF 1.2][].
2323

2424
## Usage
2525
Instantiate a reader from a local file:
@@ -36,23 +36,25 @@ Write a graph to a file:
3636
writer << graph
3737
end
3838

39-
## Turtle-star (RDF-star)
39+
## RDF 1.2
4040

41-
Both reader and writer include provisional support for [Turtle-star][RDF-star].
41+
Both reader and writer include provisional support for [RDF 1.2][] quoted triples.
42+
43+
Both reader and writer include provisional support for [RDF 1.2][] directional language-tagged strings, which are literals of type `rdf:dirLangString` having both a `language` and `direction`.
4244

4345
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`.
4446

4547
**Note: This feature is subject to change or elimination as the standards process progresses.**
4648

47-
### Serializing a Graph containing embedded statements
49+
### Serializing a Graph containing quoted triples
4850

4951
require 'rdf/turtle'
5052
statement = RDF::Statement(RDF::URI('bob'), RDF::Vocab::FOAF.age, RDF::Literal(23))
5153
graph = RDF::Graph.new << [statement, RDF::URI("ex:certainty"), RDF::Literal(0.9)]
5254
graph.dump(:ttl, validate: false, standard_prefixes: true)
5355
# => '<<<bob> foaf:age 23>> <ex:certainty> 9.0e-1 .'
5456

55-
### Reading a Graph containing embedded statements
57+
### Reading a Graph containing quoted triples
5658

5759
By default, the Turtle reader will reject a document containing a subject resource.
5860

@@ -140,9 +142,9 @@ This version uses a hand-written parser using the Lexer from the [EBNF][] gem in
140142

141143
## Dependencies
142144

143-
* [Ruby](https://ruby-lang.org/) (>= 2.6)
144-
* [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.2)
145-
* [EBNF][] (~> 1.2)
145+
* [Ruby](https://ruby-lang.org/) (>= 3.0)
146+
* [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.3)
147+
* [EBNF][] (~> 2.4)
146148

147149
## Installation
148150

@@ -187,10 +189,10 @@ A copy of the [Turtle EBNF][] and derived parser files are included in the repos
187189
[PDD]: https://unlicense.org/#unlicensing-contributions
188190
[RDF.rb]: https://ruby-rdf.github.io/rdf
189191
[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-star]: https://w3c.github.io/rdf-star/rdf-star-cg-spec.html
192+
[N-Triples]: https://www.w3.org/TR/rdf12-n-triples
193+
[Turtle]: https://www.w3.org/TR/rdf12-turtle
194+
[RDF 1.1]: https://www.w3.org/TR/rdf11-concepts/
195+
[RDF 1.2]: https://www.w3.org/TR/rdf12-concepts/
194196
[Turtle doc]: https://ruby-rdf.github.io/rdf-turtle/master/file/README.md
195-
[Turtle EBNF]: https://dvcs.w3.org/hg/rdf/file/default/rdf-turtle/turtle.bnf
196-
[Freebase Dumps]: https://developers.google.com/freebase/data
197+
[Turtle EBNF]: https://w3c.github.io/rdf-turtle/spec/turtle-bnf.html
198+
[Freebase Dumps]: https://developers.google.com/freebase/data

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.2.1
1+
3.3.0

etc/turtle.bnf

Lines changed: 71 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,74 @@
1-
[1] turtleDoc ::= statement*
2-
[2] statement ::= directive | triples "."
3-
[3] directive ::= prefixID | base | sparqlPrefix | sparqlBase
4-
[4] prefixID ::= PREFIX PNAME_NS IRIREF "."?
5-
[5] base ::= BASE IRIREF "."?
6-
[5s] sparqlPrefix ::= "PREFIX" PNAME_NS IRIREF
7-
[6s] parqlBase ::= "BASE" IRIREF
8-
[6] triples ::= subject predicateObjectList | blankNodePropertyList predicateObjectList?
9-
[7] predicateObjectList ::= verb objectList ( ";" ( verb objectList)? )*
10-
[8] objectList ::= object annotation? ( "," object annotation? )*
11-
[9] verb ::= predicate | "a"
12-
[10] subject ::= iri | BlankNode | collection | quotedTriple
13-
[11] predicate ::= iri
14-
[12] object ::= iri | BlankNode | collection | blankNodePropertyList | literal | quotedTriple
15-
[13] literal ::= RDFLiteral | NumericLiteral | BooleanLiteral
16-
[14] blankNodePropertyList ::= "[" predicateObjectList "]"
17-
[15] collection ::= "(" object* ")"
18-
[16] NumericLiteral ::= INTEGER | DECIMAL | DOUBLE
19-
[128s] RDFLiteral ::= String ( LANGTAG | ( "^^" iri ) )?
20-
[133s] BooleanLiteral ::= "true" | "false"
21-
[17] String ::= STRING_LITERAL_QUOTE | STRING_LITERAL_SINGLE_QUOTE | STRING_LITERAL_LONG_SINGLE_QUOTE |
22-
STRING_LITERAL_LONG_QUOTE
23-
[135s] iri ::= IRIREF | PrefixedName
24-
[136s] PrefixedName ::= PNAME_LN | PNAME_NS
25-
[137s] BlankNode ::= BLANK_NODE_LABEL | ANON
26-
[27] quotedTriple ::= "<<" qtSubject predicate qtObject ">>"
27-
[28] qtSubject ::= iri | BlankNode | quotedTriple
28-
[29] qtObject ::= iri | BlankNode | literal | quotedTriple
29-
[30] annotation ::= '{|' predicateObjectList '|}'
1+
turtleDoc ::= statement*
2+
statement ::= directive | triples "."
3+
directive ::= prefixID | base | sparqlPrefix | sparqlBase
4+
prefixID ::= PREFIX PNAME_NS IRIREF "."?
5+
base ::= BASE IRIREF "."?
6+
sparqlPrefix ::= "PREFIX" PNAME_NS IRIREF
7+
parqlBase ::= "BASE" IRIREF
8+
triples ::= subject predicateObjectList | blankNodePropertyList predicateObjectList?
9+
predicateObjectList ::= verb objectList ( ";" ( verb objectList)? )*
10+
objectList ::= object annotation? ( "," object annotation? )*
11+
verb ::= predicate | "a"
12+
subject ::= iri | BlankNode | collection | quotedTriple
13+
predicate ::= iri
14+
object ::= iri | BlankNode | collection | blankNodePropertyList | literal | quotedTriple
15+
literal ::= RDFLiteral | NumericLiteral | BooleanLiteral
16+
blankNodePropertyList ::= "[" predicateObjectList "]"
17+
collection ::= "(" object* ")"
18+
NumericLiteral ::= INTEGER | DECIMAL | DOUBLE
19+
RDFLiteral ::= String ( LANG_DIR | ( "^^" iri ) )?
20+
BooleanLiteral ::= "true" | "false"
21+
String ::= STRING_LITERAL_QUOTE | STRING_LITERAL_SINGLE_QUOTE | STRING_LITERAL_LONG_SINGLE_QUOTE |
22+
STRING_LITERAL_LONG_QUOTE
23+
iri ::= IRIREF | PrefixedName
24+
PrefixedName ::= PNAME_LN | PNAME_NS
25+
BlankNode ::= BLANK_NODE_LABEL | ANON
26+
quotedTriple ::= "<<" qtSubject predicate qtObject ">>"
27+
qtSubject ::= iri | BlankNode | quotedTriple
28+
qtObject ::= iri | BlankNode | literal | quotedTriple
29+
annotation ::= '{|' predicateObjectList '|}'
3030

3131
@terminals
3232

33-
[18] IRIREF ::= '<' ([^#x00-#x20<>"{}|^`\] | UCHAR)* '>'
34-
[139s] PNAME_NS ::= PN_PREFIX? ":"
35-
[140s] PNAME_LN ::= PNAME_NS PN_LOCAL
36-
[141s] BLANK_NODE_LABEL ::= '_:' ( PN_CHARS_U | [0-9] ) ((PN_CHARS|'.')* PN_CHARS)?
37-
[144s] LANGTAG ::= "@" [a-zA-Z]+ ( "-" [a-zA-Z0-9]+ )*
38-
[19] INTEGER ::= [+-]? [0-9]+
39-
[20] DECIMAL ::= [+-]? ( ([0-9])* '.' ([0-9])+ )
40-
[21] DOUBLE ::= [+-]? ( [0-9]+ '.' [0-9]* EXPONENT | '.' ([0-9])+ EXPONENT | ([0-9])+ EXPONENT )
41-
[154s] EXPONENT ::= [eE] [+-]? [0-9]+
42-
[22] STRING_LITERAL_QUOTE ::= '"' ( [^#x22#x5C#xA#xD] | ECHAR | UCHAR )* '"'
43-
[23] STRING_LITERAL_SINGLE_QUOTE ::= "'" ( [^#x27#x5C#xA#xD] | ECHAR | UCHAR )* "'"
44-
[24] STRING_LITERAL_LONG_SINGLE_QUOTE ::= "'''" ( ( "'" | "''" )? ( [^'\] | ECHAR | UCHAR ) )* "'''"
45-
[25] STRING_LITERAL_LONG_QUOTE ::= '"""' ( ( '"' | '""' )? ( [^"\] | ECHAR | UCHAR ) )* '"""'
46-
[26] UCHAR ::= ( "\u" HEX HEX HEX HEX ) | ( "\U" HEX HEX HEX HEX HEX HEX HEX HEX )
47-
[159s] ECHAR ::= "\" [tbnrf\"']
48-
[28t] PREFIX ::= "@"?[Pp][Rr][Ee][Ff][Ii][Xx]
49-
[29t] BASE ::= "@"?[Bb][Aa][Ss][Ee]
50-
[161s] WS ::= #x20 | #x9 | #xD | #xA
51-
[162s] ANON ::= "[" WS* "]"
52-
[163s] PN_CHARS_BASE ::= [A-Z]
53-
| [a-z]
54-
| [#x00C0-#x00D6]
55-
| [#x00D8-#x00F6]
56-
| [#x00F8-#x02FF]
57-
| [#x0370-#x037D]
58-
| [#x037F-#x1FFF]
59-
| [#x200C-#x200D]
60-
| [#x2070-#x218F]
61-
| [#x2C00-#x2FEF]
62-
| [#x3001-#xD7FF]
63-
| [#xF900-#xFDCF]
64-
| [#xFDF0-#xFFFD]
65-
| [#x10000-#xEFFFF]
66-
[164s] PN_CHARS_U ::= PN_CHARS_BASE | '_'
67-
[166s] PN_CHARS ::= PN_CHARS_U | "-" | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040]
68-
[167s] PN_PREFIX ::= PN_CHARS_BASE ( ( PN_CHARS | "." )* PN_CHARS )?
69-
[168s] PN_LOCAL ::= ( PN_CHARS_U | ':' | [0-9] | PLX ) ( ( PN_CHARS | '.' | ':' | PLX )* ( PN_CHARS | ':' | PLX ) ) ?
70-
[169s] PLX ::= PERCENT | PN_LOCAL_ESC
71-
[170s] PERCENT ::= '%' HEX HEX
72-
[171s] HEX ::= [0-9] | [A-F] | [a-f]
73-
[172s] PN_LOCAL_ESC ::= '\' ( '_' | '~' | '.' | '-' | '!' | '$' | '&' | "'" | '(' | ')' | '*' | '+' | ',' | ';' | '='
74-
| '/' | '?' | '#' | '@' | '%' )
33+
IRIREF ::= '<' ([^#x00-#x20<>"{}|^`\] | UCHAR)* '>'
34+
PNAME_NS ::= PN_PREFIX? ":"
35+
PNAME_LN ::= PNAME_NS PN_LOCAL
36+
BLANK_NODE_LABEL ::= '_:' ( PN_CHARS_U | [0-9] ) ((PN_CHARS|'.')* PN_CHARS)?
37+
LANG_DIR ::= "@" [a-zA-Z]+ ( "-" [a-zA-Z0-9]+ )* ('--' [a-zA-Z]+)?`
38+
INTEGER ::= [+-]? [0-9]+
39+
DECIMAL ::= [+-]? ( ([0-9])* '.' ([0-9])+ )
40+
DOUBLE ::= [+-]? ( [0-9]+ '.' [0-9]* EXPONENT | '.' ([0-9])+ EXPONENT | ([0-9])+ EXPONENT )
41+
EXPONENT ::= [eE] [+-]? [0-9]+
42+
STRING_LITERAL_QUOTE ::= '"' ( [^#x22#x5C#xA#xD] | ECHAR | UCHAR )* '"'
43+
STRING_LITERAL_SINGLE_QUOTE ::= "'" ( [^#x27#x5C#xA#xD] | ECHAR | UCHAR )* "'"
44+
STRING_LITERAL_LONG_SINGLE_QUOTE ::= "'''" ( ( "'" | "''" )? ( [^'\] | ECHAR | UCHAR ) )* "'''"
45+
STRING_LITERAL_LONG_QUOTE ::= '"""' ( ( '"' | '""' )? ( [^"\] | ECHAR | UCHAR ) )* '"""'
46+
UCHAR ::= ( "\u" HEX HEX HEX HEX ) | ( "\U" HEX HEX HEX HEX HEX HEX HEX HEX )
47+
ECHAR ::= "\" [tbnrf\"']
48+
PREFIX ::= "@"?[Pp][Rr][Ee][Ff][Ii][Xx]
49+
BASE ::= "@"?[Bb][Aa][Ss][Ee]
50+
WS ::= #x20 | #x9 | #xD | #xA
51+
ANON ::= "[" WS* "]"
52+
PN_CHARS_BASE ::= [A-Z]
53+
| [a-z]
54+
| [#x00C0-#x00D6]
55+
| [#x00D8-#x00F6]
56+
| [#x00F8-#x02FF]
57+
| [#x0370-#x037D]
58+
| [#x037F-#x1FFF]
59+
| [#x200C-#x200D]
60+
| [#x2070-#x218F]
61+
| [#x2C00-#x2FEF]
62+
| [#x3001-#xD7FF]
63+
| [#xF900-#xFDCF]
64+
| [#xFDF0-#xFFFD]
65+
| [#x10000-#xEFFFF]
66+
PN_CHARS_U ::= PN_CHARS_BASE | '_'
67+
PN_CHARS ::= PN_CHARS_U | "-" | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040]
68+
PN_PREFIX ::= PN_CHARS_BASE ( ( PN_CHARS | "." )* PN_CHARS )?
69+
PN_LOCAL ::= ( PN_CHARS_U | ':' | [0-9] | PLX ) ( ( PN_CHARS | '.' | ':' | PLX )* ( PN_CHARS | ':' | PLX ) ) ?
70+
PLX ::= PERCENT | PN_LOCAL_ESC
71+
PERCENT ::= '%' HEX HEX
72+
HEX ::= [0-9] | [A-F] | [a-f]
73+
PN_LOCAL_ESC ::= '\' ( '_' | '~' | '.' | '-' | '!' | '$' | '&' | "'" | '(' | ')' | '*' | '+' | ',' | ';' | '='
74+
| '/' | '?' | '#' | '@' | '%' )

lib/rdf/turtle/freebase_reader.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,9 @@ def read_literal
7979
if literal_str = match(LITERAL_PLAIN)
8080
literal_str = self.class.unescape(literal_str)
8181
literal = case
82-
when language = match(RDF::NTriples::Reader::LANGTAG)
83-
RDF::Literal.new(literal_str, language: language)
82+
when lang_dir = match(RDF::Turtle::Reader::LANG_DIR)
83+
language, direction = lang_dir.split('--')
84+
RDF::Literal.new(literal_str, language: language, direction: direction)
8485
when datatype = match(/^(\^\^)/)
8586
RDF::Literal.new(literal_str, datatype: read_pname(intern: true) || read_uriref || fail_object)
8687
else

lib/rdf/turtle/reader.rb

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class Reader < RDF::Reader
3636

3737
terminal(:PREFIX, PREFIX)
3838
terminal(:BASE, BASE)
39-
terminal(:LANGTAG, LANGTAG)
39+
terminal(:LANG_DIR, LANG_DIR)
4040

4141
##
4242
# Reader options
@@ -394,7 +394,7 @@ def read_object(subject = nil, predicate = nil)
394394
end
395395
end
396396

397-
# Read an RDF-star reified statement
397+
# Read a quoted triple
398398
# @return [RDF::Statement]
399399
def read_quotedTriple
400400
return unless @options[:rdfstar]
@@ -470,8 +470,10 @@ def read_literal
470470
value = @lexer.shift.value[1..-2]
471471
error("read_literal", "Unexpected end of file") unless token = @lexer.first
472472
case token.type || token.value
473-
when :LANGTAG
474-
literal(value, language: @lexer.shift.value[1..-1].to_sym)
473+
when :LANG_DIR
474+
lang_dir = @lexer.shift.value[1..-1]
475+
language, direction = lang_dir.split('--')
476+
literal(value, language: language, direction: direction)
475477
when '^^'
476478
@lexer.shift
477479
literal(value, datatype: read_iri)
@@ -484,8 +486,10 @@ def read_literal
484486
value = @lexer.shift.value[3..-4]
485487
error("read_literal", "Unexpected end of file") unless token = @lexer.first
486488
case token.type || token.value
487-
when :LANGTAG
488-
literal(value, language: @lexer.shift.value[1..-1].to_sym)
489+
when :LANG_DIR
490+
lang_dir = @lexer.shift.value[1..-1]
491+
language, direction = lang_dir.split('--')
492+
literal(value, language: language, direction: direction)
489493
when '^^'
490494
@lexer.shift
491495
literal(value, datatype: read_iri)

lib/rdf/turtle/terminals.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ module Terminals
4848
# 141s
4949
BLANK_NODE_LABEL = /_:(?:[0-9]|#{PN_CHARS_U})(?:(?:#{PN_CHARS}|\.)*#{PN_CHARS})?/u.freeze
5050
# 144s
51-
LANGTAG = /@[a-zA-Z]+(?:-[a-zA-Z0-9]+)*/u.freeze
51+
LANG_DIR = /@([a-zA-Z]+(?:-[a-zA-Z0-9]+)*(?:--[a-zA-Z]+)?)/u.freeze
5252
# 19
5353
INTEGER = /[+-]?[0-9]+/u.freeze
5454
# 20

lib/rdf/turtle/writer.rb

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ def self.options
8787
symbol: :literal_shorthand,
8888
datatype: FalseClass,
8989
on: ["--no-literal-shorthand"],
90-
description: "Do not ttempt to use Literal shorthands fo numbers and boolean values.") {false},
90+
description: "Do not attempt to use Literal shorthands fo numbers and boolean values.") {false},
9191
]
9292
end
9393

@@ -215,7 +215,7 @@ def get_pname(resource)
215215
end
216216

217217
pname = case
218-
when @uri_to_pname.has_key?(uri)
218+
when @uri_to_pname.key?(uri)
219219
return @uri_to_pname[uri]
220220
when u = @uri_to_prefix.keys.sort_by {|uu| uu.length}.reverse.detect {|uu| uri.index(uu.to_s) == 0}
221221
# Use a defined prefix
@@ -296,8 +296,9 @@ def format_literal(literal, **options)
296296
in_form ? literal.value : literal.canonicalize.to_s.sub('E', 'e').to_s
297297
else
298298
text = quoted(literal.value)
299-
text << "@#{literal.language}" if literal.has_language?
300-
text << "^^#{format_uri(literal.datatype)}" if literal.has_datatype?
299+
text << "@#{literal.language}" if literal.language?
300+
text << "--#{literal.direction}" if literal.direction?
301+
text << "^^#{format_uri(literal.datatype)}" if literal.datatype?
301302
text
302303
end
303304
else

0 commit comments

Comments
 (0)