"rdf" .
#
- # ## Quoted Triples
+ # ## Triple terms
+ #
+ # Supports statements as resources using `<<(s p o)>>`.
+
+ # ## Quoted Triples (Deprecated)
#
# Supports statements as resources using `<>`.
#
diff --git a/lib/rdf/ntriples/reader.rb b/lib/rdf/ntriples/reader.rb
index 4fbb21a1..93fe6d7a 100644
--- a/lib/rdf/ntriples/reader.rb
+++ b/lib/rdf/ntriples/reader.rb
@@ -70,8 +70,11 @@ class Reader < RDF::Reader
LANG_DIR = /@([a-zA-Z]+(?:-[a-zA-Z0-9]+)*(?:--[a-zA-Z]+)?)/.freeze
STRING_LITERAL_QUOTE = /"((?:[^\"\\\n\r]|#{ECHAR}|#{UCHAR})*)"/.freeze
- ST_START = /^<>/.freeze
+ TT_START = /^<<\(/.freeze
+ TT_END = /^\s*\)>>/.freeze
+
+ QT_START = /^<>/.freeze
# @see http://www.w3.org/TR/rdf-testcases/#ntrip_grammar
COMMENT = /^#\s*(.*)$/.freeze
@@ -208,7 +211,7 @@ def read_value
begin
read_statement
rescue RDF::ReaderError
- value = read_uriref || read_node || read_literal || read_quotedTriple
+ value = read_uriref || read_node || read_literal || read_tripleTerm || read_quotedTriple
log_recover
value
end
@@ -226,7 +229,7 @@ def read_triple
unless blank? || read_comment
subject = read_uriref || read_node || read_quotedTriple || fail_subject
predicate = read_uriref(intern: true) || fail_predicate
- object = read_uriref || read_node || read_literal || read_quotedTriple || fail_object
+ object = read_uriref || read_node || read_literal || read_tripleTerm || read_quotedTriple || fail_object
if validate? && !read_eos
log_error("Expected end of statement (found: #{current_line.inspect})", lineno: lineno, exception: RDF::ReaderError)
@@ -242,12 +245,29 @@ def read_triple
##
# @return [RDF::Statement]
+ def read_tripleTerm
+ if @options[:rdfstar] && match(TT_START)
+ subject = read_uriref || read_node || fail_subject
+ predicate = read_uriref(intern: true) || fail_predicate
+ object = read_uriref || read_node || read_literal || read_tripleTerm || fail_object
+ if !match(TT_END)
+ log_error("Expected end of statement (found: #{current_line.inspect})", lineno: lineno, exception: RDF::ReaderError)
+ end
+ RDF::Statement.new(subject, predicate, object, tripleTerm: true)
+ end
+ end
+
+ ##
+ # @return [RDF::Statement]
+ # @deprecated Quoted triples are now deprecated
def read_quotedTriple
- if @options[:rdfstar] && match(ST_START)
+ if @options[:rdfstar] && match(QT_START)
+ warn "[DEPRECATION] RDF-star quoted triples are deprecated and will be removed in a future version.\n" +
+ "Called from #{Gem.location_of_caller.join(':')}"
subject = read_uriref || read_node || read_quotedTriple || fail_subject
predicate = read_uriref(intern: true) || fail_predicate
object = read_uriref || read_node || read_literal || read_quotedTriple || fail_object
- if !match(ST_END)
+ if !match(QT_END)
log_error("Expected end of statement (found: #{current_line.inspect})", lineno: lineno, exception: RDF::ReaderError)
end
RDF::Statement.new(subject, predicate, object, quoted: true)
diff --git a/lib/rdf/ntriples/writer.rb b/lib/rdf/ntriples/writer.rb
index 3a1513a7..a69fc94a 100644
--- a/lib/rdf/ntriples/writer.rb
+++ b/lib/rdf/ntriples/writer.rb
@@ -223,15 +223,28 @@ def format_statement(statement, **options)
format_triple(*statement.to_triple, **options)
end
+ ##
+ # Returns the N-Triples representation of an RDF 1.2 triple term.
+ #
+ # @param [RDF::Statement] statement
+ # @param [Hash{Symbol => Object}] options ({})
+ # @return [String]
+ def format_tripleTerm(statement, **options)
+ "<<(%s %s %s)>>" % statement.to_a.map { |value| format_term(value, **options) }
+ end
+
##
# Returns the N-Triples representation of an RDF-star quoted triple.
#
# @param [RDF::Statement] statement
# @param [Hash{Symbol => Object}] options ({})
# @return [String]
+ # @deprecated Quoted triples are now deprecated
def format_quotedTriple(statement, **options)
+ # FIXME: quoted triples are now deprecated
"<<%s %s %s>>" % statement.to_a.map { |value| format_term(value, **options) }
end
+
##
# Returns the N-Triples representation of a triple.
#
diff --git a/lib/rdf/repository.rb b/lib/rdf/repository.rb
index 69f053bd..c7cfb0ca 100644
--- a/lib/rdf/repository.rb
+++ b/lib/rdf/repository.rb
@@ -182,6 +182,8 @@ def supports?(feature)
when :validity then @options.fetch(:with_validity, true)
when :literal_equality then true
when :atomic_write then false
+ when :rdf_full then false
+ # FIXME: quoted triples are now deprecated
when :quoted_triples then false
when :base_direction then false
when :snapshots then false
@@ -270,6 +272,7 @@ def supports?(feature)
when :validity then @options.fetch(:with_validity, true)
when :literal_equality then true
when :atomic_write then true
+ when :rdf_full then true
when :quoted_triples then true
when :base_direction then true
when :snapshots then true
diff --git a/lib/rdf/writer.rb b/lib/rdf/writer.rb
index c8d1ee46..a9afbbdc 100644
--- a/lib/rdf/writer.rb
+++ b/lib/rdf/writer.rb
@@ -518,7 +518,8 @@ def format_term(term, **options)
when RDF::Literal then format_literal(term, **options)
when RDF::URI then format_uri(term, **options)
when RDF::Node then format_node(term, **options)
- when RDF::Statement then format_quotedTriple(term, **options)
+ # FIXME: quoted triples are now deprecated
+ when RDF::Statement then term.tripleTerm? ? format_tripleTerm(term, **options) : format_quotedTriple(term, **options)
else nil
end
end
@@ -566,7 +567,7 @@ def format_list(value, **options)
end
##
- # Formats a referenced triple.
+ # Formats a referenced triple term.
#
# @example
# << >> .
@@ -576,8 +577,24 @@ def format_list(value, **options)
# @return [String]
# @raise [NotImplementedError] unless implemented in subclass
# @abstract
+ def format_tripleTerm(value, **options)
+ raise NotImplementedError.new("#{self.class}#format_tripleTerm") # override in subclasses
+ end
+
+ ##
+ # Formats a referenced quoted triple.
+ #
+ # @example
+ # << >> .
+ #
+ # @param [RDF::Statement] value
+ # @param [Hash{Symbol => Object}] options = ({})
+ # @return [String]
+ # @raise [NotImplementedError] unless implemented in subclass
+ # @abstract
+ # @deprecated Quoted Triples are now deprecated in favor of Triple Terms
def format_quotedTriple(value, **options)
- raise NotImplementedError.new("#{self.class}#format_statement") # override in subclasses
+ raise NotImplementedError.new("#{self.class}#format_quotedTriple") # override in subclasses
end
protected
diff --git a/spec/model_statement_spec.rb b/spec/model_statement_spec.rb
index a159edb8..46558700 100644
--- a/spec/model_statement_spec.rb
+++ b/spec/model_statement_spec.rb
@@ -75,7 +75,8 @@
it {is_expected.to have_object}
its(:object) {is_expected.not_to be_nil}
it {is_expected.to be_asserted}
- it {is_expected.not_to be_quoted}
+ it {is_expected.not_to be_tripleTerm}
+ it {is_expected.not_to be_quoted} # FIXME: quoted triples are deprecated
it {is_expected.to be_statement}
it {is_expected.not_to be_inferred}
its(:terms) {is_expected.to include(s, p, o)}
@@ -210,6 +211,12 @@
it {is_expected.to be_inferred}
end
+ context "when marked as tripleTerm" do
+ subject {RDF::Statement.new(RDF::Node.new, p, o, tripleTerm: true)}
+ it {is_expected.to be_tripleTerm}
+ end
+
+ # FIXME: quoted triples are deprecated
context "when marked as quoted" do
subject {RDF::Statement.new(RDF::Node.new, p, o, quoted: true)}
it {is_expected.to be_quoted}
diff --git a/spec/nquads_spec.rb b/spec/nquads_spec.rb
index 9dd84178..3e5b1dfa 100644
--- a/spec/nquads_spec.rb
+++ b/spec/nquads_spec.rb
@@ -180,7 +180,8 @@
end
end
- context "RDF-star" do
+ # FIXME: quoted triples are deprecated
+ context "quoted triples" do
statements = {
"subject-iii": '<< >> .',
"subject-iib": '<< _:o1>> .',
@@ -205,7 +206,13 @@
statements.each do |name, st|
context name do
- let(:graph) {RDF::Graph.new << RDF::NQuads::Reader.new(st, rdfstar: true)}
+ let(:graph) do
+ g = RDF::Graph.new
+ expect do
+ g << RDF::NQuads::Reader.new(st, rdfstar: true)
+ end.to write('[DEPRECATION]').to(:error)
+ g
+ end
it "creates two statements" do
expect(graph.count).to eql(1)
diff --git a/spec/ntriples_spec.rb b/spec/ntriples_spec.rb
index 0d42ff09..95ae52fa 100644
--- a/spec/ntriples_spec.rb
+++ b/spec/ntriples_spec.rb
@@ -432,6 +432,78 @@
end
end
+ context "triple terms" do
+ ill_statements = {
+ "subject-iii": '<<( )>> .',
+ "subject-iib": '<<( _:o1)>> .',
+ "subject-iil": '<<( "o1")>> .',
+ "subject-bii": '<<(_:s1 )>> .',
+ "subject-bib": '<<(_:s1 _:o1)>> .',
+ "subject-bil": '<<(_:s1 "o")>> .',
+ "subject-ws": '<<( )>> .',
+ "recursive-subject": '<<(<<( )>> )>> .',
+ }
+
+ statements = {
+ "object-iii": ' <<( )>> .',
+ "object-iib": ' <<( _:o1)>> .',
+ "object-iil": ' <<( "o1")>> .',
+ "object-bii": ' <<(_:s1 )>> .',
+ "object-bib": ' <<(_:s1 _:o1)>> .',
+ "object-bil": ' <<(_:s1 "o1")>> .',
+ "object-ws": ' <<( )>> .',
+
+ "recursive-object": ' <<( <<( )>>)>> .',
+ }
+
+ context "without rdfstar option" do
+ it "Raises an error" do
+ expect do
+ expect {parse(statements.values.first)}.to raise_error(RDF::ReaderError)
+ end.to write(:something).to(:error)
+ end
+ end
+
+ context "with rdfstar option" do
+ ill_statements.each do |name, st|
+ context name do
+ it "Raises an error" do
+ expect do
+ expect {parse(st)}.to raise_error(RDF::ReaderError)
+ end.to write(:something).to(:error)
+ end
+ end
+ end
+
+ statements.each do |name, st|
+ context name do
+ let(:graph) {parse(st, rdfstar: true)}
+
+ it "creates two unquoted statements" do
+ expect(graph.count).to eql(1)
+ graph.statements.each do |stmt|
+ expect(stmt).not_to be_quoted
+ end
+ end
+
+ it "has a statement whose object is a statement" do
+ referencing = graph.statements.first
+ expect(referencing).to be_a_statement
+ expect(referencing.object).to be_a_statement
+ end
+
+ it "statements which are object of another statement are triple terms" do
+ referencing = graph.statements.first
+ expect(referencing).to be_a_statement
+ expect(referencing.object).to be_a_statement
+ expect(referencing.object).to be_tripleTerm
+ end
+ end
+ end
+ end
+ end
+
+ # FIXME: quoted triples are deprecated
context "quoted triples" do
statements = {
"subject-iii": '<< >> .',
@@ -459,7 +531,7 @@
context "with rdfstar option" do
statements.each do |name, st|
context name do
- let(:graph) {parse(st, rdfstar: true)}
+ let(:graph) {parse(st, rdfstar: true, deprecated: true)}
it "creates two unquoted statements" do
expect(graph.count).to eql(1)
@@ -1205,10 +1277,19 @@ def parse(input, **options)
options = {
validate: false,
canonicalize: false,
+ deprecated: false,
}.merge(options)
graph = options[:graph] || RDF::Graph.new
- RDF::NTriples::Reader.new(input, **options).each do |statement|
- graph << statement
+ if options[:deprecated]
+ expect do
+ RDF::NTriples::Reader.new(input, **options).each do |statement|
+ graph << statement
+ end
+ end.to write('[DEPRECATION]').to(:error)
+ else
+ RDF::NTriples::Reader.new(input, **options).each do |statement|
+ graph << statement
+ end
end
graph
end
diff --git a/spec/query_pattern_spec.rb b/spec/query_pattern_spec.rb
index 37a68783..bbd1d466 100644
--- a/spec/query_pattern_spec.rb
+++ b/spec/query_pattern_spec.rb
@@ -282,7 +282,7 @@
end
end
- context "quoted triples" do
+ context "triple terms" do
let(:s) {RDF::Query::Variable.new(:s)}
let(:p) {RDF::Query::Variable.new(:p)}
let(:o) {RDF::Query::Variable.new(:o)}