Module: BEncode::Parser

Defined in:
lib/bencode/parser.rb

Class Method Summary collapse

Class Method Details

.parse_dictionary(scanner) ⇒ Hash

This method parases a bencoded dictionary.

scanner = StringScanner.new("de")
BEncode::Parser.parse_dictionary(scanner) #=> {}

Parameters:

  • scanner (StringScanner)

    the scanner of a bencoded dictionary

Returns:

  • (Hash)

    the parsed hash



85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/bencode/parser.rb', line 85

def parse_dictionary(scanner)
  dictionary = {}

  scanner.scan(/d/) or raise BEncodeError, "Invalid dictionary: missing opening d. #{scanner.pos}"
  while true
    key_value = parse_key_value(scanner)
    break unless key_value
    dictionary.store(*key_value)
  end
  scanner.scan(/e/) or raise BEncodeError, "Invalid dictionary: missing closing e. #{scanner.pos}"

  dictionary
end

.parse_integer(scanner) ⇒ Integer

This method parases a bencoded integer.

scanner = StringScanner.new("i1e")
BEncode::Parser.parse_integer(scanner) #=> 1

Parameters:

  • scanner (StringScanner)

    the scanner of a bencoded integer

Returns:



50
51
52
53
54
55
# File 'lib/bencode/parser.rb', line 50

def parse_integer(scanner)
  scanner.scan(/i/)                         or raise BEncodeError, "Invalid integer: missing opening i. #{scanner.pos}"
  integer = scanner.scan(/-?[1-9][0-9]*|0/) or raise BEncodeError, "Invalid integer: valid integer not found. #{scanner.pos}"
  scanner.scan(/e/)                         or raise BEncodeError, "Invalid integer: missing closing e. #{scanner.pos}"
  integer.to_i
end

.parse_key_value(scanner) ⇒ Object

:nodoc:

Raises:



100
101
102
103
104
105
106
107
108
109
# File 'lib/bencode/parser.rb', line 100

def parse_key_value(scanner) # :nodoc:
  key = parse_object(scanner)
  return key unless key
  raise BEncodeError, "Invalid dictionary: key is not a string. #{scanner.pos}" unless key.is_a?(::String)

  value = parse_object(scanner)
  raise BEncodeError, "Invalid dictionary: missing value for key (#{key}). #{scanner.pos}" unless value

  [key, value]
end

.parse_list(scanner) ⇒ Array

This method parases a bencoded list.

scanner = StringScanner.new("le")
BEncode::Parser.parse_list(scanner) #=> []

Parameters:

  • scanner (StringScanner)

    the scanner of a bencoded list

Returns:

  • (Array)

    the parsed array



64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/bencode/parser.rb', line 64

def parse_list(scanner)
  list = []

  scanner.scan(/l/) or raise BEncodeError, "Invalid list: missing opening l. #{scanner.pos}"
  while true
    object = parse_object(scanner)
    break unless object
    list << object
  end
  scanner.scan(/e/) or raise BEncodeError, "Invalid list: missing closing e. #{scanner.pos}"

  list
end

.parse_object(scanner) ⇒ String, ...

This method parases a bencoded object.

scanner = StringScanner.new("6:string")
BEncode::Parser.parse_object(scanner) #=> "string"

Parameters:

  • scanner (StringScanner)

    the scanner of a bencoded object

Returns:

  • (String, Integer, Hash, Array, nil)

    an object if type is recognized or nil



15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/bencode/parser.rb', line 15

def parse_object(scanner)
  case scanner.peek(1)[0]
    when ?0..?9
      parse_string(scanner)
    when ?i
      parse_integer(scanner)
    when ?l
      parse_list(scanner)
    when ?d
      parse_dictionary(scanner)
    else
      nil
  end
end

.parse_string(scanner) ⇒ String

This method parases a bencoded string.

scanner = StringScanner.new("6:string")
BEncode::Parser.parse_string(scanner) #=> "string"

Parameters:

  • scanner (StringScanner)

    the scanner of a bencoded string

Returns:

  • (String)

    the parsed string



37
38
39
40
41
# File 'lib/bencode/parser.rb', line 37

def parse_string(scanner)
  length = scanner.scan(/[1-9][0-9]*|0/)    or raise BEncodeError, "Invalid string: length invalid. #{scanner.pos}"
  scanner.scan(/:/)                         or raise BEncodeError, "Invalid string: missing colon(:). #{scanner.pos}"
  scanner.scan(/.{#{length.to_i}}/)         or raise BEncodeError, "Invalid string: length too long(#{length}) #{scanner.pos}."
end