Class: AceMQ::AMQP::TOMLCodec

Inherits:
Object
  • Object
show all
Defined in:
lib/acemq/amqp/codec/toml.rb,
lib/acemq/amqp/codec/toml/reader.rb,
lib/acemq/amqp/codec/toml/writer.rb

Overview

Reads and writes TOML.

The same audience as YAMLCodec — a message a person reads and edits — with the ambiguity removed. TOML has one way to write a string, no significant indentation, and no Norway problem: in YAML country: NO is the boolean false, while here an unquoted NO is a parse error rather than a country that quietly became a boolean. Where a human edits the message and a machine acts on it, that matters more than terseness.

A poor choice for high volume: it is text, it is larger than JSON, and it parses more slowly than any of the binary formats.

The shape of the data has to suit it

TOML is a table format, so a message body is an object at the top level. A bare list or a bare number is not a TOML document, and this says so rather than writing something no parser will read back. Deep nesting reads poorly too; where the payload is a tree rather than a table, JSON is the honest answer.

Why the parser is written here

There is no TOML parser in Ruby's standard library and this gem declares no runtime dependencies, so the reader and writer below are the codec. The bar they are held to is the one that matters: the bytes Jackson's TomlMapper writes in the Java library and the bytes BurntSushi's encoder writes in the Go one. Those two do not agree on everything — Jackson quotes strings with ' and Go with " — so a reader that handled only one of them would be a codec that could read half the estate.

Defined Under Namespace

Classes: Reader, Writer

Constant Summary collapse

CONTENT_TYPE =

What this codec writes: the type the TOML specification registered, and what Java, Go and .NET write.

"application/toml"
ALSO_READS =

Predates the registration and is still what a lot of tooling writes.

["text/toml"].freeze

Instance Method Summary collapse

Instance Method Details

#can_decode?(content_type) ⇒ Boolean

Accepts application/toml, text/toml and any +...+toml+ media type.

Never a message whose sender set no content type: the same reasoning as YAMLCodec. A sender that said nothing is almost always sending JSON, and answering would be right about the value and wrong about the format.

Returns:

  • (Boolean)


91
92
93
94
95
96
# File 'lib/acemq/amqp/codec/toml.rb', line 91

def can_decode?(content_type)
  lower = content_type.to_s.downcase
  return false if lower.empty?

  lower.start_with?(CONTENT_TYPE, *ALSO_READS) || lower.include?("+toml")
end

#content_type ⇒ Object



60
# File 'lib/acemq/amqp/codec/toml.rb', line 60

def content_type = CONTENT_TYPE

#decode(body) ⇒ Hash

Parameters:

  • body (String)

Returns:

  • (Hash)

Raises:



80
81
82
83
84
# File 'lib/acemq/amqp/codec/toml.rb', line 80

def decode(body)
  Reader.new(body.to_s).parse
rescue Reader::Invalid => e
  raise DecodeError, "this message is not TOML: #{e.message}"
end

#encode(payload) ⇒ String

Parameters:

  • payload (Hash) —

    a table; TOML has no document that is not one

Returns:

  • (String)

Raises:

  • (EncodeError) —

    when the payload is not a table, or holds a value TOML cannot spell



66
67
68
69
70
71
72
73
74
75
# File 'lib/acemq/amqp/codec/toml.rb', line 66

def encode(payload)
  unless payload.is_a?(Hash)
    raise EncodeError,
          "cannot encode a #{payload.class} as TOML: a TOML document is a table, so " \
          "the top level has to be a Hash. A list, a string or a number has no TOML " \
          "representation — wrap it in a hash with a named key, or use JSON."
  end

  Writer.new.write(payload)
end