class Boss::Formatter

Formats ruby object hierarchies with BOSS notation

Public Class Methods

new(dst=nil) click to toggle source

Construct formatter for a given IO-like object or create StringIO one as output

# File lib/boss-protocol.rb, line 122
def initialize(dst=nil)
  @io = dst ? dst : StringIO.new('', 'wb')
  @io.set_encoding Encoding::BINARY if @io.respond_to? :set_encoding
  @cache       = { nil => 0 }
  @stream_mode = false
end

Public Instance Methods

<<(ob)
Alias for: put
get_stream() click to toggle source
# File lib/boss-protocol.rb, line 129
def get_stream
  @io
end
put(ob) click to toggle source

Put object tree routed as ob to the output. Alias: <<. It is possible to put more than one object to the same Formatter. Not that formatter has per-instance cache so put(x) put(x) put(x) will store one object and 2 more refs to it, so on load time only one object will be constructed and 2 more refs will be created.

# File lib/boss-protocol.rb, line 177
def put(ob)
  case ob
    when Fixnum, Bignum
      if ob < 0
        whdr TYPE_NINT, -ob
      else
        whdr TYPE_INT, ob
      end
    when String, Symbol
      ob = ob.to_s unless ob.is_a?(String)
      if notCached(ob)
        if ob.encoding == Encoding::BINARY
          whdr TYPE_BIN, ob.length
          wbin ob
        else
          whdr TYPE_TEXT, ob.bytesize
          wbin ob.dup.encode(Encoding::UTF_8)
        end
      end
    when Array
      if notCached(ob)
        whdr TYPE_LIST, ob.length
        ob.each { |x| put(x) }
      end
    when Hash
      if notCached(ob)
        whdr TYPE_DICT, ob.length
        ob.each { |k, v| self << k << v }
      end
    when Float
      case ob
        when 0
          whdr TYPE_EXTRA, DZERO
        when -1.0
          whdr TYPE_EXTRA, DMINUSONE
        when +1.0
          whdr TYPE_EXTRA, DONE
        else
          whdr TYPE_EXTRA, TDOUBLE
          wdouble ob
      end
    when TrueClass, FalseClass
      whdr TYPE_EXTRA, ob ? TTRUE : TFALSE
    when nil
      whdr TYPE_CREF, 0
    when Time
      whdr TYPE_EXTRA, TTIME
      wrenc ob.to_i
    else
      error = "error: not supported object: #{ob}, #{ob.class}"
      raise NotSupportedException, error
  end
  self
end
Also aliased as: <<
put_compressed(ob) click to toggle source

same as put but automatically select and use proper compression. Parser.get will automatically decompress.

# File lib/boss-protocol.rb, line 150
def put_compressed ob
  data = Boss.dump(ob)
  whdr TYPE_EXTRA, TCOMPRESSED
  type = case data.length
           when 0..160
             0
           when 161..8192
             data = Zlib::Deflate.new.deflate(data, Zlib::FINISH)
             1
           else
             data = Zlib::Deflate.new.deflate(data, Zlib::FINISH)
             1
           #data = Bzip2.compress data
           #2
         end
  whdr type, data.length
  wbin data
end
set_stream_mode() click to toggle source

Switch to stream mode. Stream mode turns off caching.

# File lib/boss-protocol.rb, line 140
def set_stream_mode
  @stream_mode = true
  whdr TYPE_EXTRA, XT_STREAM_MODE
  @cache = { nil => 0 }
end
stream_mode() click to toggle source

Switch to stream mode. Stream mode turns off caching.

# File lib/boss-protocol.rb, line 135
def stream_mode
  set_stream_mode
end
string() click to toggle source

Get the result as string, may not work if some specific IO instance is passed to constructor. works well with default constructor or StringIO

# File lib/boss-protocol.rb, line 238
def string
  @io.string
end

Private Instance Methods

notCached(obj) click to toggle source

Write cache ref if the object is cached, and return true otherwise store object in the cache. Caller should write object to @io if notCached return true, and skip writing otherwise

# File lib/boss-protocol.rb, line 249
def notCached(obj)
  n = @cache[obj]
  if n
    whdr TYPE_CREF, n
    false
  else
    # Check stream mode, bin and strings only
    unless @stream_mode
      @cache[obj] = @cache.length
    end
    true
  end
end
sizeBytes(value) click to toggle source

Determine minimum amount of bytes needed to store value (should be positive integer)

# File lib/boss-protocol.rb, line 298
def sizeBytes(value)
  checkArg value >= 0
  mval = 0x100
  cnt  = 1
  while value >= mval
    cnt  += 1
    mval <<= 8
  end
  cnt
end
wbin(bb) click to toggle source

write binary value

# File lib/boss-protocol.rb, line 312
def wbin(bb)
  @io.write bb
end
wbyte(b) click to toggle source

write single byte

# File lib/boss-protocol.rb, line 318
def wbyte(b)
  @io << b.chr
end
wdouble(val) click to toggle source
# File lib/boss-protocol.rb, line 322
def wdouble val
  wbin [val].pack('E')
end
whdr(code, value) click to toggle source

write standard record header with code and value

# File lib/boss-protocol.rb, line 277
def whdr(code, value)
  checkArg code.between?(0, 7)
  checkArg value >= 0
  #      p "WHDR #{code}, #{value}"
  if value < 23
    wbyte code | value<<3
  else
    # Get the size of the value (0..9)
    if (n=sizeBytes(value)) < 9
      wbyte code | (n+22) << 3
    else
      wbyte code | 0xF8
      wrenc n
    end
    n.times { wbyte value & 0xff; value >>=8 }
  end
end
wrenc(value) click to toggle source

Write variable-length positive integer

# File lib/boss-protocol.rb, line 265
def wrenc(value)
  checkArg value >= 0
  while value > 0x7f
    wbyte value & 0x7f
    value >>= 7
  end
  wbyte value | 0x80
end