bencode 0.5.1 → 0.6.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.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ doc
2
+ *.gem
3
+ .idea
data/README.md CHANGED
@@ -22,12 +22,17 @@ It contains only four data types, namely:
22
22
  Examples
23
23
  --------
24
24
 
25
+ Encoding objects is as simple as calling `#bencode` on them:
26
+
25
27
  "foo bar".bencode # => "7:foo bar"
26
28
  42.bencode # => "i42e"
27
29
  [1, 2, 3].bencode # => "li1ei2ei3ee"
28
30
  {"foo" => 1, "bar" => -10}.bencode # => "d3:bari-10e3:fooi1ee"
29
31
 
30
32
 
33
+ Decoding a data stream is as easy as calling `BEncode.load(data)`.
34
+
35
+
31
36
  License
32
37
  -------
33
38
 
@@ -37,4 +42,8 @@ Released under the MIT license.
37
42
  Contributors
38
43
  ------------
39
44
 
45
+ - Daniel Schierbeck
40
46
  - Mike Hodgson
47
+ - Andrew Danforth
48
+ - Eric Himmelreich
49
+ - Allen Madsen
data/Rakefile CHANGED
@@ -2,13 +2,41 @@
2
2
  require 'rake/testtask'
3
3
  require 'rake/rdoctask'
4
4
 
5
- ##
6
- # Run all unit tests.
7
- Rake::TestTask.new
5
+ task :default => :test
6
+
7
+ desc "Run all unit tests"
8
+ Rake::TestTask.new(:test) do |test|
9
+ test.libs << 'lib' << 'test'
10
+ test.pattern = 'test/**/*_test.rb'
11
+ test.verbose = false
12
+ end
8
13
 
9
14
 
10
- ##
11
- # Generate RDoc documentation.
15
+ desc "Generate RDoc documentation"
12
16
  Rake::RDocTask.new :doc do |rdoc|
13
17
  rdoc.rdoc_dir = 'doc'
14
18
  end
19
+
20
+ desc "Run all the benchmarks"
21
+ task :benchmark do
22
+ Dir["test/benchmark/*.rb"].each do |file|
23
+ puts ">> Running #{file}"
24
+ puts %x[ruby #{file}]
25
+ puts
26
+ end
27
+ end
28
+
29
+ begin
30
+ require 'jeweler'
31
+ Jeweler::Tasks.new do |gem|
32
+ gem.name = "bencode"
33
+ gem.summary = "Encode and decode bencoded data"
34
+ gem.description = "A simple encoder and decoder for the BitTorrent serialization format."
35
+ gem.email = "daniel.schierbeck@gmail.com"
36
+ gem.homepage = "http://github.com/dasch/ruby-bencode"
37
+ gem.authors = ["Daniel Schierbeck"]
38
+ end
39
+ Jeweler::GemcutterTasks.new
40
+ rescue LoadError
41
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
42
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.6.0
@@ -1,4 +1,6 @@
1
1
 
2
+ require 'strscan'
3
+
2
4
  module BEncode
3
5
  class << self
4
6
  # BEncodes +obj+
@@ -8,8 +10,6 @@ module BEncode
8
10
 
9
11
  # Bdecodes +str+
10
12
  def load(str)
11
- require 'strscan'
12
-
13
13
  scanner = StringScanner.new(str)
14
14
  obj = parse(scanner)
15
15
  raise BEncode::DecodeError unless scanner.eos?
@@ -18,51 +18,48 @@ module BEncode
18
18
 
19
19
  # Bdecodes the file located at +path+
20
20
  def load_file(path)
21
- if RUBY_PLATFORM =~ /(win|w)32$/
22
- load(File.open(path, 'rb').read)
23
- else
24
- load(File.open(path).read)
25
- end
21
+ load(File.open(path, 'rb') {|f| f.read})
26
22
  end
27
23
 
28
24
  def parse(scanner) # :nodoc:
29
- case scanner.scan(/[ild]|\d+:/)
30
- when "i"
31
- number = scanner.scan(/0|(?:-?[1-9][0-9]*)/)
32
- raise BEncode::DecodeError unless number and scanner.scan(/e/)
33
- return number.to_i
34
- when "l"
35
- ary = []
36
- # TODO: There must be a smarter way of doing this...
37
- ary.push(parse(scanner)) until scanner.peek(1) == "e"
25
+ case scanner.peek(1)[0]
26
+ when ?i
38
27
  scanner.pos += 1
28
+ num = scanner.scan_until(/e/) or raise BEncode::DecodeError
29
+ return Integer(num.chop)
30
+ when ?l
31
+ scanner.pos += 1
32
+ ary = []
33
+ ary.push(parse(scanner)) until scanner.scan(/e/)
39
34
  return ary
40
- when "d"
35
+ when ?d
36
+ scanner.pos += 1
41
37
  hsh = {}
42
- until scanner.peek(1) == "e"
43
- key, value = parse(scanner), parse(scanner)
38
+ until scanner.scan(/e/)
39
+ key = parse(scanner)
44
40
 
45
- unless key.is_a? String
46
- raise BEncode::DecodeError, "key must be a string"
41
+ unless key.is_a? String or key.is_a? Fixnum
42
+ raise BEncode::DecodeError, "key must be a string or number"
47
43
  end
48
44
 
49
- hsh.store(key, value)
45
+ hsh.store(key.to_s, parse(scanner))
50
46
  end
51
- scanner.pos += 1
52
47
  return hsh
53
- when /\d+:/
54
- length = Integer($~.string.chop)
55
- str = scanner.peek(length)
48
+ when ?0 .. ?9
49
+ num = scanner.scan_until(/:/) or
50
+ raise BEncode::DecodeError, "invalid string length (no colon)"
56
51
 
57
52
  begin
53
+ length = Integer(num.chop)
54
+ str = scanner.peek(length)
58
55
  scanner.pos += length
59
- rescue RangeError
56
+ rescue
60
57
  raise BEncode::DecodeError, "invalid string length"
61
58
  end
62
59
 
63
60
  return str
64
61
  else
65
- raise BEncode::DecodeError
62
+ raise BEncode::DecodeError, "Invalid specifier #{scanner.peek(1).inspect} at position #{scanner.pos+1}"
66
63
  end
67
64
  end
68
65
 
data/lib/bencode/io.rb CHANGED
@@ -1,11 +1,11 @@
1
1
 
2
2
  class IO
3
3
  def self.bdecode(filename)
4
- open(filename, 'r').bdecode
4
+ open(filename, 'rb') {|io| io.bdecode}
5
5
  end
6
6
 
7
7
  def self.bencode(filename)
8
- open(filename, 'r').bencode
8
+ open(filename, 'rb') {|io| io.bencode}
9
9
  end
10
10
 
11
11
  def bdecode
@@ -0,0 +1,22 @@
1
+ $:.unshift(File.dirname(__FILE__)+"/../../lib")
2
+ require 'benchmark'
3
+ require 'bencode'
4
+
5
+ Benchmark.bmbm do |x|
6
+ x.report("Decoding an integer") do
7
+ 100_000.times do
8
+ BEncode.load("i42e")
9
+ end
10
+ end
11
+
12
+ x.report("Decoding an string") do
13
+ 100_000.times do
14
+ BEncode.load("6:foobar")
15
+ end
16
+ end
17
+ x.report("Decoding a long integer array") do
18
+ 100.times do
19
+ BEncode.load("l" + ("i42e" * 1000) + "e")
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ $:.unshift(File.dirname(__FILE__)+"/../../lib")
2
+ require 'benchmark'
3
+ require 'bencode'
4
+
5
+ Benchmark.bmbm do |x|
6
+ x.report("Encoding an array of integers") do
7
+ 100.times do
8
+ ((1..50).to_a * 100).bencode
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+
2
+ require 'test/environment'
3
+
4
+
5
+ class BitTorrentTest < Test::Unit::TestCase
6
+ should "load a bencoded torrent file" do
7
+ assert_nothing_raised do
8
+ BEncode.load_file("test/fixtures/python.torrent")
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+
2
+ require 'test/environment'
3
+
4
+ class DecodingTest < Test::Unit::TestCase
5
+ context "The BEncode decoder" do
6
+ should_decode 42, "i42e"
7
+ should_decode 0, "i0e"
8
+ should_decode -42, "i-42e"
9
+
10
+ should_decode "foo", "3:foo"
11
+ should_decode "", "0:"
12
+
13
+ should_decode [1, 2, 3], "li1ei2ei3ee"
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+
2
+ require 'test/environment'
3
+
4
+ class EncodingTest < Test::Unit::TestCase
5
+ context "The BEncode encoder" do
6
+ should_encode "i42e", 42
7
+ should_encode "3:foo", "foo"
8
+ end
9
+ end
data/test/environment.rb CHANGED
@@ -1,2 +1,8 @@
1
1
 
2
+ require 'rubygems'
3
+ require 'test/unit'
4
+ require 'shoulda'
2
5
  require File.dirname(__FILE__) + '/../lib/bencode'
6
+ Dir.glob(File.dirname(__FILE__) + '/shoulda_macros/*.rb').each do |macro|
7
+ require macro
8
+ end
Binary file
@@ -0,0 +1,8 @@
1
+
2
+ class Test::Unit::TestCase
3
+ def self.should_decode(expected, encoded)
4
+ should "decode #{encoded.inspect} into #{expected.inspect}" do
5
+ assert_equal expected, BEncode.load(encoded)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+
2
+ class Test::Unit::TestCase
3
+ def self.should_encode(expected, value)
4
+ should "encode #{value.inspect} into #{expected.inspect}" do
5
+ assert_equal expected, value.bencode
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,12 @@
1
+
2
+ require 'test/environment'
3
+
4
+ class UTF8DecodingTest < Test::Unit::TestCase
5
+ context "The BEncode decoder" do
6
+ should "be able to handle UTF8-encoded data" do
7
+ assert_nothing_raised do
8
+ BEncode.load_file('test/fixtures/test.torrent')
9
+ end
10
+ end
11
+ end
12
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bencode
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Schierbeck
@@ -9,39 +9,53 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-06 00:00:00 +02:00
12
+ date: 2010-02-06 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
16
- description: Ruby bindings for the bencode data serialization format.
16
+ description: A simple encoder and decoder for the BitTorrent serialization format.
17
17
  email: daniel.schierbeck@gmail.com
18
18
  executables: []
19
19
 
20
20
  extensions: []
21
21
 
22
- extra_rdoc_files: []
23
-
22
+ extra_rdoc_files:
23
+ - LICENSE
24
+ - README.md
24
25
  files:
25
- - Rakefile
26
+ - .gitignore
26
27
  - LICENSE
27
28
  - README.md
29
+ - Rakefile
30
+ - VERSION
28
31
  - lib/bencode.rb
29
32
  - lib/bencode/decode.rb
30
33
  - lib/bencode/decode_error.rb
31
- - lib/bencode/encode_error.rb
32
- - lib/bencode/io.rb
33
34
  - lib/bencode/encode/array.rb
34
- - lib/bencode/encode/integer.rb
35
- - lib/bencode/encode/string.rb
36
35
  - lib/bencode/encode/hash.rb
36
+ - lib/bencode/encode/integer.rb
37
37
  - lib/bencode/encode/object.rb
38
+ - lib/bencode/encode/string.rb
39
+ - lib/bencode/encode_error.rb
40
+ - lib/bencode/io.rb
41
+ - test/benchmark/decoding.rb
42
+ - test/benchmark/encoding.rb
43
+ - test/bittorrent_test.rb
44
+ - test/decoding_test.rb
45
+ - test/encoding_test.rb
46
+ - test/environment.rb
47
+ - test/fixtures/python.torrent
48
+ - test/fixtures/test.torrent
49
+ - test/shoulda_macros/decoding.rb
50
+ - test/shoulda_macros/encoding.rb
51
+ - test/utf8_decoding_test.rb
38
52
  has_rdoc: true
39
- homepage: http://github.com/dasch/ruby-bencode-bindings
53
+ homepage: http://github.com/dasch/ruby-bencode
40
54
  licenses: []
41
55
 
42
56
  post_install_message:
43
- rdoc_options: []
44
-
57
+ rdoc_options:
58
+ - --charset=UTF-8
45
59
  require_paths:
46
60
  - lib
47
61
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -62,8 +76,14 @@ rubyforge_project:
62
76
  rubygems_version: 1.3.5
63
77
  signing_key:
64
78
  specification_version: 3
65
- summary: Ruby bencode bindings
79
+ summary: Encode and decode bencoded data
66
80
  test_files:
67
- - test/test_decode_utf8.rb
81
+ - test/bittorrent_test.rb
82
+ - test/decoding_test.rb
83
+ - test/utf8_decoding_test.rb
84
+ - test/shoulda_macros/decoding.rb
85
+ - test/shoulda_macros/encoding.rb
68
86
  - test/environment.rb
69
- - test/fixtures/test.torrent
87
+ - test/encoding_test.rb
88
+ - test/benchmark/decoding.rb
89
+ - test/benchmark/encoding.rb
@@ -1,13 +0,0 @@
1
-
2
- require 'test/unit'
3
- require 'test/environment'
4
-
5
- class TestDecodeUTF8 < Test::Unit::TestCase
6
-
7
- def test_can_handle_utf8_encoded_data
8
- assert_nothing_raised do
9
- BEncode.load_file('test/fixtures/test.torrent')
10
- end
11
- end
12
-
13
- end