bencodr 1.2.0 → 2.0.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.
@@ -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