radix 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  = Radix
2
2
 
3
- * http://rubyworks.github.com/radix
4
- * http://github.com/rubyworks/radix
3
+ * home: http://rubyworks.github.com/radix
4
+ * code: http://github.com/rubyworks/radix
5
5
 
6
6
 
7
7
  == DESCRIPTION
@@ -16,14 +16,14 @@ base 62.
16
16
  == FEATURES/ISSUES
17
17
 
18
18
  * Convert to and from any base.
19
- * User-definable character set upto base 62.
20
- * Defaults to standard base 62.
21
- * Can be used to encode strings.
19
+ * Define custom character sets.
20
+ * Can be used to encode/decode strings.
21
+ * Very intuitive API.
22
22
 
23
23
 
24
24
  == RELEASE NOTES
25
25
 
26
- Please see HISTORY file.
26
+ Please see the HISTORY.rdoc file.
27
27
 
28
28
 
29
29
  == SYNOPSIS
@@ -37,44 +37,45 @@ But Ruby reaches it's limit at base 36.
37
37
 
38
38
  255.to_s(37) #=> Error
39
39
 
40
- Radix provides the means of converting to and from any base. For example,
41
- a number in base 256, represented by the array [100, 10] (ie. 100 * 256 + 10 * 1),
42
- can be converted to base 10 as follows:
40
+ Radix provides the means of converting to and from any base.
43
41
 
44
- Radix.convert_base([100, 10], 256, 10)
45
- #=> [2,5,6,1,0]
42
+ For example, a number in base 256 can be represented by the array [100, 10]
43
+ (ie. 100**256 + 10**1) and can be convert to base 10.
46
44
 
47
- And it can handle any string notation up to base 62.
45
+ [100,10].b(256).to_a(10) #=> [2,5,6,1,0]
48
46
 
49
- Radix.convert("10", 62, 10) #=> "62"
47
+ Or, to get a string representation for any base upto 62.
50
48
 
51
- The string notation need not be in ASCII order --odd notations
52
- can be used.
49
+ [100,10].b(256).to_s(10) #=> "25610"
53
50
 
54
- b10 = Radix.new([:Q, :W, :E, :R, :T, :Y, :U, :I, :O, :U])
55
- b10.convert("FF", 16) #=> "EYY"
51
+ A string representation of anumber can be converted too, again,
52
+ upto base 62.
56
53
 
54
+ "10".b(62).to_s(10) #=> "62"
57
55
 
58
- == HOW TO INSTALL
56
+ To use a custom character set, use an array of characters as the base
57
+ rather than an integer. For example we can convert a base 10 number
58
+ to another base 10 number using a different encoding.
59
59
 
60
- To install with RubyGems simply open a console and type:
60
+ base = [:Q, :W, :E, :R, :T, :Y, :U, :I, :O, :U]
61
+
62
+ "10".b(10).to_a(base) #=> [:W, :Q]
61
63
 
62
- gem install radix
64
+ To learn more have a look at the {QED}[http://rubyworks.github.com/radix/docs/qed].
63
65
 
64
- Site installation requires Setup.rb (gem install setup),
65
- then download the tarball package and type:
66
+ == HOW TO INSTALL
67
+
68
+ To install with RubyGems simply open a console and type:
66
69
 
67
- tar -xvzf radix-1.0.0.tgz
68
- cd radix-1.0.0
69
- sudo setup.rb all
70
+ $ gem install radix
70
71
 
71
- Windows users use 'ruby setup.rb all'.
72
+ Radix follows {Ruby Setup}[http://rubyworks.github.com/setup] package standard.
72
73
 
73
74
 
74
- == LINCENSE/COPYRIGHT
75
+ == LICENSE/COPYRIGHT
75
76
 
76
77
  Copyright (c) 2009 Thomas Sawyer
77
78
 
78
- This program is ditributed unser the terms of the LGPLv3 license.
79
+ This program is ditributed unser the terms of the Apache 2.0 license.
79
80
 
80
81
  See LICENSE file for details.
@@ -0,0 +1,60 @@
1
+ = Synopsis
2
+
3
+ Base conversions with ASCII ordered notations are easy in Ruby.
4
+
5
+ 255.to_s(16) #=> "ff"
6
+ "ff".to_i(16) #=> 255
7
+
8
+ But Ruby reaches it's limit at base 36.
9
+
10
+ expect ArgumentError do
11
+ 255.to_s(37)
12
+ end
13
+
14
+ Radix provides the means of converting to and from any base.
15
+
16
+ require 'radix'
17
+
18
+ For example, a number in base 256 can be represented by the array [100, 10]
19
+ (ie. 100**256 + 10**1) and easily converted to base 10.
20
+
21
+ [100,10].b(256).to_i #=> 25610
22
+
23
+ We can get an Array representation as well.
24
+
25
+ [100,10].b(256).to_a(10) #=> [2,5,6,1,0]
26
+ [100,10].b(256).to_a(62) #=> [6,41,4]
27
+ [100,10].b(256).to_a(64) #=> [6,16,10]
28
+
29
+ To get a String representation for any base use #to_s.
30
+
31
+ [100,10].b(256).to_s(10) #=> "25610"
32
+ [100,10].b(256).to_s(62) #=> "6 41 4"
33
+ [100,10].b(256).to_s(64) #=> "6 16 10"
34
+
35
+ Notice that anything above base 10 is seperated by a space divider. The divider
36
+ can be changed by providing a second argument.
37
+
38
+ [100,10].b(256).to_s(64, ':') #=> "6:16:10"
39
+
40
+ A string representation of a number can be converted upto base 62 (B62).
41
+
42
+ "10".b(62).to_s(10) #=> "62"
43
+ "zz".b(62).to_s(10) #=> "3843"
44
+
45
+ To encode a number with a base greater than 10, use an Array base. Radix
46
+ provides a built-in set of these, such as `BASE::B62`.
47
+
48
+ [100,10].b(256).to_s(Radix::BASE::B62) #=> "6f4"
49
+
50
+ To use a custom character set, use an array of characters as the base
51
+ rather than an integer. For example we can convert a base 10 number
52
+ to another base 10 number but useing a different encoding.
53
+
54
+ base = %w[Q W E R T Y U I O U]
55
+
56
+ "10".b(10).to_a(base) #=> ["W", "Q"]
57
+
58
+ "10".b(10).to_s(base) #=> "WQ"
59
+
60
+ All of the above holds equally for floating point numbers.
@@ -0,0 +1,48 @@
1
+ = Radix Integer
2
+
3
+ Radix provides an Integer class for working with integers in various bases.
4
+
5
+ require 'radix'
6
+
7
+ Radix extend the Integer, String and Array classes with the #b method
8
+ which simplifies the creation of Radix::Integer instances. The following
9
+ return the equivalent instance of Radix::Integer.
10
+
11
+ a = 8.b(2)
12
+
13
+ b = "1000".b(2)
14
+
15
+ c = [1, 0, 0, 0].b(2)
16
+
17
+ a.assert == b
18
+ b.assert == c
19
+ c.assert == a
20
+
21
+ a.assert == 8
22
+ b.assert == 8
23
+ c.assert == 8
24
+
25
+ Radix integers can ve converted to other bases with the #convert method.
26
+
27
+ b = "1000".b(2)
28
+ d = b.convert(10)
29
+ d.digits.assert == [8]
30
+
31
+ Radix::Integer supports all the usual mathematical operators.
32
+
33
+ r = "1000".b(2) + "2".b(8)
34
+ r.assert == "1010".b(2)
35
+ r.assert == "12".b(8)
36
+ r.assert == "10".b(10)
37
+
38
+ A more complex example with a much higher base.
39
+
40
+ r = "AZ42".b(62) + "54".b(10)
41
+ r.assert == "2518124".b(10)
42
+ r.assert == 2518124
43
+
44
+ Work with arrays for bases greater than 62.
45
+
46
+ r = [100,10].b(256) + "54".b(10)
47
+ r.assert == "25664".b(10)
48
+
@@ -0,0 +1,36 @@
1
+ = Radix Float
2
+
3
+ Radix provides a Float class for working with floating point numbers in
4
+ any base.
5
+
6
+ require 'radix'
7
+
8
+ With it, the #b method extends String and Array classes to
9
+ simplify all mulit-base operations.
10
+
11
+ b = "100.01".b(2)
12
+ b.to_a.assert == [1,0,0,'.',0,1]
13
+
14
+ Convert to base 10.
15
+
16
+ t = b.convert(10)
17
+ t.to_a.assert == [4,'.',2,5]
18
+
19
+ Like a Numeric class, Radix::Float's can be added, subtracted, multipled, etc.
20
+
21
+ r = "1000.01".b(2) + "2".b(8)
22
+ r.assert == "1010.01".b(2)
23
+ r.assert == "12.2".b(8)
24
+ r.assert == "10.25".b(10)
25
+
26
+ Even complex conversions are supported.
27
+
28
+ r = "AZ42".b(62) + "54".b(10)
29
+ r.assert == "2518124".b(10)
30
+
31
+ To work with bases greater than 62, use arrays. A '.' entry in the array
32
+ can be used to separate the whole from the fractional part of the number.
33
+
34
+ r = [100,10,'.',64].b(256) + "54".b(10)
35
+ r.assert == "25664.25".b(10)
36
+
@@ -0,0 +1,27 @@
1
+ = Radix Rational
2
+
3
+ Radix also provides a Rational class. Like the Integer and Float classes
4
+ Radix::Rational delegates to an underlying instance of Ruby standard
5
+ Rational class.
6
+
7
+ require 'radix'
8
+
9
+ b = ["100","10"].br(2)
10
+ b.assert = [2,1].br(10)
11
+
12
+ When convert to Array or String Radix::Rational uses `/` to separate
13
+ the numerator from the denominator.
14
+
15
+ b.to_a #=> [1,0,0,'/',1,0]
16
+ b.to_s #=> "100/10"
17
+
18
+ To use a custom character set, use an array of characters as the base
19
+ rather than an integer. For example we can convert a base 10 number
20
+ to another base 10 number but useing a different encoding.
21
+
22
+ base = %w[Q W E R T Y U I O U]
23
+
24
+ ["10","1"].br(10).to_a(base) #=> ["W", "Q", '/', 'W']
25
+
26
+ ["10","1"].br(10).to_s(base) #=> "WQ/W"
27
+
@@ -1,14 +1,20 @@
1
- = Overview of Radix::::Base
1
+ = Radix Base
2
2
 
3
- First require the library.
3
+ Radix::Base encapsulates a base which can then be used to perform conversions
4
+ to and form that base.
5
+
6
+ NOTE: Radix::Base is the original Radix API. But with the advent of v2.0
7
+ and the new Integer and Float classes, it is outmoded. For now it is here
8
+ for backward compatibility. In a future version it may be deprecated, or
9
+ reworked to serve as the backbone of the other classes.
4
10
 
5
11
  require 'radix/base'
6
12
 
7
13
  First let's try something we all know, hexideciaml.
8
14
  First we setup the radix for each.
9
15
 
10
- b10 = Radix::Base.new(Radix::Base::BASE10)
11
- b16 = Radix::Base.new(Radix::Base::BASE16)
16
+ b10 = Radix::Base.new(Radix::BASE::B10)
17
+ b16 = Radix::Base.new(Radix::BASE::B16)
12
18
 
13
19
  Now we can covert from one base to the other.
14
20
 
@@ -30,42 +36,47 @@ a Radix object.
30
36
  b10.convert("A0", 16).should == "160"
31
37
  b10.convert("FF", 16).should == "255"
32
38
 
33
- We can also use the module function to convert to and from standard
34
- notations upto 62 without creating an instance of Radix::Base.
39
+ Now let's try a more down to earth base, my favorite,
40
+ senary, or base six.
35
41
 
36
- Radix::Base.convert("10", 16, 10).should == "16"
37
- Radix::Base.convert("A0", 16, 10).should == "160"
38
- Radix::Base.convert("FF", 16, 10).should == "255"
42
+ b6 = Radix::Base.new(0..5)
43
+ b6.convert("39", 10).should == "103"
39
44
 
40
- Let's try that again with the maximum base supported.
45
+ And the notations need not be in ASCII order. Odd alternate notations
46
+ can be used as well.
41
47
 
42
- Radix::Base.convert( "62", 10, 62).should == "10"
43
- Radix::Base.convert("8814542", 10, 62).should == "AZ42"
48
+ b10 = Radix::Base.new([:Q, :W, :E, :R, :T, :Y, :U, :I, :O, :U])
49
+ b10.convert("FF", 16) #=> "EYY"
44
50
 
45
- Radix::Base.convert( "10", 62, 10).should == "62"
46
- Radix::Base.convert( "AZ42", 62, 10).should == "8814542"
51
+ == Encoding and Decoding
47
52
 
48
53
  Radix can also be used to encode and decode strings.
49
54
 
50
55
  b16.encode("CHARLIE").should == "434841524C4945"
51
56
  b16.decode("434841524C4945").should == "CHARLIE"
52
57
 
53
- Now let's try a more down to earth base, my favorite,
54
- senary, or base six.
58
+ == Module Methods
55
59
 
56
- b6 = Radix::Base.new(0..5)
57
- b6.convert("39", 10).should == "103"
60
+ We can also use the module function to convert to and from standard
61
+ notations upto 62 without creating an instance of Radix::Base.
58
62
 
59
- And the notations need not be in ASCII order. Odd alternate notations
60
- can be used as well.
63
+ Radix.convert("10", 16, 10).should == "16"
64
+ Radix.convert("A0", 16, 10).should == "160"
65
+ Radix.convert("FF", 16, 10).should == "255"
61
66
 
62
- b10 = Radix::Base.new([:Q, :W, :E, :R, :T, :Y, :U, :I, :O, :U])
63
- b10.convert("FF", 16) #=> "EYY"
67
+ Let's try that again with the maximum base supported.
68
+
69
+ Radix.convert( "62", 10, 62).should == "10"
70
+ Radix.convert("8814542", 10, 62).should == "az42"
71
+
72
+ Radix.convert( "10", 62, 10).should == "62"
73
+ Radix.convert( "az42", 62, 10).should == "8814542"
64
74
 
65
75
  Finally, we will demonstrate how to convert bases larger than 62.
66
76
  These can only be represented as arrays since there are not enough
67
77
  latin characters to represent them.
68
78
 
69
- Radix::Base.convert_base([100, 10], 256, 10).should == [2, 5, 6, 1, 0]
70
- Radix::Base.convert_base([2, 5, 6, 1, 0], 10, 256).should == [100, 10]
79
+ Radix.convert_base([100, 10], 256, 10).should == [2, 5, 6, 1, 0]
80
+ Radix.convert_base([2, 5, 6, 1, 0], 10, 256).should == [100, 10]
81
+ Radix.convert_base([1, 0, 1, 0, 1], 2, 10).should == [2, 1]
71
82
 
File without changes
@@ -0,0 +1 @@
1
+ require 'qed/extensions/check'
@@ -1 +1,42 @@
1
- require 'radix/operator'
1
+ require 'radix/meta/data'
2
+ require 'radix/base'
3
+ require 'radix/integer'
4
+ require 'radix/float'
5
+ require 'radix/rational' # load ?
6
+
7
+ class ::Float
8
+ #
9
+ def b(base)
10
+ Radix::Float.new(self, base)
11
+ end
12
+ end
13
+
14
+ class ::Integer
15
+ #
16
+ def b(base)
17
+ Radix::Integer.new(self, base)
18
+ end
19
+ end
20
+
21
+ class ::String
22
+ #
23
+ def b(base)
24
+ if index('.')
25
+ Radix::Float.new(self, base)
26
+ else
27
+ Radix::Integer.new(self, base)
28
+ end
29
+ end
30
+ end
31
+
32
+ class ::Array
33
+ #
34
+ def b(base)
35
+ if index('.')
36
+ Radix::Float.new(self, base)
37
+ else
38
+ Radix::Integer.new(self, base)
39
+ end
40
+ end
41
+ end
42
+
@@ -1,96 +1,81 @@
1
- # Radix coverts to and from any base.
2
- #
3
- # Base conversions with ASCII ordered notations are easy in Ruby.
4
- #
5
- # 255.to_s(16) #=> "FF"
6
- # "FF".to_i(16) #=> 255
7
- #
8
- # But Ruby reaches it's limit at base 36.
9
- #
10
- # 255.to_s(37) #=> Error
11
- #
12
- # Radix provides the means of converting to and from any base.
13
- #
14
- # Radix::Base.convert_base([100, 10], 256, 10)
15
- # #=> [2,5,6,1,0]
16
- #
17
- # And it can handle any notation upto base 62.
18
- #
19
- # Radix::Base.convert("10", 62, 10) #=> "62"
20
- #
21
- # And the notations need not be in ASCII order --odd notations
22
- # can be used.
23
- #
24
- # b10 = Radix::Base.new([:Q, :W, :E, :R, :T, :Y, :U, :I, :O, :U])
25
- # b10.convert("FF", 16) #=> "EYY"
26
- #
27
1
  module Radix
28
2
 
29
- class Base
3
+ # Collection of base encodings.
4
+ module BASE
5
+ B10 = ('0'..'9').to_a
6
+ B12 = B10 + ['X', 'E']
7
+ B16 = B10 + ('A'..'F').to_a
8
+ B36 = B10 + ('A'..'Z').to_a
9
+ B60 = B36 + ('a'..'x').to_a
10
+ B62 = B36 + ('a'..'z').to_a
11
+
12
+ # Like BASE16 but encodes with lowercase letters.
13
+ HEX = B10 + ('a'..'f').to_a
14
+ end
30
15
 
31
- BASE10 = ["0".."9"].map { |r| r.to_a }.flatten
32
- BASE12 = ["0".."9", ["X", "E"]].map { |r| r.to_a }.flatten
33
- BASE16 = ["0".."9", "A".."F"].map { |r| r.to_a }.flatten
34
- BASE36 = ["0".."9", "A".."Z"].map { |r| r.to_a }.flatten
35
- BASE60 = ["0".."9", "a".."z", "A".."X"].map { |r| r.to_a }.flatten
36
- BASE62 = ["0".."9", "a".."z", "A".."Z"].map { |r| r.to_a }.flatten
16
+ # Radix::Base provides the means of converting to and from any base.
17
+ #
18
+ # b10 = Radix::Base.new(10)
19
+ # b10.convert_base([100, 10], 256)
20
+ # #=> [2,5,6,1,0]
21
+ #
22
+ # And it can handle any notation upto base 62.
23
+ #
24
+ # b10.convert("10", 62) #=> "62"
25
+ #
26
+ # And the notations need not be in ASCII order --odd notations
27
+ # can be used.
28
+ #
29
+ # b10 = Radix::Base.new(%w{Q W E R T Y U I O U})
30
+ # b10.convert("FF", 16) #=> "EYY"
31
+ #
32
+ # NOTE: Radix::Base is the original Radix API. But with the advent of v2.0
33
+ # and the new Integer and Float classes, it is outmoded. For now it is here
34
+ # for backward compatibility. In a future version it may be deprecated, or
35
+ # reworked to serve as the backbone of the other classes.
36
+ #
37
+ class Base
37
38
 
38
39
  attr :chars
40
+
39
41
  attr :base
42
+
40
43
  attr :values
41
44
 
42
45
  # New Radix using +chars+ representation.
43
- def initialize(chars=BASE62)
46
+ def initialize(chars=BASE::B62)
47
+ if ::Numeric === chars
48
+ chars = BASE::B62[0...chars]
49
+ end
44
50
  @chars = chars.map{ |c| c.to_s }
45
51
  @base = @chars.size
46
52
  @values = Hash[*(0...@base).map { |i| [ @chars[i], i ] }.flatten]
47
53
  end
48
54
 
49
- # Encode a string in the radix.
50
- def encode(byte_string)
51
- digits = byte_string.unpack("C*")
52
- digits = convert_base(digits, 256, base)
53
- digits.map{ |d| @chars[d] }.join
54
- end
55
+ # Convert an *encoded* +number+ of given +base+ to the Base's radix.
56
+ def convert(number, radix_base)
57
+ radix_base = Radix::Base.new(radix_base) unless Radix::Base === radix_base
55
58
 
56
- # Decode a string that was previously encoded in the radix.
57
- def decode(encoded)
58
- digits = encoded.split(//).map{ |c| @values[c] }
59
- convert_base(digits, base, 256).pack("C*")
60
- end
59
+ case number
60
+ when ::String, ::Numeric
61
+ digits = number.to_s.split(//)
62
+ else
63
+ digits = number
64
+ end
65
+
66
+ # decode the digits
67
+ digits = digits.map{ |digit| radix_base.values[digit] }
68
+
69
+ # THINK: Is best way to check for base out of bounds?
70
+ raise TypeError if digits.any?{ |digit| digit.nil? }
61
71
 
62
- # Convert a representational +number+ of +from_radix+ to the radix.
63
- def convert(number, from_radix)
64
- from_radix = standard_radix(from_radix) if Integer === from_radix
65
- digits = number.to_s.split(//)
66
- digits = digits.map{ |digit| from_radix.values[digit] }
67
- digits = convert_base(digits, from_radix.base, base)
72
+ digits = Radix.convert_base(digits, radix_base.base, base)
68
73
  digits = digits.map{ |digit| chars[digit] }
69
74
  digits.join
70
75
  end
71
76
 
72
77
  # Convert any base to any other base, using array of +digits+.
73
78
  def convert_base(digits, from_base, to_base)
74
- self.class.convert_base(digits, from_base, to_base)
75
- end
76
-
77
- private
78
-
79
- def standard_radix(integer_base)
80
- self.class.standard_radix(integer_base)
81
- end
82
-
83
- public
84
-
85
- # Do a standard conversion upto base 62.
86
- def self.convert(number, from_base, to_base)
87
- r1 = standard_radix(from_base)
88
- r2 = standard_radix(to_base)
89
- r2.convert(number, r1)
90
- end
91
-
92
- # Convert any base to any other base, using array of +digits+.
93
- def self.convert_base(digits, from_base, to_base)
94
79
  bignum = 0
95
80
  digits.each { |digit| bignum = bignum * from_base + digit }
96
81
  converted = []
@@ -98,33 +83,44 @@ module Radix
98
83
  bignum, digit = bignum.divmod(to_base)
99
84
  converted.push(digit)
100
85
  end
86
+ converted << 0 if converted.empty? # THINK: correct?
101
87
  converted.reverse
102
88
  end
103
89
 
104
- # Provide a standard representation of a base upto 62.
105
- def self.standard_radix(integer_base)
106
- if integer_base > 36
107
- new(BASE62[0..integer_base-1])
108
- else
109
- new(BASE36[0..integer_base-1])
110
- end
90
+ # Encode a string in the radix.
91
+ def encode(byte_string)
92
+ digits = byte_string.unpack("C*")
93
+ digits = Radix.convert_base(digits, 256, base)
94
+ digits.map{ |d| @chars[d] }.join
95
+ end
96
+
97
+ # Decode a string that was previously encoded in the radix.
98
+ def decode(encoded)
99
+ digits = encoded.split(//).map{ |c| @values[c] }
100
+ Radix.convert_base(digits, base, 256).pack("C*")
111
101
  end
112
102
 
113
103
  end
114
104
 
105
+ # Convert number from it's given base to antoher base.
115
106
  # Do a standard conversion upto base 62.
116
107
  def self.convert(number, from_base, to_base)
117
- Radix::Base.convert(number, from_base, to_base)
108
+ from_base = Radix::Base.new(from_base) unless Radix::Base === from_base
109
+ to_base = Radix::Base.new(to_base) unless Radix::Base === to_base
110
+ to_base.convert(number, from_base)
118
111
  end
119
112
 
120
113
  # Convert any base to any other base, using array of +digits+.
121
114
  def self.convert_base(digits, from_base, to_base)
122
- Radix::Base.convert_base(digits, from_base, to_base)
123
- end
124
-
125
- # Provide a standard representation of a base upto 62.
126
- def self.standard_radix(integer_base)
127
- Radix::Base.standard_radix(integer_base)
115
+ bignum = 0
116
+ digits.each { |digit| bignum = bignum * from_base + digit }
117
+ converted = []
118
+ until bignum.zero?
119
+ bignum, digit = bignum.divmod(to_base)
120
+ converted.push(digit)
121
+ end
122
+ converted << 0 if converted.empty? # THINK: correct?
123
+ converted.reverse
128
124
  end
129
125
 
130
126
  end