bencodr 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,56 +2,28 @@
2
2
 
3
3
  module BEncodr
4
4
  module Dictionary
5
- module Generic
6
- module InstanceMethods
7
- # Encodes an array into a bencoded dictionary. Bencoded dictionaries are encoded as a 'd' followed by a list of
8
- # alternating keys and their corresponding values followed by an 'e'. Keys appear in sorted order (sorted as raw
9
- # strings, not alphanumerics).
10
- #
11
- # {:cow => "moo", :seven => 7}.bencodr #=> "d3:cow3:moo5:seveni7ee"
12
- #
13
- # @return [::String] the bencoded dictionary
14
- def bencode
15
- (respond_to?(:to_h) ? to_h : to_hash).bencode
16
- end
17
- end
5
+ def bencode
6
+ Dictionary.bencode(self)
18
7
  end
19
-
20
- # Registers a class as an object that can be converted into a bencoded dictionary. Class must have instance method
21
- # to_h or to_hash.
22
- #
23
- # class MyClass
24
- # def to_h
25
- # {:a => :a, :b => 1}
26
- # end
27
- # end
28
- #
29
- # BEncodr::String.register MyClass
30
- # my_class = MyClass.new
31
- # my_class.bencodr #=> "d1:a1:a1:bi1ee"
32
- #
33
- # @param [Class#to_h, Class#to_hash] type the class to add the bencodr instance method to
34
- def self.register(type)
35
- type.send :include, Generic::InstanceMethods
8
+
9
+ def self.bencode(hashable)
10
+ hash = coerce(hashable)
11
+
12
+ hash.keys.sort{|a, b| a.to_s <=> b.to_s}.collect do |key|
13
+ BEncodr::String.bencode(key.to_s) + Object.bencode(hash[key])
14
+ end.unshift(:d).push(:e).join
36
15
  end
37
-
38
- module Hash
39
- module InstanceMethods
40
- # Encodes an array into a bencoded dictionary. Bencoded dictionaries are encoded as a 'd' followed by a list of
41
- # alternating keys and their corresponding values followed by an 'e'. Keys appear in sorted order (sorted as raw
42
- # strings, not alphanumerics).
43
- #
44
- # {:cow => "moo", :seven => 7}.bencodr #=> "d3:cow3:moo5:seveni7ee"
45
- #
46
- # @return [::String] the bencoded dictionary
47
- def bencode
48
- keys.sort{|a, b| a.to_s <=> b.to_s}.collect do |key|
49
- key.to_s.bencode + self[key].bencode
50
- end.unshift(:d).push(:e).join
51
- end
16
+
17
+ private
18
+
19
+ def self.coerce(hashable)
20
+ if hashable.respond_to?(:to_h)
21
+ hashable.to_h
22
+ elsif hashable.respond_to?(:to_hash)
23
+ hashable.to_hash
24
+ else
25
+ raise BEncodeError, "BEncodr::Dictionary.bencode can only be called on an object that provides a to_h or to_hash method."
52
26
  end
53
-
54
- ::Hash.send :include, InstanceMethods
55
27
  end
56
28
  end
57
29
  end
@@ -0,0 +1,38 @@
1
+ module BEncodr
2
+ module Ext
3
+ def self.include!
4
+ include_string!
5
+ include_integer!
6
+ include_list!
7
+ include_dictionary!
8
+ include_io!
9
+ end
10
+
11
+ private
12
+
13
+ def self.include_string!
14
+ ::String.send :include, Object
15
+ [::String, Symbol, URI::Generic].each do |stringable|
16
+ stringable.send :include, String
17
+ end
18
+ end
19
+
20
+ def self.include_integer!
21
+ [Numeric, Time].each do |intable|
22
+ intable.send :include, Integer
23
+ end
24
+ end
25
+
26
+ def self.include_list!
27
+ Array.send :include, List
28
+ end
29
+
30
+ def self.include_dictionary!
31
+ Hash.send :include, Dictionary
32
+ end
33
+
34
+ def self.include_io!
35
+ ::IO.send :include, IO
36
+ end
37
+ end
38
+ end
@@ -2,56 +2,26 @@
2
2
 
3
3
  module BEncodr
4
4
  module Integer
5
- module Generic
6
- module InstanceMethods
7
- # Encodes object into a bencoded integer. BEncoded strings are length-prefixed base ten followed by a colon and
8
- # the string. Object must implement to_i or to_int.
9
- #
10
- # 1.bencodr #=> "i1e"
11
- #
12
- # @return [::String] the bencoded integer
13
- def bencode
14
- (respond_to?(:to_i) ? to_i : to_int).bencode
15
- end
16
- end
5
+ def bencode
6
+ Integer.bencode(self)
17
7
  end
18
-
19
- # Registers a class as an object that can be converted into a bencoded integer. Class must have instance method to_i
20
- # or to_int.
21
- #
22
- # class MyClass
23
- # def to_i
24
- # 1
25
- # end
26
- # end
27
- #
28
- # BEncodr::Integer.register MyClass
29
- # my_class = MyClass.new
30
- # my_class.bencodr #=> "i1e"
31
- #
32
- # @param [Class#to_i, Class#to_int] type the class to add the bencodr instance method to
33
- def self.register(type)
34
- type.send :include, Generic::InstanceMethods
8
+
9
+ def self.bencode(intable)
10
+ int = coerce(intable)
11
+
12
+ [:i, int, :e].join
35
13
  end
36
-
37
- register Numeric
38
- register Time
39
-
40
- module Integer
41
- module InstanceMethods
42
- # Encodes an integer into a bencoded integer. Bencoded integers are represented by an 'i' followed by the number
43
- # in base 10 followed by an 'e'.
44
- #
45
- # 3.bencodr #=> "i3e"
46
- # -3.bencodr #=> "i-3e"
47
- #
48
- # @return [::String] the bencoded integer
49
- def bencode
50
- [:i, self, :e].join
51
- end
14
+
15
+ private
16
+
17
+ def self.coerce(intable)
18
+ if intable.respond_to?(:to_i)
19
+ intable.to_i
20
+ elsif intable.respond_to?(:to_int)
21
+ intable.to_int
22
+ else
23
+ raise BEncodeError, "BEncodr::Integer.bencode can only be called on an object that provides a to_i or to_int method."
52
24
  end
53
-
54
- ::Integer.send :include, InstanceMethods
55
25
  end
56
26
  end
57
27
  end
data/lib/bencodr/io.rb CHANGED
@@ -1,60 +1,25 @@
1
- class IO
2
- class << self
3
- # This method encodes the object and writes it to the specified output.
4
- #
5
- # # write to standard out
6
- # IO.bencode(1, "string") #=> "6:string" to stdout
7
- #
8
- # # write to file
9
- # File.bencode("a.bencode", "string") #=> "6:string" to a.bencode
10
- #
11
- # @param [Object] fd the file descriptor to use for output
12
- # @param [Object] object the object to write
13
- def bencode(fd, object)
14
- open(fd, "wb") {|file| file.bencode object }
1
+ module BEncodr
2
+ module IO
3
+ module ClassMethods
4
+ def bencode(fd, object)
5
+ open(fd, "wb") {|file| file.bencode(object)}
6
+ end
7
+
8
+ def bdecode(fd)
9
+ open(fd, "rb") {|file| file.bdecode}
10
+ end
15
11
  end
16
-
17
- # This method reads from the specified input and decodes the object.
18
- #
19
- # # read from standard in
20
- # IO.bdecode(0) #=> "string"
21
- #
22
- # # read from file
23
- # File.bdecode("a.bencode") #=> "string"
24
- #
25
- # @param [Object] fd the file descriptor to use for input
26
- # @param [Object] object the object to write
27
- def bdecode(fd)
28
- open(fd, "rb") {|file| file.bdecode}
12
+
13
+ def bencode(object)
14
+ write(Object.bencode(object))
15
+ end
16
+
17
+ def bdecode
18
+ Object.bdecode(read)
19
+ end
20
+
21
+ def self.included(base)
22
+ base.extend ClassMethods
29
23
  end
30
- end
31
-
32
- # This method encodes the object and writes.
33
- #
34
- # # write to standard out
35
- # $stdout.bencode("string") #=> "6:string" to stdout
36
- #
37
- # # write to file
38
- # file = File.open("a.bencode", "wb")
39
- # file.bencode("string") #=> "6:string" to a.bencode
40
- #
41
- # @param [Object] object the object to write
42
- def bencode(object)
43
- write object.bencode
44
- end
45
-
46
- # This method reads from the specified input and decodes the object.
47
- #
48
- # # read from standard in
49
- # $stdin.bdecode #=> "string"
50
- #
51
- # # read from file
52
- # file = File.open("a.bencode", "wb")
53
- # file.bdecode #=> "string"
54
- #
55
- # @param [Object] fd the file descriptor to use for input
56
- # @param [Object] object the object to write
57
- def bdecode
58
- read.bdecode
59
24
  end
60
25
  end
data/lib/bencodr/list.rb CHANGED
@@ -2,54 +2,28 @@
2
2
 
3
3
  module BEncodr
4
4
  module List
5
- module Generic
6
- module InstanceMethods
7
- # Encodes object into a bencoded list. BEncoded strings are length-prefixed base ten followed by a colon and
8
- # the string. Object must implement to_a or to_ary.
9
- #
10
- # [].bencodr #=> "le"
11
- #
12
- # @return [::String] the bencoded list
13
- def bencode
14
- (respond_to?(:to_ary) ? to_ary : to_a).bencode
15
- end
16
- end
5
+ def bencode
6
+ List.bencode(self)
17
7
  end
18
-
19
- # Registers a class as an object that can be converted into a bencoded list. Class must have instance method to_a
20
- # or to_ary.
21
- #
22
- # class MyClass
23
- # def to_a
24
- # [1, :cat]
25
- # end
26
- # end
27
- #
28
- # BEncodr::Integer.register MyClass
29
- # my_class = MyClass.new
30
- # my_class.bencodr #=> "li1e3:cate"
31
- #
32
- # @param [Class#to_a, Class#to_ary] type the class to add the bencodr instance method to
33
- def self.register(type)
34
- type.send :include, Generic::InstanceMethods
8
+
9
+ def self.bencode(arrayable)
10
+ ary = coerce(arrayable)
11
+
12
+ ary.collect do |element|
13
+ Object.bencode(element)
14
+ end.unshift(:l).push(:e).join
35
15
  end
36
-
37
- module Array
38
- module InstanceMethods
39
- # Encodes an array into a bencoded list. Bencoded lists are encoded as an 'l' followed by their elements (also
40
- # bencoded) followed by an 'e'.
41
- #
42
- # [:eggs, "ham", 3, 4.1].bencodr #=> "l4:eggs3:hami3ei4ee"
43
- #
44
- # @return [::String] the bencoded list
45
- def bencode
46
- collect do |element|
47
- element.bencode
48
- end.unshift(:l).push(:e).join
49
- end
16
+
17
+ private
18
+
19
+ def self.coerce(arrayable)
20
+ if arrayable.respond_to?(:to_a)
21
+ arrayable.to_a
22
+ elsif arrayable.respond_to?(:to_ary)
23
+ arrayable.to_ary
24
+ else
25
+ raise BEncodeError, "BEncodr::List.bencode can only be called on an object that provides a to_a or to_ary method."
50
26
  end
51
-
52
- ::Array.send :include, InstanceMethods
53
27
  end
54
28
  end
55
29
  end
@@ -0,0 +1,36 @@
1
+ module BEncodr
2
+ module Object
3
+ def self.bencode(object)
4
+ return object.bencode if object.respond_to?(:bencode)
5
+
6
+ case object
7
+ when ::String, Symbol, URI::Generic
8
+ return String.bencode(object)
9
+ when Numeric, Time
10
+ return Integer.bencode(object)
11
+ when Array
12
+ return List.bencode(object)
13
+ when Hash
14
+ return Dictionary.bencode(object)
15
+ else
16
+ [String, Integer, List, Dictionary].each do |type|
17
+ begin
18
+ return type.bencode(object)
19
+ rescue
20
+ end
21
+ end
22
+ end
23
+
24
+ raise BEncodeError, "BEncodr::Object.bencode was unable to infer the type of the object passed in."
25
+ end
26
+
27
+ def self.bdecode(string)
28
+ object = Parser.parse_object(StringScanner.new(string))
29
+ object or raise BEncodeError, "BEncodr::Object.bdecode was unable to parse the string passed in."
30
+ end
31
+
32
+ def bdecode
33
+ Object.bdecode(self)
34
+ end
35
+ end
36
+ end
@@ -110,18 +110,4 @@ module BEncodr
110
110
  private :parse_key_value
111
111
  end
112
112
  end
113
- end
114
-
115
- class String
116
- # This method decodes a bencoded string into a ruby object.
117
- #
118
- # "6:string".bdecode #=> "string"
119
- # "i-1e".bdecode #=> -1
120
- # "le".bdecode #=> []
121
- # "de".bdecode #=> {}
122
- #
123
- # @return [::String, ::Integer, ::Array, ::Hash] the decoded object
124
- def bdecode
125
- BEncodr::Parser.parse_object(StringScanner.new self) or raise BEncodr::BEncodeError, "Invalid bencoding"
126
- end
127
113
  end
@@ -4,55 +4,26 @@ require 'uri'
4
4
 
5
5
  module BEncodr
6
6
  module String
7
- module Generic
8
- module InstanceMethods
9
- # Encodes object into a bencoded string. BEncoded strings are length-prefixed base ten followed by a colon and
10
- # the string.
11
- #
12
- # :symbol.bencodr #=> "6:symbol"
13
- #
14
- # @return [::String] the bencoded string
15
- def bencode
16
- (respond_to?(:to_s) ? to_s : to_str).bencode
17
- end
18
- end
7
+ def bencode
8
+ String.bencode(self)
19
9
  end
20
-
21
- # Registers a class as an object that can be converted into a bencoded string. Class must have instance method to_s
22
- # or to_str.
23
- #
24
- # class MyClass
25
- # def to_s
26
- # "string"
27
- # end
28
- # end
29
- #
30
- # BEncode::String.register MyClass
31
- # my_class = MyClass.new
32
- # my_class.bencodr #=> "6:string"
33
- #
34
- # @param [Class#to_s, Class#to_str] type the class to add the bencodr instance method to
35
- def self.register(type)
36
- type.send :include, Generic::InstanceMethods
10
+
11
+ def self.bencode(stringable)
12
+ string = coerce(stringable)
13
+
14
+ [string.length, ':', string].join
37
15
  end
38
-
39
- register Symbol
40
- register URI::Generic
41
-
42
- module String
43
- module InstanceMethods
44
- # Encodes a string into a bencoded string. BEncoded strings are length-prefixed base ten followed by a colon and
45
- # the string.
46
- #
47
- # "string".bencodr #=> "6:string"
48
- #
49
- # @return [::String] the bencoded string
50
- def bencode
51
- [length, ':', self].join
52
- end
16
+
17
+ private
18
+
19
+ def self.coerce(stringable)
20
+ if stringable.respond_to?(:to_s)
21
+ stringable.to_s
22
+ elsif stringable.respond_to?(:to_str)
23
+ stringable.to_str
24
+ else
25
+ raise BEncodeError, "BEncodr::String.bencode can only be called on an object that provides a to_s or to_str method."
53
26
  end
54
-
55
- ::String.send :include, InstanceMethods
56
27
  end
57
28
  end
58
29
  end