Skip to content

Commit 196b73b

Browse files
committed
Add support for RDF 1.2 Triple Terms and deprecation notices for RDF-star quoted triples.
Note all RDF 1.2 and RDF-star support remains experimental and may be changed or removed in a future minor or patch version.
1 parent 7eeab69 commit 196b73b

17 files changed

Lines changed: 201 additions & 27 deletions

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,9 +265,15 @@ A separate [SPARQL][SPARQL doc] gem builds on basic BGP support to provide full
265265
foaf[:name] #=> RDF::URI("http://xmlns.com/foaf/0.1/name")
266266
foaf['mbox'] #=> RDF::URI("http://xmlns.com/foaf/0.1/mbox")
267267

268+
## RDF-star CG
269+
270+
[RDF.rb][] includes provisional support for [RDF-star][] with an N-Triples/N-Quads syntax for quoted triples in the _subject_ or _object_ position.
271+
272+
Support for RDF-star quoted triples is now deprecated, use RDF 1.2 triple terms instead.
273+
268274
## RDF 1.2
269275

270-
[RDF.rb][] includes provisional support for [RDF 1.2][] with an N-Triples/N-Quads syntax for quoted triples in the _subject_ or _object_ position.
276+
[RDF.rb][] includes provisional support for [RDF 1.2][] with an N-Triples/N-Quads syntax for triple terms in the _object_ position.
271277
[RDF.rb][] includes provisional support for [RDF 1.2][] directional language-tagged strings, which are literals of type `rdf:dirLangString` having both a `language` and `direction`.
272278

273279
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`.
@@ -501,6 +507,7 @@ see <https://unlicense.org/> or the accompanying {file:UNLICENSE} file.
501507
[SPARQL doc]: https://ruby-rdf.github.io/sparql
502508
[RDF 1.0]: https://www.w3.org/TR/2004/REC-rdf-concepts-20040210/
503509
[RDF 1.1]: https://www.w3.org/TR/rdf11-concepts/
510+
[RDF-star]: https://www.w3.org/2021/12/rdf-star.html
504511
[RDF 1.2]: https://www.w3.org/TR/rdf12-concepts/
505512
[SPARQL 1.1]: https://www.w3.org/TR/sparql11-query/
506513
[RDF.rb]: https://ruby-rdf.github.io/

etc/n-triples.ebnf

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ ntriplesDoc ::= triple? (EOL triple)* EOL?
22
triple ::= subject predicate object '.'
33
subject ::= IRIREF | BLANK_NODE_LABEL | quotedTriple
44
predicate ::= IRIREF
5-
object ::= IRIREF | BLANK_NODE_LABEL | literal | quotedTriple
5+
object ::= IRIREF | BLANK_NODE_LABEL | literal | tripleTerm | quotedTriple
66
literal ::= STRING_LITERAL_QUOTE ('^^' IRIREF | LANG_DIR )?
7+
tripleTerm ::= '<<' subject predicate object '>>'
78
quotedTriple ::= '<<' subject predicate object '>>'
89

910
@terminals

lib/rdf/mixin/enumerable.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ def to_a
8383
# * `:literal_equality' preserves [term-equality](https://www.w3.org/TR/rdf11-concepts/#dfn-literal-term-equality) for literals. Literals are equal only if their lexical values and datatypes are equal, character by character. Literals may be "inlined" to value-space for efficiency only if `:literal_equality` is `false`.
8484
# * `:validity` allows a concrete Enumerable implementation to indicate that it does or does not support valididty checking. By default implementations are assumed to support validity checking.
8585
# * `:skolemize` supports [Skolemization](https://www.w3.org/wiki/BnodeSkolemization) of an `Enumerable`. Implementations supporting this feature must implement a `#skolemize` method, taking a base URI used for minting URIs for BNodes as stable identifiers and a `#deskolemize` method, also taking a base URI used for turning URIs having that prefix back into the same BNodes which were originally skolemized.
86-
# * `:quoted_triples` supports RDF 1.2 quoted triples.
86+
# * `:rdf_full` supports RDF 1.2 Full profile, including support for embedded Triple Terms.
87+
# * `:quoted_triples` supports RDF-star quoted triples.
8788
# * `:base_direction` supports RDF 1.2 directional language-tagged strings.
8889
#
8990
# @param [Symbol, #to_sym] feature

lib/rdf/mixin/writable.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ def insert_graph(graph)
127127
def insert_statements(statements)
128128
each = statements.respond_to?(:each_statement) ? :each_statement : :each
129129
statements.__send__(each) do |statement|
130-
if statement.embedded? && respond_to?(:supports?) && !supports?(:quoted_triples)
130+
# FIXME: quoted triples are now deprecated
131+
if statement.embedded? && respond_to?(:supports?) && !(supports?(:quoted_triples) || supports?(:rdf_full))
131132
raise ArgumentError, "Writable does not support quoted triples"
132133
end
133134
if statement.object && statement.object.literal? && statement.object.direction? && respond_to?(:supports?) && !supports?(:base_direction)

lib/rdf/model/dataset.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ def isolation_level
104104
# @private
105105
# @see RDF::Enumerable#supports?
106106
def supports?(feature)
107-
return true if %i(graph_name quoted_triples).include?(feature)
107+
# FIXME: quoted triples are now deprecated
108+
return true if %i(graph_name quoted_triples rdf_full).include?(feature)
108109
super
109110
end
110111

lib/rdf/model/graph.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,8 +305,9 @@ def query_pattern(pattern, **options, &block)
305305
# @private
306306
# @see RDF::Mutable#insert
307307
def insert_statement(statement)
308-
if statement.embedded? && !@data.supports?(:quoted_triples)
309-
raise ArgumentError, "Graph does not support quoted triples"
308+
# FIXME: quoted triples are now deprecated
309+
if statement.embedded? && !(@data.supports?(:quoted_triples) || @data.supports?(:rdf_full))
310+
raise ArgumentError, "Graph does not support the RDF Full profile"
310311
end
311312
if statement.object && statement.object.literal? && statement.object.direction? && !@data.supports?(:base_direction)
312313
raise ArgumentError, "Graph does not support directional languaged-tagged strings"

lib/rdf/model/statement.rb

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ def self.from(statement, graph_name: nil, **options)
7171
# @option options [RDF::Term] :graph_name (nil)
7272
# Note, in RDF 1.1, a graph name MUST be an {Resource}.
7373
# @option options [Boolean] :inferred used as a marker to record that this statement was inferred based on semantic relationships (T-Box).
74-
# @option options [Boolean] :quoted used as a marker to record that this statement quoted and appears as the subject or object of another RDF::Statement.
74+
# @option options [Boolean] :tripleTerm used as a marker to record that this statement appears as the object of another RDF::Statement.
75+
# @option options [Boolean] :quoted used as a marker to record that this statement quoted and appears as the subject or object of another RDF::Statement (deprecated).
7576
# @return [RDF::Statement]
7677
#
7778
# @overload initialize(subject, predicate, object, **options)
@@ -84,7 +85,8 @@ def self.from(statement, graph_name: nil, **options)
8485
# @option options [RDF::Term] :graph_name (nil)
8586
# Note, in RDF 1.1, a graph name MUST be an {Resource}.
8687
# @option options [Boolean] :inferred used as a marker to record that this statement was inferred based on semantic relationships (T-Box).
87-
# @option options [Boolean] :quoted used as a marker to record that this statement quoted and appears as the subject or object of another RDF::Statement.
88+
# @option options [Boolean] :tripleTerm used as a marker to record that this statement appears as the object of another RDF::Statement.
89+
# @option options [Boolean] :quoted used as a marker to record that this statement quoted and appears as the subject or object of another RDF::Statement (deprecated).
8890
# @return [RDF::Statement]
8991
def initialize(subject = nil, predicate = nil, object = nil, options = {})
9092
if subject.is_a?(Hash)
@@ -211,6 +213,13 @@ def asserted?
211213

212214
##
213215
# @return [Boolean]
216+
def tripleTerm?
217+
!!@options[:tripleTerm]
218+
end
219+
220+
##
221+
# @return [Boolean]
222+
# @deprecated Quoted triples are now deprecated
214223
def quoted?
215224
!!@options[:quoted]
216225
end

lib/rdf/nquads.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,10 @@ def read_triple
7171

7272
begin
7373
unless blank? || read_comment
74+
# FIXME: quoted triples are now deprecated
7475
subject = read_uriref || read_node || read_quotedTriple || fail_subject
7576
predicate = read_uriref(intern: true) || fail_predicate
76-
object = read_uriref || read_node || read_literal || read_quotedTriple || fail_object
77+
object = read_uriref || read_node || read_literal || read_tripleTerm || read_quotedTriple || fail_object
7778
graph_name = read_uriref || read_node
7879
if validate? && !read_eos
7980
log_error("Expected end of statement (found: #{current_line.inspect})", lineno: lineno, exception: RDF::ReaderError)

lib/rdf/ntriples.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ module RDF
1515
#
1616
# <https://rubygems.org/gems/rdf> <http://purl.org/dc/terms/title> "rdf" .
1717
#
18-
# ## Quoted Triples
18+
# ## Triple terms
19+
#
20+
# Supports statements as resources using `<<(s p o)>>`.
21+
22+
# ## Quoted Triples (Deprecated)
1923
#
2024
# Supports statements as resources using `<<s p o>>`.
2125
#

lib/rdf/ntriples/reader.rb

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,11 @@ class Reader < RDF::Reader
7070
LANG_DIR = /@([a-zA-Z]+(?:-[a-zA-Z0-9]+)*(?:--[a-zA-Z]+)?)/.freeze
7171
STRING_LITERAL_QUOTE = /"((?:[^\"\\\n\r]|#{ECHAR}|#{UCHAR})*)"/.freeze
7272

73-
ST_START = /^<</.freeze
74-
ST_END = /^\s*>>/.freeze
73+
TT_START = /^<<\(/.freeze
74+
TT_END = /^\s*\)>>/.freeze
75+
76+
QT_START = /^<</.freeze
77+
QT_END = /^\s*>>/.freeze
7578

7679
# @see http://www.w3.org/TR/rdf-testcases/#ntrip_grammar
7780
COMMENT = /^#\s*(.*)$/.freeze
@@ -208,7 +211,7 @@ def read_value
208211
begin
209212
read_statement
210213
rescue RDF::ReaderError
211-
value = read_uriref || read_node || read_literal || read_quotedTriple
214+
value = read_uriref || read_node || read_literal || read_tripleTerm || read_quotedTriple
212215
log_recover
213216
value
214217
end
@@ -226,7 +229,7 @@ def read_triple
226229
unless blank? || read_comment
227230
subject = read_uriref || read_node || read_quotedTriple || fail_subject
228231
predicate = read_uriref(intern: true) || fail_predicate
229-
object = read_uriref || read_node || read_literal || read_quotedTriple || fail_object
232+
object = read_uriref || read_node || read_literal || read_tripleTerm || read_quotedTriple || fail_object
230233

231234
if validate? && !read_eos
232235
log_error("Expected end of statement (found: #{current_line.inspect})", lineno: lineno, exception: RDF::ReaderError)
@@ -242,12 +245,29 @@ def read_triple
242245

243246
##
244247
# @return [RDF::Statement]
248+
def read_tripleTerm
249+
if @options[:rdfstar] && match(TT_START)
250+
subject = read_uriref || read_node || fail_subject
251+
predicate = read_uriref(intern: true) || fail_predicate
252+
object = read_uriref || read_node || read_literal || read_tripleTerm || fail_object
253+
if !match(TT_END)
254+
log_error("Expected end of statement (found: #{current_line.inspect})", lineno: lineno, exception: RDF::ReaderError)
255+
end
256+
RDF::Statement.new(subject, predicate, object, tripleTerm: true)
257+
end
258+
end
259+
260+
##
261+
# @return [RDF::Statement]
262+
# @deprecated Quoted triples are now deprecated
245263
def read_quotedTriple
246-
if @options[:rdfstar] && match(ST_START)
264+
if @options[:rdfstar] && match(QT_START)
265+
warn "[DEPRECATION] RDF-star quoted triples are deprecated and will be removed in a future version.\n" +
266+
"Called from #{Gem.location_of_caller.join(':')}"
247267
subject = read_uriref || read_node || read_quotedTriple || fail_subject
248268
predicate = read_uriref(intern: true) || fail_predicate
249269
object = read_uriref || read_node || read_literal || read_quotedTriple || fail_object
250-
if !match(ST_END)
270+
if !match(QT_END)
251271
log_error("Expected end of statement (found: #{current_line.inspect})", lineno: lineno, exception: RDF::ReaderError)
252272
end
253273
RDF::Statement.new(subject, predicate, object, quoted: true)

0 commit comments

Comments
 (0)