Skip to content

Commit

Permalink
Update writer and sync production names.
Browse files Browse the repository at this point in the history
  • Loading branch information
gkellogg committed Aug 19, 2024
1 parent 430c874 commit 7ecbbd9
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 27 deletions.
2 changes: 1 addition & 1 deletion etc/turtle.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ iri ::= IRIREF | PrefixedName
PrefixedName ::= PNAME_LN | PNAME_NS
BlankNode ::= BLANK_NODE_LABEL | ANON
reifier ::= '~' (iri | BlankNode)?
reifiedTriple ::= '<<' (subject | reifiedTriple) predicate object reifier* '>>'
reifiedTriple ::= '<<' (subject | reifiedTriple) predicate object reifier? '>>'
tripleTerm ::= '<<(' ttSubject predicate ttObject ')>>'
ttSubject ::= iri | BlankNode
ttObject ::= iri | BlankNode | literal | tripleTerm
Expand Down
6 changes: 3 additions & 3 deletions lib/rdf/turtle/reader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ def read_object(subject = nil, predicate = nil)
##
# Read reifiedTriple
#
# reifiedTriple ::= '<<' (subject | reifiedTriple) predicate object reifier* '>>'
# reifiedTriple ::= '<<' (subject | reifiedTriple) predicate object reifier? '>>'
#
# @return [RDF::Term]
def read_reifiedTriple
Expand Down Expand Up @@ -537,7 +537,7 @@ def read_ttObject(subject = nil, predicate = nil)
##
# Read an annotation on a triple
#
# annotation := (reifier | '{|' predicateObjectList '|}')*
# annotation := (reifier | annotationBlock)*
#
# The `reifier` becomes the identifier for a subsequent annotation block (if it exists). If there is no reifier, then a blank node is created.
def read_annotation(subject, predicate, object)
Expand All @@ -548,7 +548,7 @@ def read_annotation(subject, predicate, object)

while %w(~ {|).include? @lexer.first.to_s
if @lexer.first === '~'
prod(:annotation, %(~})) do
prod(:annotation, %(~)) do
@lexer.shift # eat '~'
# Emit any pending reifiedTriple if there was no annotation block
add_statement('annotation', RDF::Statement(id, RDF.reifies, tt)) if id
Expand Down
43 changes: 22 additions & 21 deletions lib/rdf/turtle/writer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ def format_node(node, **options)
# @param [Hash{Symbol => Object}] options
# @return [String]
def format_tripleTerm(statement, **options)
log_debug("rdfstar") {"#{statement.to_ntriples}"}
log_debug("tripleTerm") {"#{statement.to_ntriples}"}
"<<(%s %s %s)>>" % statement.to_a.map { |value| format_term(value, **options) }
end

Expand Down Expand Up @@ -443,7 +443,7 @@ def preprocess_statement(statement, as_subject: true)
statement.to_a.each {|t| @in_triple_term[t] = true}
end

# If it fits, allow this to be rendered as a reification
# If it fits, allow this to be rendered as a reifiedTriple
if statement.object.statement? && statement.predicate == RDF.reifies
@reification[statement.subject] ||= []
@reification[statement.subject] << statement.object unless
Expand Down Expand Up @@ -483,7 +483,7 @@ def reset
@serialized = {}
@subjects = {}
@reification = {}
@as_reification = {}
@as_reifiedTriple = {}
@in_triple_term = {}
end

Expand Down Expand Up @@ -572,7 +572,7 @@ def collection(node, position)
def blankNodePropertyList?(resource, position)
!resource.statement? && resource.node? &&
!collection?(resource) &&
!reification?(resource, position) &&
!reifiedTriple?(resource, position) &&
!in_triple_term?(resource) &&
(!is_done?(resource) || position == :subject) &&
ref_count(resource) == (position == :object ? 1 : 0)
Expand All @@ -590,33 +590,34 @@ def blankNodePropertyList(resource, position)
true
end

# Is this a reification?
def reification?(resource, position)
# Is this a reifiedTriple?
def reifiedTriple?(resource, position)
@reification.key?(resource) &&
(position == :subject ? (prop_count(resource) > 0) : (prop_count(resource) == 0))
end

# Render a reification
def reification(resource, position)
return false unless reification?(resource, position)
# Render a reifiedTriple
def reifiedTriple(resource, position)
return false unless reifiedTriple?(resource, position)
write_id = resource.iri? || ref_count(resource) > 1
@as_reification[resource] = true # Prevent rdf:reifies from being emitted
@as_reifiedTriple[resource] = true # Prevent rdf:reifies from being emitted

log_debug("reification") {resource.to_ntriples}
log_debug("reifiedTriple") {resource.to_ntriples}
subject_done(resource)
# There may be multiple reifications using this resource
# There may be multiple reifiedTriples using this resource
@reification[resource].each do |tt|
@output.write(position == :subject ? "\n#{indent} << " : '<< ')
reifiedTriple(tt.subject, :object) || p_term(tt.subject, :object)
@output.write(' ')
predicate(tt.predicate)
@output.write(' ')
reifiedTriple(tt.object, :object) || p_term(tt.object, :object)

if write_id
# Only need to output blank node identifiers if they have more than one reference
@output.write(' ~')
p_term(resource, :subject)
@output.write(' | ')
end
reification(tt.subject, :object) || p_term(tt.subject, :object)
@output.write(' ')
predicate(tt.predicate)
@output.write(' ')
reification(tt.object, :object) || p_term(tt.object, :object)
@output.write(' >>')
end
true
Expand Down Expand Up @@ -645,7 +646,7 @@ def path(resource, position)
end
raise RDF::WriterError, "Cannot serialize resource '#{resource}'" unless
collection(resource, position) ||
reification(resource, position) ||
reifiedTriple(resource, position) ||
blankNodePropertyList(resource, position) ||
p_term(resource, position)
end
Expand Down Expand Up @@ -677,7 +678,7 @@ def objectList(subject, predicate, objects)
reifs = @reification.select {|k, v| v.include?(tt)}.keys
if reifs.length == 1
reif = reifs.first
@as_reification[reif] = true
@as_reifiedTriple[reif] = true
@output.write ' {| '
predicateObjectList(reif, true)
@output.write ' |}'
Expand All @@ -693,7 +694,7 @@ def predicateObjectList(subject, from_bpl = false)

prop_list = sort_properties(properties)
prop_list -= [RDF.first, RDF.rest] if @lists.key?(subject)
prop_list -= [RDF.reifies] if @as_reification.key?(subject)
prop_list -= [RDF.reifies] if @as_reifiedTriple.key?(subject)
log_debug("predicateObjectList") {prop_list.inspect}
return 0 if prop_list.empty?

Expand Down
26 changes: 24 additions & 2 deletions spec/writer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -653,15 +653,15 @@
regexp: [
%r(ex:s ex:p <<\(\s*ex:s1 ex:p1 <<\(\s*ex:s2 ex:p2 ex:o2*\s*\)>>\s*\)>>)
]
},
}
}.each do |name, params|
it name do
graph = RDF::Graph.new {|g| g << params[:input]}
serialize(graph, params.fetch(:regexp, []), prefixes: {ex: 'http://example/'}, **params)
end
end

context "reifications" do
context "reifiedTriples" do
{
"subject-iii": {
input: %(
Expand Down Expand Up @@ -765,6 +765,28 @@
%r(<<\s*<<\s*ex:s2 ex:p2 ex:o2\s*>> ex:p1 ex:o1\s*>> ex:p ex:o .)
]
},
"explicit reifier as subject": {
input: %(
PREFIX : <http://example/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
:r rdf:reifies <<( :s :p :o )>> .
:r :p1 :o1 .
),
regexp: [
%r(<<\s*ex:s ex:p ex:o\s*~\s*ex:r\s*>>\s*ex:p1 ex:o1 .)
]
},
"explicit reifier as object": {
input: %(
PREFIX : <http://example/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
:r rdf:reifies <<( :s :p :o )>> .
:s1 :p1 :r .
),
regexp: [
%r(ex:s1 ex:p1 <<\s*ex:s ex:p ex:o\s*~\s*ex:r\s*>>\s*.)
]
},
}.each do |name, params|
it name do
graph = RDF::Graph.new {|g| g << parse(params[:input], rdfstar: true)}
Expand Down

0 comments on commit 7ecbbd9

Please sign in to comment.