class Boss::Parser

Parser implements IO-like behavior and provides deserializing of BOSS objects. Parser can store multiple root objects and share same object cache for all them

Public Class Methods

new(src=nil) click to toggle source

construct parser to read from the given string or IO-like object

# File lib/boss-protocol.rb, line 338
def initialize(src=nil)
  @io = src.class <= String ? StringIO.new(src) : src
  @io.set_encoding Encoding::BINARY if @io.respond_to? :set_encoding
  @rbyte       = @io.respond_to?(:readbyte) ? -> { @io.readbyte } : -> { @io.read(1).ord }
  @cache       = [nil]
  @stream_mode = false
end

Public Instance Methods

each() { |get until eof?| ... } click to toggle source

yields all objects in the stream

# File lib/boss-protocol.rb, line 438
def each
  yield get until eof?
end
eof?() click to toggle source

True is underlying IO-like object reached its end.

# File lib/boss-protocol.rb, line 432
def eof?
  @io.eof?
end
get() click to toggle source

Load the object (object tree) from the stream. Note that if there is more than one object in the stream that are stored with the same Formatter instance, they will share same cache and references, see Boss.Formatter.put for details. Note that nil is a valid restored object. Check eof? or catch EOFError, or use Boss.Parser.each to read all objects from the stream

# File lib/boss-protocol.rb, line 364
def get
  code, value = rhdr
  case code
    when TYPE_INT
      value
    when TYPE_NINT
      -value
    when TYPE_EXTRA
      case value
        when TTRUE
          true
        when TFALSE
          false
        when DZERO, FZERO
          0
        when DONE, FONE
          1.0
        when DMINUSONE, FMINUSONE
          -1.0
        when TDOUBLE
          rdouble
        when TCOMPRESSED
          type, size = rhdr
          data       = rbin size
          case type
            when 0
              Boss.load data
            when 1
              Boss.load Zlib::Inflate.new(Zlib::MAX_WBITS).inflate(data)
            #when 2
            #  Boss.load Bzip2.uncompress data
            else
              raise UnknownTypeException, "type #{type}"
          end
        when TTIME
          Time.at renc
        when XT_STREAM_MODE
          @cache       = [nil]
          @stream_mode = true
          get
        else
          raise UnknownTypeException
      end
    when TYPE_TEXT, TYPE_BIN
      s = rbin value
      s.force_encoding code == TYPE_BIN ? Encoding::BINARY : Encoding::UTF_8
      cache_object s
      s
    when TYPE_LIST
      #        p "items", value
      cache_object (list = [])
      value.times { list << get }
      list
    when TYPE_DICT
      cache_object (dict = {})
      value.times { dict[get] = get }
      dict
    when TYPE_CREF
      x = @cache[value]
      x.freeze if x.is_a?(String)
      x
    else
      raise UnknownTypeException
  end
end
read() click to toggle source

Load the object (object tree) from the stream. Note that if there is more than one object in the stream that are stored with the same Formatter instance, they will share same cache and references, see Boss.Formatter.put for details. Note that nil is a valid restored object. Check eof? or catch EOFError, or use Boss.Parser.each to read all objects from the stream

# File lib/boss-protocol.rb, line 353
def read
  get
end

Private Instance Methods

cache_object(object) click to toggle source
# File lib/boss-protocol.rb, line 444
def cache_object object
  # Stream mode?
  unless @stream_mode
    @cache << object
  end
end
rbin(length) click to toggle source
# File lib/boss-protocol.rb, line 502
def rbin(length)
  @io.read length
end
rbyte() click to toggle source
# File lib/boss-protocol.rb, line 490
def rbyte
  @rbyte.call
end
rdouble() click to toggle source
# File lib/boss-protocol.rb, line 494
def rdouble
  rbin(8).unpack('E')[0]
end
renc() click to toggle source

Read variable-length positive integer

# File lib/boss-protocol.rb, line 480
def renc
  value = i = 0
  loop do
    x     = rbyte
    value |= (x&0x7f) << i
    return value if x & 0x80 != 0
    i += 7
  end
end
rfloat() click to toggle source
# File lib/boss-protocol.rb, line 498
def rfloat
  rbin(4).unpack('e')[0]
end
rhdr() click to toggle source

Read header and return code,value

# File lib/boss-protocol.rb, line 453
def rhdr
  b           = rbyte
  code, value = b & 7, b >> 3
  case value
    when 0..22
      return code, value
    when 23...31
      return code, rlongint(value-22)
    else
      n = renc
      return code, rlongint(n)
  end
end
rlongint(bytes) click to toggle source

read n-bytes long positive integer

# File lib/boss-protocol.rb, line 469
def rlongint(bytes)
  res = i = 0
  bytes.times do
    res |= rbyte << i
    i   += 8
  end
  res
end