bencoder 0.0.1 → 0.0.3
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 +4 -4
- data/README.md +15 -0
- data/lib/bencoder.rb +121 -14
- data/test/test_bencoder.rb +27 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 51e49c375c750bc8fc138694c480243464b72569
|
4
|
+
data.tar.gz: 61d783b6a72ed79143a178e0b3238d66285174cb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 624aefbb8c412f1ad58f8df03a6a3492af110859065e7bff4541d286361e6bee0113fbc0fdbfa388f5c183e4c4b036080fefe036bcdba4cfc08341384fa9b17d
|
7
|
+
data.tar.gz: 65232d1a24bfcb6cf2e5abea661df2fba8ff0a2441aacbe696fdb0417b8b0ff82a38cdddadaa7bf8058ffeee74c563648b5537b0ab45b866d20d67af39338724
|
data/README.md
CHANGED
@@ -3,6 +3,15 @@ bencoder
|
|
3
3
|
|
4
4
|
Bittorrent encoding in ruby
|
5
5
|
|
6
|
+
BEncoder will encode the 4 data types in the specification:
|
7
|
+
|
8
|
+
- Strings
|
9
|
+
- Integers
|
10
|
+
- Arrays
|
11
|
+
- Hashes
|
12
|
+
|
13
|
+
Additionally, it will pass symbols as strings, to allow for easier hash convertion.
|
14
|
+
|
6
15
|
install with
|
7
16
|
|
8
17
|
gem install bencoder
|
@@ -13,7 +22,13 @@ Usage is easy:
|
|
13
22
|
BEncoder.encode "herp"
|
14
23
|
=> "4:herp"
|
15
24
|
|
25
|
+
BEncoder.decode "4:herp"
|
26
|
+
=> "herp"
|
27
|
+
|
16
28
|
BEncoder.encode ['what', 'strange', { data: 'I', have: 'here' }, 666]
|
17
29
|
=> "l4:what7:stranged4:data1:I4:have4:hereei666ee"
|
30
|
+
|
31
|
+
BEncoder.decode 'l4:what7:stranged4:data1:I4:have4:hereei666ee'
|
32
|
+
=> ['what', 'strange', { data: 'I', have: 'here' }, 666]
|
18
33
|
```
|
19
34
|
Intentionally minimalistic.
|
data/lib/bencoder.rb
CHANGED
@@ -1,18 +1,125 @@
|
|
1
|
+
require 'stringio'
|
1
2
|
class BEncoder
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
3
|
+
class << self
|
4
|
+
def encode(object)
|
5
|
+
case object
|
6
|
+
when Symbol
|
7
|
+
encode object.to_s
|
8
|
+
when String
|
9
|
+
encode_string object
|
10
|
+
when Integer
|
11
|
+
encode_int object
|
12
|
+
when Array
|
13
|
+
encode_array object
|
14
|
+
when Hash
|
15
|
+
encode_hash object
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def decode(string)
|
20
|
+
parse string
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def parse(string)
|
28
|
+
case string[0]
|
29
|
+
when 'i'
|
30
|
+
parse_int string
|
31
|
+
when 'l'
|
32
|
+
parse_list string
|
33
|
+
when 'd'
|
34
|
+
parse_dict string
|
35
|
+
else
|
36
|
+
parse_string string
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse_list(string)
|
41
|
+
if string.is_a? StringIO
|
42
|
+
str = string
|
43
|
+
str.getc if peek(str) == 'l'
|
44
|
+
elsif string[0] == 'l' && string[-1] == 'e'
|
45
|
+
str = StringIO.new string[1..-2]
|
46
|
+
else
|
47
|
+
raise 'Not a list'
|
48
|
+
end
|
49
|
+
list = []
|
50
|
+
until peek(str) == 'e' || str.eof?
|
51
|
+
case peek(str)
|
52
|
+
when 'i'
|
53
|
+
list << parse_int(str.gets sep='e')
|
54
|
+
when 'l'
|
55
|
+
list << parse_list(str)
|
56
|
+
when 'd'
|
57
|
+
list << parse_dict(str)
|
58
|
+
when ->(e) { e =~ /\d/ }
|
59
|
+
length = str.gets(sep=':').to_i
|
60
|
+
list << str.gets(length)
|
61
|
+
else
|
62
|
+
raise str.read
|
63
|
+
end
|
64
|
+
end
|
65
|
+
str.getc
|
66
|
+
list
|
67
|
+
end
|
68
|
+
|
69
|
+
def parse_dict(string)
|
70
|
+
if string.is_a? StringIO
|
71
|
+
string.getc if peek(string) == 'd'
|
72
|
+
list_of_keys_and_values = parse_list(string)
|
73
|
+
elsif string[0] == 'd' && string[-1] == 'e'
|
74
|
+
list_of_keys_and_values = parse_list("l#{string[1..-2]}e")
|
75
|
+
else
|
76
|
+
raise 'Something in hash is wrong!'
|
77
|
+
end
|
78
|
+
hash = {}
|
79
|
+
list_of_keys_and_values.each_slice(2) do |k,v|
|
80
|
+
hash[k] = v
|
81
|
+
end
|
82
|
+
hash
|
83
|
+
end
|
84
|
+
|
85
|
+
def parse_int(string)
|
86
|
+
if string[0] == 'i' && string[-1] == 'e'
|
87
|
+
string[1..-2].to_i
|
88
|
+
else
|
89
|
+
raise 'Int is formatted wrong'
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def parse_string(string)
|
94
|
+
length, content = string.split ':'
|
95
|
+
if content.length == length.to_i
|
96
|
+
content
|
97
|
+
else
|
98
|
+
raise 'String length is messed up'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def encode_string(string)
|
103
|
+
"#{string.length}:#{string}"
|
104
|
+
end
|
105
|
+
|
106
|
+
def encode_int(int)
|
107
|
+
"i#{int}e"
|
108
|
+
end
|
109
|
+
|
110
|
+
def encode_array(array)
|
111
|
+
array.inject("l") { |result, el| result += encode(el) } + "e"
|
112
|
+
end
|
113
|
+
|
114
|
+
def encode_hash(hash)
|
115
|
+
hash.inject("d") { |result, (k,v)| result += "#{encode(k.to_s)}#{encode(v)}" } + 'e'
|
116
|
+
end
|
117
|
+
|
118
|
+
def peek(io)
|
119
|
+
char = io.getc
|
120
|
+
io.ungetc char
|
121
|
+
puts char
|
122
|
+
char
|
16
123
|
end
|
17
124
|
end
|
18
125
|
end
|
data/test/test_bencoder.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
require 'minitest/autorun'
|
2
2
|
require 'bencoder'
|
3
3
|
|
4
|
-
class TestBencoder < Minitest::
|
4
|
+
class TestBencoder < Minitest::Test
|
5
5
|
def setup
|
6
6
|
@be = BEncoder
|
7
7
|
end
|
8
|
+
|
9
|
+
#encoding
|
10
|
+
|
8
11
|
def test_string_encoding
|
9
12
|
assert_equal '7:Someday', @be.encode('Someday')
|
10
13
|
end
|
@@ -21,7 +24,29 @@ class TestBencoder < Minitest::Unit::TestCase
|
|
21
24
|
assert_equal 'd4:what2:is2:up4:dawge', @be.encode({what: 'is', up: 'dawg'})
|
22
25
|
end
|
23
26
|
|
24
|
-
def
|
27
|
+
def test_nested_encoding
|
25
28
|
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"]])
|
26
29
|
end
|
30
|
+
|
31
|
+
#decoding
|
32
|
+
|
33
|
+
def test_string_decoding
|
34
|
+
assert_equal "I'm free!", @be.decode("9:I'm free!")
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_int_decoding
|
38
|
+
assert_equal 321, @be.decode('i321e')
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_array_decoding
|
42
|
+
assert_equal ['1', 2, 3], @be.decode('l1:1i2ei3ee')
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_hash_decoding
|
46
|
+
assert_equal({'abc' => 'def', 'ghi' => 32}, @be.decode("d3:abc3:def3:ghii32ee"))
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_nested_decoding
|
50
|
+
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')
|
51
|
+
end
|
27
52
|
end
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bencoder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
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-
|
11
|
+
date: 2014-10-18 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description: Minimalistic
|
13
|
+
description: Minimalistic BEncoding gem
|
14
14
|
email: kholbekj@gmail.com
|
15
15
|
executables: []
|
16
16
|
extensions: []
|