module OTNetstring

Public Class Methods

encode(obj, string_sep = ',') click to toggle source
# File lib/otnetstring.rb, line 62
def encode(obj, string_sep = ',')
  case obj
  when String   then with_encoding "#{obj.bytesize}#{string_sep}#{obj}", "binary"
  when Integer  then encode(obj.inspect, '#')
  when NilClass then "0~"
  when Array    then encode(obj.map { |e| encode(e) }.join, '[')
  when Hash     then encode(obj.map { |a,b| encode(a)+encode(b) }.join, '{')
  when FalseClass, TrueClass then encode(obj.inspect, '!')
  else raise Error, 'cannot encode %p' % obj
  end
end
parse(io, encoding = 'internal', fallback_encoding = nil) click to toggle source
# File lib/otnetstring.rb, line 28
def parse(io, encoding = 'internal', fallback_encoding = nil)
  fallback_encoding = io.encoding if io.respond_to? :encoding
  io = StringIO.new(io) if io.respond_to? :to_str
  length, byte = String.new, nil

  while byte.nil? || byte =~ /\d/
    length << byte if byte
    byte = io.read(1)
  end

  if length.size > 9
    raise Error, "#{length} is longer than 9 digits"
  elsif length !~ /\d+/
    raise Error, "Expected '#{byte}' to be a digit"
  end
  length = Integer(length)

  case byte
  when '#' then Integer io.read(length)
  when ',' then with_encoding io.read(length), encoding, fallback_encoding
  when '~' then
    raise Error, "nil has length of 0, #{length} given" unless length == 0
  when '!' then io.read(length) == 'true'
  when '[', '{'
    array = []
    start = io.pos
    array << parse(io, encoding, fallback_encoding) while io.pos - start < length
    raise Error, 'Nested element longer than container' if io.pos - start != length
    byte == "{" ? Hash[*array] : array
  else
    raise Error, "Unknown type '#{byte}'"
  end
end

Private Class Methods

with_encoding(str, encoding, fallback = nil) click to toggle source
# File lib/otnetstring.rb, line 76
def with_encoding(str, encoding, fallback = nil)
  return str unless str.respond_to? :encode
  encoding = Encoding.find encoding if encoding.respond_to? :to_str
  encoding ||= fallback
  encoding ? str.encode(encoding) : str
rescue EncodingError
  str.force_encoding(encoding)
end