class BEncoder
Public Class Methods
decode(string)
click to toggle source
# File lib/bencoder.rb, line 25 def decode(string) parse string end
encode(object)
click to toggle source
# File lib/bencoder.rb, line 8 def encode(object) case object when Symbol encode object.to_s when String encode_string object when Integer encode_int object when Array encode_array object when Hash encode_hash object else raise UnencodableTypeError, "Cannot encode instance of type #{object.class}" end end
Private Class Methods
encode_array(array)
click to toggle source
# File lib/bencoder.rb, line 124 def encode_array(array) array.inject("l") { |result, el| result += encode(el) } + "e" end
encode_hash(hash)
click to toggle source
# File lib/bencoder.rb, line 128 def encode_hash(hash) hash.inject("d") { |result, (k,v)| result += "#{ encode(k.to_s) }#{ encode(v) }" } + 'e' end
encode_int(int)
click to toggle source
# File lib/bencoder.rb, line 120 def encode_int(int) "i#{ int }e" end
encode_string(string)
click to toggle source
# File lib/bencoder.rb, line 116 def encode_string(string) "#{ string.length }:#{ string }" end
make_hash_from_array(list)
click to toggle source
# File lib/bencoder.rb, line 91 def make_hash_from_array(list) hash = {} list.each_slice(2) do |k,v| hash[k] = v end hash end
parse(string)
click to toggle source
# File lib/bencoder.rb, line 33 def parse(string) case string[0] when 'i' parse_int string when 'l' parse_list string when 'd' parse_dict string else parse_string string end end
parse_dict(string)
click to toggle source
# File lib/bencoder.rb, line 58 def parse_dict(string) if string.is_a? StringIO string.getc if peek(string) == 'd' list_of_keys_and_values = parse_list(string) elsif string[0] == 'd' && string[-1] == 'e' list_of_keys_and_values = parse_list("l#{ string[1..-2] }e") else raise InvalidEncodingError, 'Dict does not have a closing e' end make_hash_from_array list_of_keys_and_values end
parse_int(string)
click to toggle source
# File lib/bencoder.rb, line 99 def parse_int(string) if string[0] == 'i' && string[-1] == 'e' string[1..-2].to_i else raise InvalidEncodingError, 'Integer does not have closing e' end end
parse_io_list(io)
click to toggle source
# File lib/bencoder.rb, line 70 def parse_io_list(io) list = [] until peek(io) == 'e' || io.eof? case peek(io) when 'i' list << parse_int(io.gets sep='e') when 'l' list << parse_list(io) when 'd' list << parse_dict(io) when ->(e) { e =~ /\d/ } length = io.gets(sep=':').to_i list << io.gets(length) else raise InvalidEncodingError, "Encountered unexpected identifier #{ peek io }" end end io.getc list end
parse_list(string)
click to toggle source
# File lib/bencoder.rb, line 46 def parse_list(string) if string.is_a? StringIO str = string str.getc if peek(str) == 'l' elsif string[0] == 'l' && string[-1] == 'e' str = StringIO.new string[1..-2] else raise InvalidEncodingError, 'List does not have a closing e' end parse_io_list str end
parse_string(string)
click to toggle source
# File lib/bencoder.rb, line 107 def parse_string(string) length, content = string.split ':' if content.length == length.to_i content else raise InvalidEncodingError, "String length declared as #{length.to_i}, but was #{content.length} " end end
peek(io)
click to toggle source
# File lib/bencoder.rb, line 132 def peek(io) char = io.getc io.ungetc char char end