slides

Transit-Ruby   slide




David Chelimsky
Chicago Ruby Meetup
2 September 2014

Problem / Goals   slide

  • convey values between programs written in different languages
  • types
  • optional schema
  • extensibility
  • good performance
  • reach (including browser)

Transit   slide

Types   slide

  • ground types (generally represented as/is in JSON or MessagePack)
    • scalar
      • null, string, boolean, integer, float, byte array,
    • composite
      • array, map
  • built-in extension types
    • scalar
      • keyword, symbol, arbitrary precision integer and decimal, point in time, uuid, uri, char, quoted value
        • special numbers (NaN, INF, -INF) coming this week
    • composite
      • set, list, map w/ composite keys, link
  • custom extensions
    • use exactly same mechanism as built-in extension types

transit-ruby   slide

require 'transit'

########################

writer = Transit::Writer.new(:json_verbose, STDOUT)
writer.write({:answer => 42})
# => "{\"~:answer\":42}"

reader = Transit::Reader.new(:json, StringIO.new("{\"~:answer\":42}"))
reader.read
# => {:answer=>42}

########################

writer = Transit::Writer.new(:json, STDOUT)
writer.write({:answer => 42})
# => "[\"^ \",\"~:answer\",42]"

reader = Transit::Reader.new(:json, StringIO.new("[\"^ \",\"~:answer\",42]"))
reader.read
# => {:answer=>42}

Type Mappings   slide

Transit type Write accepts Read returns
null nil nil
string String String
boolean true, false true, false
integer Fixnum, Bignum Fixnum, Bignum
float Float Float
keyword Symbol Symbol
big decimal BigDecimal BigDecimal
big integer Fixnum, Bignum Fixnum, Bignum
time DateTime, Date, Time DateTime
uri Addressable::URI, URI Addressable::URI
uuid Transit::UUID Transit::UUID
char Transit::TaggedValue String
array Array Array
list Transit::TaggedValue Array
set Set Set
map Hash Hash
bytes Transit::ByteArray Transit::ByteArray
link Transit::Link Transit::Link

Special case type mappings   slide

Transit type Write accepts Read returns
point in time DateTime, Date, Time DateTime
uri Addressable::URI, URI Addressable::URI
  • Ruby Date, Time, and DateTime all have subtly different semantics
    • DateTime is richer and parses Strings faster
  • Addressable::URI supports
    • more protocols than URI
    • UTF-8

Special case type mappings: Transit::Types   slide

Transit type Write accepts Read returns
symbol Transit::Symbol Transit::Symbol
uuid Transit::UUID Transit::UUID
bytes Transit::ByteArray Transit::ByteArray
link Transit::Link Transit::Link

Special case type mappings: TaggedValues   slide

Transit type Write accepts Read returns
char Transit::TaggedValue String
list Transit::TaggedValue Array

More on TaggedValues   slide

  • everything is a tagged value in the wire format
  • implementations handle all the built-in types
    • but what about custom types?
  • Transit::TaggedValue is the default when a reader encounters a tag it doesn't understand
require 'transit'
require 'json'

reader = Transit::Reader.new(:json, StringIO.new({"~#unrecognized-tag" => [:some, :data]}.to_json))
reader.read
# => #<Transit::TaggedValue:... @tag="unrecognized-tag", @rep=["some", "data"]>
  • makes everything round-tripable
  • supports dumb middle-men

Extensibility   slide

  • define a semantic type
    • immutable values
    • language independent
  • choose a tag
    • single capital letter for scalars
    • 2 or more chars for composite types
  • implement write and read handlers
    • only in the languages that need to write or read
    • TaggedValues allow you to pass through other implementations without handlers

Example   slide

# semantic type: point
# tag: "point"
# rep: [int,int]

require 'ostruct'

Point = Struct.new(:x,:y) do
  def to_a; [x,y] end
end

class PointWriteHandler
  def tag(_) "point" end
  def rep(p) p.to_a end
  def string_rep(_) nil end
end

io = StringIO.new('','w+')
writer = Transit::Writer.new(:json_verbose, io, :handlers => {Point => PointWriteHandler.new})
writer.write(Point.new(37,42))
io.string
# => "{\"~#point\":[37,42]}\n"

class PointReadHandler
  def from_rep(rep)
    Point.new(*rep)
  end
end

reader = Transit::Reader.new(:json, StringIO.new(io.string), :handlers => {"point" => PointReadHandler.new})
reader.read
# => #<struct Point x=37, y=42>

END

Author: David Chelimsky

Created: 2014-09-03 Wed 06:55

Emacs 24.3.1 (Org mode 8.2.5h)

Validate