class RDF::NTriples::Writer

N-Triples serializer.

Output is serialized for UTF-8, to serialize as ASCII (with) unicode escapes, set encoding: Encoding::ASCII as an option to {RDF::NTriples::Writer#initialize}.

@example Obtaining an NTriples writer class

RDF::Writer.for(:ntriples)     #=> RDF::NTriples::Writer
RDF::Writer.for("etc/test.nt")
RDF::Writer.for(file_name:      "etc/test.nt")
RDF::Writer.for(file_extension: "nt")
RDF::Writer.for(content_type:   "application/n-triples")

@example Serializing RDF statements into an NTriples file

RDF::NTriples::Writer.open("etc/test.nt") do |writer|
  graph.each_statement do |statement|
    writer << statement
  end
end

@example Serializing RDF statements into an NTriples string

RDF::NTriples::Writer.buffer do |writer|
  graph.each_statement do |statement|
    writer << statement
  end
end

@example Serializing RDF statements into an NTriples string with escaped UTF-8

RDF::NTriples::Writer.buffer(encoding: Encoding::ASCII) do |writer|
  graph.each_statement do |statement|
    writer << statement
  end
end

@see www.w3.org/TR/rdf-testcases/#ntriples @see www.w3.org/TR/n-triples/

Constants

ESCAPE_PLAIN

@see www.w3.org/TR/rdf-testcases/#ntrip_strings

ESCAPE_PLAIN_U

Public Class Methods

escape(string, encoding = nil) click to toggle source

Escape Literal and URI content. If encoding is ASCII, all unicode is escaped, otherwise only ASCII characters that must be escaped are escaped.

@param [String] string @param [Encoding] encoding @return [String] @see www.w3.org/TR/rdf-testcases/#ntrip_strings

# File lib/rdf/ntriples/writer.rb, line 56
def self.escape(string, encoding = nil)
  ret = case
    when string.match?(ESCAPE_PLAIN) # a shortcut for the simple case
      string
    when string.ascii_only?
      StringIO.open do |buffer|
        buffer.set_encoding(Encoding::ASCII)
        string.each_byte { |u| buffer << escape_ascii(u, encoding) }
        buffer.string
      end
    when encoding && encoding != Encoding::ASCII
      # Not encoding UTF-8 characters
      StringIO.open do |buffer|
        buffer.set_encoding(encoding)
        string.each_char do |u|
          buffer << case u.ord
          when (0x00..0x7F)
            escape_ascii(u, encoding)
          else
            u
          end
        end
        buffer.string
      end
    else
      # Encode ASCII && UTF-8 characters
      StringIO.open do |buffer|
        buffer.set_encoding(Encoding::ASCII)
        string.each_codepoint { |u| buffer << escape_unicode(u, encoding) }
        buffer.string
      end
  end
  encoding ? ret.encode(encoding) : ret
end
escape_ascii(u, encoding) click to toggle source

Standard ASCII escape sequences. If encoding is ASCII, use Test-Cases sequences, otherwise, assume the test-cases escape sequences. Otherwise, the N-Triples recommendation includes ‘b` and `f` escape sequences.

Within STRING_LITERAL_QUOTE, only the characters ‘U+0022`, `U+005C`, `U+000A`, `U+000D` are encoded using `ECHAR`. `ECHAR` must not be used for characters that are allowed directly in STRING_LITERAL_QUOTE.

@param [Integer, ord] u @return [String] @raise [ArgumentError] if ‘u` is not a valid Unicode codepoint @see www.w3.org/TR/rdf-testcases/#ntrip_strings @see www.w3.org/TR/n-triples/

# File lib/rdf/ntriples/writer.rb, line 125
def self.escape_ascii(u, encoding)
  case (u = u.ord)
  when (0x08)       then "\\b"
  when (0x09)       then "\\t"
  when (0x0A)       then "\\n"
  when (0x0C)       then "\\f"
  when (0x0D)       then "\\r"
  when (0x22)       then "\\\""
  when (0x5C)       then "\\\\"
  when (0x00..0x1F) then escape_utf16(u)
  when (0x7F)       then escape_utf16(u)
  when (0x20..0x7E) then u.chr
  else
    raise ArgumentError.new("expected an ASCII character in (0x00..0x7F), but got 0x#{u.to_s(16)}")
  end
end
escape_unicode(u, encoding) click to toggle source

Escape ascii and unicode characters. If encoding is UTF_8, only ascii characters are escaped.

@param [Integer, ord] u @param [Encoding] encoding @return [String] @raise [ArgumentError] if ‘u` is not a valid Unicode codepoint @see www.w3.org/TR/rdf-testcases/#ntrip_strings

# File lib/rdf/ntriples/writer.rb, line 100
def self.escape_unicode(u, encoding)
  case (u = u.ord)
    when (0x00..0x7F)        # ASCII 7-bit
      escape_ascii(u, encoding)
    when (0x80..0xFFFF)      # Unicode BMP
      escape_utf16(u)
    when (0x10000..0x10FFFF) # Unicode
      escape_utf32(u)
    else
      raise ArgumentError.new("expected a Unicode codepoint in (0x00..0x10FFFF), but got 0x#{u.to_s(16)}")
  end
end
escape_utf16(u) click to toggle source

@param [Integer, ord] u @return [String] @see www.w3.org/TR/rdf-testcases/#ntrip_strings

# File lib/rdf/ntriples/writer.rb, line 146
def self.escape_utf16(u)
  sprintf("\\u%04X", u.ord)
end
escape_utf32(u) click to toggle source

@param [Integer, ord] u @return [String] @see www.w3.org/TR/rdf-testcases/#ntrip_strings

# File lib/rdf/ntriples/writer.rb, line 154
def self.escape_utf32(u)
  sprintf("\\U%08X", u.ord)
end
new(output = $stdout, validate: true, **options, &block) click to toggle source

Initializes the writer.

@param [IO, File] output

the output stream

@param [Boolean] validate (true)

whether to validate terms when serializing

@param [Hash{Symbol => Object}] options ({})

any additional options. See {RDF::Writer#initialize}

@yield [writer] ‘self` @yieldparam [RDF::Writer] writer @yieldreturn [void]

Calls superclass method RDF::Writer::new
# File lib/rdf/ntriples/writer.rb, line 191
def initialize(output = $stdout, validate: true, **options, &block)
  super
end
serialize(value) click to toggle source

Returns the serialized N-Triples representation of the given RDF value.

@param [RDF::Value] value @return [String] @raise [ArgumentError] if ‘value` is not an `RDF::Statement` or `RDF::Term`

# File lib/rdf/ntriples/writer.rb, line 165
def self.serialize(value)
  writer = (@serialize_writer_memo ||= self.new)
  case value
    when nil then nil
    when FalseClass then value.to_s
    when RDF::Statement
      writer.format_statement(value) + "\n"
    when RDF::Term
      writer.format_term(value)
    else
      raise ArgumentError, "expected an RDF::Statement or RDF::Term, but got #{value.inspect}"
  end
end

Public Instance Methods

escaped(string) click to toggle source

@private

# File lib/rdf/ntriples/writer.rb, line 337
def escaped(string)
  self.class.escape(string, encoding)
end
format_literal(literal, **options) click to toggle source

Returns the N-Triples representation of a literal.

@param [RDF::Literal, String, to_s] literal @param [Hash{Symbol => Object}] options ({}) @return [String]

# File lib/rdf/ntriples/writer.rb, line 321
def format_literal(literal, **options)
  case literal
    when RDF::Literal
      # Note, escaping here is more robust than in Term
      text = quoted(escaped(literal.value))
      text << "@#{literal.language}" if literal.language?
      text << "--#{literal.direction}" if literal.direction?
      text << "^^<#{uri_for(literal.datatype)}>" if literal.datatype?
      text
    else
      quoted(escaped(literal.to_s))
  end
end
format_node(node, unique_bnodes: false, **options) click to toggle source

Returns the N-Triples representation of a blank node.

@param [RDF::Node] node @param [Boolean] unique_bnodes (false)

Serialize node using unique identifier, rather than any used to create the node.

@param [Hash{Symbol => Object}] options ({}) @return [String]

# File lib/rdf/ntriples/writer.rb, line 267
def format_node(node, unique_bnodes: false, **options)
  unique_bnodes ? node.to_unique_base : node.to_s
end
format_quotedTriple(statement, **options) click to toggle source

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

# File lib/rdf/ntriples/writer.rb, line 242
def format_quotedTriple(statement, **options)
  # FIXME: quoted triples are now deprecated
  "<<%s %s %s>>" % statement.to_a.map { |value| format_term(value, **options) }
end
format_statement(statement, **options) click to toggle source

Returns the N-Triples representation of a statement.

@param [RDF::Statement] statement @param [Hash{Symbol => Object}] options ({}) @return [String]

# File lib/rdf/ntriples/writer.rb, line 221
def format_statement(statement, **options)
  format_triple(*statement.to_triple, **options)
end
format_triple(subject, predicate, object, **options) click to toggle source

Returns the N-Triples representation of a triple.

@param [RDF::Resource] subject @param [RDF::URI] predicate @param [RDF::Term] object @param [Hash{Symbol => Object}] options ({}) @return [String]

# File lib/rdf/ntriples/writer.rb, line 255
def format_triple(subject, predicate, object, **options)
  "%s %s %s ." % [subject, predicate, object].map { |value| format_term(value, **options) }
end
format_tripleTerm(statement, **options) click to toggle source

Returns the N-Triples representation of an RDF 1.2 triple term.

@param [RDF::Statement] statement @param [Hash{Symbol => Object}] options ({}) @return [String]

# File lib/rdf/ntriples/writer.rb, line 231
def format_tripleTerm(statement, **options)
  "<<(%s %s %s)>>" % statement.to_a.map { |value| format_term(value, **options) }
end
format_uri(uri, **options) click to toggle source

Returns the N-Triples representation of a URI reference using write encoding.

@param [RDF::URI] uri @param [Hash{Symbol => Object}] options ({}) @return [String]

# File lib/rdf/ntriples/writer.rb, line 277
def format_uri(uri, **options)
  string = uri.to_s
  iriref = case
    when string.match?(ESCAPE_PLAIN_U) # a shortcut for the simple case
      string
    when string.ascii_only? || (encoding && encoding != Encoding::ASCII)
      StringIO.open do |buffer|
        buffer.set_encoding(encoding)
        string.each_char do |u|
          buffer << case u.ord
            when (0x00..0x20) then self.class.escape_utf16(u)
            when 0x22, 0x3c, 0x3e, 0x5c, 0x5e, 0x60, 0x7b, 0x7c, 0x7d # "<>\^`{|}
              self.class.escape_utf16(u)
            else u
          end
        end
        buffer.string
      end
    else
      # Encode ASCII && UTF-8/16 characters
      StringIO.open do |buffer|
        buffer.set_encoding(Encoding::ASCII)
        string.each_byte do |u|
          buffer << case u
            when (0x00..0x20) then self.class.escape_utf16(u)
            when 0x22, 0x3c, 0x3e, 0x5c, 0x5e, 0x60, 0x7b, 0x7c, 0x7d # "<>\^`{|}
              self.class.escape_utf16(u)
            when (0x80..0xFFFF)                then self.class.escape_utf16(u)
            when (0x10000..0x10FFFF)           then self.class.escape_utf32(u)
            else u
          end
        end
        buffer.string
      end
  end
  encoding ? "<#{iriref}>".encode(encoding) : "<#{iriref}>"
end
write_comment(text) click to toggle source

Outputs an N-Triples comment line.

@param [String] text @return [void]

# File lib/rdf/ntriples/writer.rb, line 200
def write_comment(text)
  puts "# #{text.chomp}" # TODO: correctly output multi-line comments
end
write_triple(subject, predicate, object) click to toggle source

Outputs the N-Triples representation of a triple.

@param [RDF::Resource] subject @param [RDF::URI] predicate @param [RDF::Term] object @return [void]

# File lib/rdf/ntriples/writer.rb, line 211
def write_triple(subject, predicate, object)
  puts format_triple(subject, predicate, object, **@options)
end