bencoder 0.0.4 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dfca12e927ab3e29a541dc509d5bc787ee62b732
4
- data.tar.gz: d74de695a016dea7000cb8118e1f54ec6889a8d8
3
+ metadata.gz: 5112fd1ec7dec234a855cf2a997e3ffe733f0ecb
4
+ data.tar.gz: 11393fc29fec7354b685cddea158df8f878e0a46
5
5
  SHA512:
6
- metadata.gz: 957254eaf5930e4c8898a62a8616c760732db91f508e9af20759388419ee88f006afaf7f0402a0cbd225fd5c3a6b443bcecdff4d2f63f25b756297ca907dbe05
7
- data.tar.gz: 338dd693748fbd2c36788798c3cfc896abbd1d5d52456ef074f90ecff0a0bcd370552daa6c4cfc98b971e262ea92bf4376da7b51a3aeae206f9efa37bbcae879
6
+ metadata.gz: b0dff892b6d46411990a480a3a4d91db34e8ebe099d52317d7ffa94d38a043013ac78eedf7d0ee9d5c5010a26c1f56893905e330045e8730e7db059000f9b616
7
+ data.tar.gz: 42f0060c74935ab46d58419d3f9f6f50eb50b4d20b62765f4d538784679fe3f8099eb522308586b9edeb0c4d6263e4c17ecc08314edd30e7ffe0a011f80938ee
data/README.md CHANGED
@@ -36,4 +36,10 @@ BEncoder.encode ['what', 'strange', { data: 'I', have: 'here' }, 666]
36
36
  BEncoder.decode 'l4:what7:stranged4:data1:I4:have4:hereei666ee'
37
37
  => ['what', 'strange', { 'data' => 'I', 'have' => 'here' }, 666]
38
38
  ```
39
- Intentionally minimalistic.
39
+
40
+ Since .torrent files are bencode dicts, you can parse them out of the box
41
+
42
+ ```ruby
43
+ BEncoder.decode File.read('sample.torrent')
44
+ => {"announce"=>"udp://tracker.openbittorrent.com:80", "creation date"=>1327049827, "info"=>{"length"=>20, "name"=>"sample.txt", "piece length"=>65536, "pieces"=>"\\\xC5\xE6R\xBE\r\xE6\xF2x\x05\xB3\x04d\xFF\x9B\x00\xF4\x89\xF0\xC9", "private"=>1}}
45
+ ```
@@ -1,4 +1,8 @@
1
1
  require 'stringio'
2
+
3
+ class InvalidEncodingError < StandardError; end
4
+ class UnencodableTypeError < StandardError; end
5
+
2
6
  class BEncoder
3
7
  class << self
4
8
  def encode(object)
@@ -13,6 +17,8 @@ class BEncoder
13
17
  encode_array object
14
18
  when Hash
15
19
  encode_hash object
20
+ else
21
+ raise UnencodableTypeError, "Cannot encode instance of type #{object.class}"
16
22
  end
17
23
  end
18
24
 
@@ -24,8 +30,6 @@ class BEncoder
24
30
 
25
31
  private
26
32
 
27
- class InvalidEncodingError < StandardError; end
28
-
29
33
  def parse(string)
30
34
  case string[0]
31
35
  when 'i'
@@ -46,7 +50,7 @@ class BEncoder
46
50
  elsif string[0] == 'l' && string[-1] == 'e'
47
51
  str = StringIO.new string[1..-2]
48
52
  else
49
- raise InvalidEncodingError
53
+ raise InvalidEncodingError, 'List does not have a closing e'
50
54
  end
51
55
  parse_io_list str
52
56
  end
@@ -56,9 +60,9 @@ class BEncoder
56
60
  string.getc if peek(string) == 'd'
57
61
  list_of_keys_and_values = parse_list(string)
58
62
  elsif string[0] == 'd' && string[-1] == 'e'
59
- list_of_keys_and_values = parse_list("l#{string[1..-2]}e")
63
+ list_of_keys_and_values = parse_list("l#{ string[1..-2] }e")
60
64
  else
61
- raise InvalidEncodingError
65
+ raise InvalidEncodingError, 'Dict does not have a closing e'
62
66
  end
63
67
  make_hash_from_array list_of_keys_and_values
64
68
  end
@@ -77,7 +81,7 @@ class BEncoder
77
81
  length = io.gets(sep=':').to_i
78
82
  list << io.gets(length)
79
83
  else
80
- raise InvalidEncodingError
84
+ raise InvalidEncodingError, "Encountered unexpected identifier #{ peek io }"
81
85
  end
82
86
  end
83
87
  io.getc
@@ -96,7 +100,7 @@ class BEncoder
96
100
  if string[0] == 'i' && string[-1] == 'e'
97
101
  string[1..-2].to_i
98
102
  else
99
- raise InvalidEncodingError
103
+ raise InvalidEncodingError, 'Integer does not have closing e'
100
104
  end
101
105
  end
102
106
 
@@ -105,16 +109,16 @@ class BEncoder
105
109
  if content.length == length.to_i
106
110
  content
107
111
  else
108
- raise InvalidEncodingError
112
+ raise InvalidEncodingError, "String length declared as #{length.to_i}, but was #{content.length} "
109
113
  end
110
114
  end
111
115
 
112
116
  def encode_string(string)
113
- "#{string.length}:#{string}"
117
+ "#{ string.length }:#{ string }"
114
118
  end
115
119
 
116
120
  def encode_int(int)
117
- "i#{int}e"
121
+ "i#{ int }e"
118
122
  end
119
123
 
120
124
  def encode_array(array)
@@ -122,7 +126,7 @@ class BEncoder
122
126
  end
123
127
 
124
128
  def encode_hash(hash)
125
- hash.inject("d") { |result, (k,v)| result += "#{encode(k.to_s)}#{encode(v)}" } + 'e'
129
+ hash.inject("d") { |result, (k,v)| result += "#{ encode(k.to_s) }#{ encode(v) }" } + 'e'
126
130
  end
127
131
 
128
132
  def peek(io)
@@ -13,6 +13,10 @@ class TestBencoder < Minitest::Test
13
13
 
14
14
  #encoding
15
15
 
16
+ def test_symbol_encoding
17
+ assert_equal '6:hellou', @be.encode(:hellou)
18
+ end
19
+
16
20
  def test_string_encoding
17
21
  assert_equal '7:Someday', @be.encode('Someday')
18
22
  end
@@ -33,6 +37,12 @@ class TestBencoder < Minitest::Test
33
37
  assert_equal 'ld4:somel5:times3:youe5:gotta3:let2:go1:!ei2e5:wooooli1e1:21:3ee', @be.encode([{'some' => ['times', 'you'], gotta: 'let', go: '!'}, 2, "woooo", [1, '2', "3"]])
34
38
  end
35
39
 
40
+ def test_should_not_encode_strange_types
41
+ assert_raises UnencodableTypeError do
42
+ @be.encode 5.6
43
+ end
44
+ end
45
+
36
46
  #decoding
37
47
 
38
48
  def test_string_decoding
@@ -54,4 +64,34 @@ class TestBencoder < Minitest::Test
54
64
  def test_nested_decoding
55
65
  assert_equal [{'some' => ['times', 'you'], 'gotta' => 'let', 'go' => '!'}, 2, "woooo", [1, '2', "3"]], @be.decode('ld4:somel5:times3:youe5:gotta3:let2:go1:!ei2e5:wooooli1e1:21:3ee')
56
66
  end
67
+
68
+ def test_throws_error_on_wrong_list_encoding
69
+ assert_raises InvalidEncodingError do
70
+ @be.decode 'li4ed'
71
+ end
72
+ end
73
+
74
+ def test_throws_error_on_wrong_dict_encoding
75
+ assert_raises InvalidEncodingError do
76
+ @be.decode 'd3:abc'
77
+ end
78
+ end
79
+
80
+ def test_throws_error_on_wrong_int_encoding
81
+ assert_raises InvalidEncodingError do
82
+ @be.decode 'i14'
83
+ end
84
+ end
85
+
86
+ def test_throws_error_on_wrong_string_encoding
87
+ assert_raises InvalidEncodingError do
88
+ @be.decode '4:cat'
89
+ end
90
+ end
91
+
92
+ def test_throws_error_on_unknown_encoding_identifier
93
+ assert_raises InvalidEncodingError do
94
+ @be.decode 'li3ej5e'
95
+ end
96
+ end
57
97
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bencoder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kasper Holbek Jensen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-18 00:00:00.000000000 Z
11
+ date: 2014-10-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -72,7 +72,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: 1.9.3
76
76
  required_rubygems_version: !ruby/object:Gem::Requirement
77
77
  requirements:
78
78
  - - ">="
@@ -80,7 +80,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
80
  version: '0'
81
81
  requirements: []
82
82
  rubyforge_project:
83
- rubygems_version: 2.2.2
83
+ rubygems_version: 2.4.2
84
84
  signing_key:
85
85
  specification_version: 4
86
86
  summary: Bittorrent encoding