all-your-base 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,5 +1,5 @@
1
1
  *.sw?
2
2
  .DS_Store
3
3
  coverage
4
- rdoc
4
+ doc
5
5
  pkg
@@ -1,6 +1,62 @@
1
1
  = all-your-base
2
2
 
3
- These are extensions to Integer#to_s and String#to_i that allow bases larger than 36.
3
+ All your base provides arbitrary base conversion.
4
+
5
+ == Get it
6
+
7
+ The latest release is available on gemcutter.
8
+ sudo gem install gemcutter
9
+ sudo gem tumble
10
+ sudo gem install all-your-base
11
+
12
+ == Require it
13
+
14
+ To use the generalized API:
15
+ require 'all_your_base'
16
+
17
+ To use the simple Integer and String extensions:
18
+ require 'all_your_base/are/belong_to_us'
19
+
20
+ == Use it
21
+
22
+ All of the instance and class methods, including "new" accept an options hash.
23
+ It can contain :charset, :radix, and :honor_negation.
24
+
25
+ Instance Methods
26
+ @ayb = AllYourBase::Are.new
27
+ %w(foo bar muffin).map do |word|
28
+ "#{word} in base 10 is: #{@ayb.convert_to_base_10(word)}"
29
+ end
30
+ => foo in base 10 is: 253394
31
+ => bar in base 10 is: 227969
32
+ => muffin in base 10 is: 140676922357
33
+
34
+ %w(253394 227969 140676922357).map do |int|
35
+ "#{int} from base 10 is: #{@ayb.convert_from_base_10(int)}"
36
+ end
37
+ => 253394 from base 10 is: foo
38
+ => 227969 from base 10 is: bar
39
+ => 140676922357 from base 10 is: muffin
40
+
41
+ Class Methods
42
+ AllYourBase::Are.convert_to_base_10("foo")
43
+ => 253394
44
+
45
+ AllYourBase::Are.convert_from_base_10(140676922357)
46
+ => "muffin"
47
+
48
+ Fun Stuff!
49
+ "foo".from_base_78.to_base_32
50
+ => "7NEI"
51
+
52
+ 100011.from_base_3.to_base_11
53
+ => "205"
54
+
55
+ "foo".from_base_56.from_base_7.to_base_8.to_base_72
56
+ => "BAR"
57
+
58
+ "Zero".from_base_57.from_base_12.to_base_13.to_base_50
59
+ => "WIng"
4
60
 
5
61
  == Note on Patches/Pull Requests
6
62
 
data/Rakefile CHANGED
@@ -42,7 +42,7 @@ Rake::RDocTask.new do |rdoc|
42
42
  version = ""
43
43
  end
44
44
 
45
- rdoc.rdoc_dir = 'rdoc'
45
+ rdoc.rdoc_dir = 'doc'
46
46
  rdoc.title = "all-your-base #{version}"
47
47
  rdoc.rdoc_files.include('README*')
48
48
  rdoc.rdoc_files.include('lib/**/*.rb')
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.1
1
+ 0.3.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{all-your-base}
8
- s.version = "0.2.1"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Rusty Burchfield"]
12
- s.date = %q{2009-10-14}
12
+ s.date = %q{2009-10-19}
13
13
  s.description = %q{Provides numeric base conversions greater than base 36}
14
14
  s.email = %q{GICodeWarrior@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -28,6 +28,8 @@ Gem::Specification.new do |s|
28
28
  "lib/all_your_base.rb",
29
29
  "lib/all_your_base/are.rb",
30
30
  "lib/all_your_base/are/belong_to_us.rb",
31
+ "scripts/brute.rb",
32
+ "scripts/demo.rb",
31
33
  "spec/all_your_base/are/belong_to_us_spec.rb",
32
34
  "spec/all_your_base/are_spec.rb",
33
35
  "spec/spec_helper.rb"
@@ -1,6 +1,6 @@
1
1
  module AllYourBase
2
2
  class Are
3
-
3
+
4
4
  # This charset works for "standard" bases 2-36 and 62. It also provides
5
5
  # non-standard bases 1 and 37-61 for most uses.
6
6
  BASE_62_CHARSET = ('0'..'9').to_a + ('A'..'Z').to_a + ('a'..'z').to_a
@@ -14,24 +14,19 @@ module AllYourBase
14
14
  # or care about the validity of these characters.
15
15
  BASE_78_CHARSET = BASE_62_CHARSET + ['!', '$', '&', "'", '(', ')', '*', '+',
16
16
  ',', '-', '.', ':', ';', '=', '@', '_']
17
-
18
- def initialize(charset, options={})
19
- options[:radix] ||= charset.size
20
- if charset.size < 1 || charset.size < options[:radix]
21
- raise ArgumentError.new('charset too small ' << charset.size.to_s)
22
- elsif options[:radix] < 1
23
- raise ArgumentError.new('illegal radix ' << options[:radix].to_s)
24
- elsif charset.include?('-') && options[:honor_negation]
25
- raise ArgumentError.new('"-" is unsupported in charset when honor_negation is set')
26
- end
27
17
 
28
- @charset = charset
29
- @options = options
18
+ DEFAULT_OPTIONS = {:charset => BASE_78_CHARSET, :honor_negation => false}
19
+
20
+ def initialize(options={})
21
+ @default_options = DEFAULT_OPTIONS.merge(options)
22
+ @default_options = merge_and_validate_options
30
23
  end
31
24
 
32
- def convert_to_base_10(string)
25
+ def convert_to_base_10(string, options={})
26
+ options = merge_and_validate_options(options)
27
+
33
28
  negate = false
34
- if @options[:honor_negation]
29
+ if options[:honor_negation]
35
30
  negate = string[0...1] == '-'
36
31
  string = string[1...string.size] if negate
37
32
  end
@@ -39,30 +34,22 @@ module AllYourBase
39
34
  if string.size < 1
40
35
  raise ArgumentError.new('string too small ' << string.size.to_s)
41
36
  end
42
- if !string.match(/\A[#{Regexp.escape(@charset[0...@options[:radix]].join(''))}]+\Z/)
37
+ if !string.match(/\A[#{Regexp.escape(options[:charset][0...options[:radix]].join(''))}]+\Z/)
43
38
  raise ArgumentError.new('invalid characters')
44
39
  end
45
- regexp = Regexp.new(@charset.map{|c| Regexp.escape(c)}.join('|'))
40
+ regexp = Regexp.new(options[:charset].map{|c| Regexp.escape(c)}.join('|'))
46
41
  result = 0
47
42
  index = 0
48
43
  string.reverse.scan(regexp) do |c|
49
- result += @charset.index(c) * (@options[:radix] ** index)
44
+ result += options[:charset].index(c) * (options[:radix] ** index)
50
45
  index += 1
51
46
  end
52
47
  return result * (negate ? -1 : 1)
53
48
  end
54
-
55
- def self.convert_to_base_10(string, charset, options={})
56
- ayb = self.new(charset, options)
57
- ayb.convert_to_base_10(string)
58
- end
59
-
60
- def self.convert_from_base_10(int, charset, options={})
61
- ayb = self.new(charset, options)
62
- ayb.convert_from_base_10(int)
63
- end
64
-
65
- def convert_from_base_10(int)
49
+
50
+ def convert_from_base_10(int, options={})
51
+ options = merge_and_validate_options(options)
52
+
66
53
  if !int.to_s.match(/\A-?[0-9]+\Z/)
67
54
  raise ArgumentError.new('invalid characters')
68
55
  end
@@ -70,22 +57,46 @@ module AllYourBase
70
57
  return '0' if int == 0
71
58
 
72
59
  negate = false
73
- if @options[:honor_negation]
60
+ if options[:honor_negation]
74
61
  negate = int < 0
75
62
  end
76
63
  int = int.abs
77
-
78
- if @options[:radix] == 1
79
- result = @charset.first * int
64
+
65
+ if options[:radix] == 1
66
+ result = options[:charset].first * int
80
67
  else
81
68
  s = ''
82
69
  while int > 0
83
- s << @charset[int.modulo(@options[:radix])]
84
- int /= @options[:radix]
70
+ s << options[:charset][int.modulo(options[:radix])]
71
+ int /= options[:radix]
85
72
  end
86
73
  result = s.reverse
87
74
  end
88
75
  return ((negate ? '-' : '') << result)
89
76
  end
77
+
78
+ def self.convert_to_base_10(string, options={})
79
+ @@ayb ||= self.new
80
+ @@ayb.convert_to_base_10(string, options)
81
+ end
82
+
83
+ def self.convert_from_base_10(int, options={})
84
+ @@ayb ||= self.new
85
+ @@ayb.convert_from_base_10(int, options)
86
+ end
87
+
88
+ private
89
+ def merge_and_validate_options(options={})
90
+ options = @default_options.merge(options)
91
+ options[:radix] ||= options[:charset].size
92
+ if options[:charset].size < 1 || options[:charset].size < options[:radix]
93
+ raise ArgumentError.new('charset too small ' << options[:charset].size.to_s)
94
+ elsif options[:radix] < 1
95
+ raise ArgumentError.new('illegal radix ' << options[:radix].to_s)
96
+ elsif options[:charset].include?('-') && options[:honor_negation]
97
+ raise ArgumentError.new('"-" is unsupported in charset when honor_negation is set')
98
+ end
99
+ return options
100
+ end
90
101
  end
91
102
  end
@@ -6,17 +6,17 @@ module AllYourBase
6
6
  module From
7
7
  def method_missing(sym, *args, &block)
8
8
  if sym.to_s.match(/\Afrom_base_([0-9]+)\Z/)
9
- AllYourBase::Are.convert_to_base_10(self.to_s, AllYourBase::Are::BASE_78_CHARSET, {:radix => $1.to_i})
9
+ AllYourBase::Are.convert_to_base_10(self.to_s, {:radix => $1.to_i})
10
10
  else
11
11
  super # NoMethodError
12
12
  end
13
13
  end
14
14
  end
15
-
15
+
16
16
  module To
17
17
  def method_missing(sym, *args, &block)
18
18
  if sym.to_s.match(/\Ato_base_([0-9]+)\Z/)
19
- AllYourBase::Are.convert_from_base_10(self.to_i, AllYourBase::Are::BASE_78_CHARSET, {:radix => $1.to_i})
19
+ AllYourBase::Are.convert_from_base_10(self.to_i, {:radix => $1.to_i})
20
20
  else
21
21
  super # NoMethodError
22
22
  end
@@ -30,4 +30,3 @@ String.send :include, AllYourBase::Are::BelongToUs::From
30
30
  String.send :include, AllYourBase::Are::BelongToUs::To
31
31
  Integer.send :include, AllYourBase::Are::BelongToUs::From
32
32
  Integer.send :include, AllYourBase::Are::BelongToUs::To
33
-
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'rubygems'
4
+ require 'all_your_base/are/belong_to_us'
5
+
6
+ # Finds ways to convert from one string to another through four base
7
+ # conversions.
8
+ if ARGV.size != 2
9
+ puts <<EOF
10
+ Usage: ruby brute.rb <from> <to>
11
+ Finds ways to convert "from" to "to" through four base conversions.
12
+
13
+ Example:
14
+ $ ruby brute.rb foo bar
15
+ 'FOO' => 'BAR' -- [27, 9, 7, 53]
16
+ 'foo' => 'BAR' -- [56, 7, 8, 72]
17
+ ...
18
+
19
+ $ irb -r rubygems -r all_your_base/are/belong_to_us
20
+ irb(main):001:0> 'FOO'.from_base_27.from_base_9.to_base_7.to_base_53
21
+ => "BAR"
22
+ EOF
23
+ exit 1
24
+ end
25
+
26
+ def multi_case(s)
27
+ a = ['']
28
+ s.split(/\s*/).each do |c|
29
+ a = a.map{|s| s + c.downcase} + a.map{|s| s + c.upcase}
30
+ end
31
+ return a
32
+ end
33
+
34
+ def valid_bases(s)
35
+ max = 0
36
+ s.split(/\s*/).each do |c|
37
+ idx = AllYourBase::Are::BASE_78_CHARSET.index(c)
38
+ max = idx if idx > max
39
+ end
40
+ return (max+1..78)
41
+ end
42
+
43
+ def conversions_of(i)
44
+ list = multi_case(i).uniq
45
+ results = []
46
+ list.each do |s|
47
+ valid_bases(s).each do |r|
48
+ results << [s, r, s.send(:"from_base_#{r}")]
49
+ end
50
+ end
51
+ return results
52
+ end
53
+
54
+ hello = conversions_of(ARGV[0])
55
+ world = conversions_of(ARGV[1])
56
+
57
+ hc = []
58
+ hello.map{|h| conversions_of(h.last.to_s)}.each{|r| hc += r}
59
+ hc.sort!{|a, b| a.last.to_i <=> b.last.to_i}
60
+
61
+ wc = []
62
+ world.map{|w| conversions_of(w.last.to_s)}.each{|r| wc += r}
63
+ wc.sort!{|a, b| a.last.to_i <=> b.last.to_i}
64
+
65
+ while !hc.empty? && !wc.empty? do
66
+ h = hc.first
67
+ w = wc.first
68
+ if h.last == w.last
69
+ lr = hello.select{|m| m.last.to_s == h.first.to_s}.first
70
+ rr = world.select{|m| m.last.to_s == w.first.to_s}.first
71
+ puts "'#{lr.first}' => '#{rr.first}' -- " \
72
+ "[#{lr[1]}, #{h[1]}, #{w[1]}, #{rr[1]}]"
73
+ hc.shift
74
+ wc.shift
75
+ elsif h.last.to_i < w.last.to_i
76
+ hc.shift
77
+ else
78
+ wc.shift
79
+ end
80
+ end
81
+
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'rubygems'
4
+ require 'all_your_base/are/belong_to_us'
5
+
6
+ sections = ['Instance Methods', 'Class Methods', 'Fun Stuff!']
7
+
8
+ code = {'Instance Methods' =>
9
+ [' @ayb = AllYourBase::Are.new
10
+ %w(foo bar muffin).map do |word|
11
+ "#{word} in base 10 is: #{@ayb.convert_to_base_10(word)}"
12
+ end',
13
+ ' %w(253394 227969 140676922357).map do |int|
14
+ "#{int} from base 10 is: #{@ayb.convert_from_base_10(int)}"
15
+ end'],
16
+
17
+ 'Class Methods' =>
18
+ [' AllYourBase::Are.convert_to_base_10("foo")',
19
+ ' AllYourBase::Are.convert_from_base_10(140676922357)'],
20
+
21
+ 'Fun Stuff!' =>
22
+ [' "foo".from_base_78.to_base_32',
23
+ ' 100011.from_base_3.to_base_11',
24
+ ' "foo".from_base_56.from_base_7.to_base_8.to_base_72',
25
+ ' "Zero".from_base_57.from_base_12.to_base_13.to_base_50']}
26
+
27
+ sections.each do |s|
28
+ print "\e[H\e[2J"
29
+ puts " # #{s}"
30
+ puts
31
+ code[s].each do |c|
32
+ print c
33
+ readline
34
+ result = eval(c)
35
+ if result.is_a?(Array)
36
+ puts result.map{|r| "=> #{r}"}.join("\n")
37
+ else
38
+ puts "=> #{result.inspect}"
39
+ end
40
+ readline
41
+ end
42
+ end
@@ -13,36 +13,32 @@ describe AllYourBase::Are do
13
13
 
14
14
  describe "#initialize" do
15
15
  it "should not allow charsets less 1" do
16
- lambda {ayb = AllYourBase::Are.new([], {:radix =>1})}.should raise_error(ArgumentError, 'charset too small 0')
16
+ lambda {ayb = AllYourBase::Are.new({:charset => [], :radix => 1})}.should raise_error(ArgumentError, 'charset too small 0')
17
17
  end
18
18
  it "should not allow radix of less than 1" do
19
- lambda {ayb = AllYourBase::Are.new(AllYourBase::Are::BASE_78_CHARSET, {:radix =>0})}.should raise_error(ArgumentError, 'illegal radix 0')
19
+ lambda {ayb = AllYourBase::Are.new({:radix => 0})}.should raise_error(ArgumentError, 'illegal radix 0')
20
20
  end
21
- it "should set the charset instance variable" do
22
- ayb = AllYourBase::Are.new(AllYourBase::Are::BASE_78_CHARSET, {:radix =>78})
23
- ayb.instance_variable_get('@charset').should eql(AllYourBase::Are::BASE_78_CHARSET)
24
- end
25
- it "should set the options instance variable" do
26
- ayb = AllYourBase::Are.new(AllYourBase::Are::BASE_78_CHARSET, {:radix => 12})
27
- ayb.instance_variable_get('@options').should == {:radix => 12}
21
+ it "should default charset to base 78" do
22
+ ayb = AllYourBase::Are.new()
23
+ ayb.instance_variable_get('@default_options')[:charset].should eql(AllYourBase::Are::BASE_78_CHARSET)
28
24
  end
29
25
  it "should default radix to size of charset" do
30
- ayb = AllYourBase::Are.new(AllYourBase::Are::BASE_78_CHARSET)
31
- ayb.instance_variable_get('@options')[:radix].should eql(78)
26
+ ayb = AllYourBase::Are.new({:charset => [1, 2, 3]})
27
+ ayb.instance_variable_get('@default_options')[:radix].should eql(3)
32
28
  end
33
29
  it "should not allow a char set with - when :honor_negation is set" do
34
30
  lambda {
35
- AllYourBase::Are.new(['a', 'y', 'b', '-'], {:honor_negation => true})
31
+ AllYourBase::Are.new({:charset => ['a', 'y', 'b', '-'], :honor_negation => true})
36
32
  }.should raise_error(ArgumentError, '"-" is unsupported in charset when honor_negation is set')
37
33
  end
38
34
  end
39
35
 
40
36
  describe "#convert_to_base_10" do
41
37
  before(:each) do
42
- @ayb = AllYourBase::Are.new(AllYourBase::Are::BASE_78_CHARSET)
38
+ @ayb = AllYourBase::Are.new()
43
39
  end
44
40
  it "should raise if input is contains invalid characters" do
45
- ayb = AllYourBase::Are.new(AllYourBase::Are::BASE_78_CHARSET, {:radix => 5})
41
+ ayb = AllYourBase::Are.new({:radix => 5})
46
42
  lambda {ayb.convert_to_base_10('foo')}.should raise_error("invalid characters")
47
43
  end
48
44
  it "should raise error if string is too short" do
@@ -53,7 +49,7 @@ describe AllYourBase::Are do
53
49
  end
54
50
  describe "when honor_negation is true" do
55
51
  before(:each) do
56
- @ayb = AllYourBase::Are.new(AllYourBase::Are::BASE_62_CHARSET, {:honor_negation => true})
52
+ @ayb = AllYourBase::Are.new({:charset => AllYourBase::Are::BASE_62_CHARSET, :honor_negation => true})
57
53
  end
58
54
  it "should raise error if string is too short" do
59
55
  lambda {@ayb.convert_to_base_10('-')}.should raise_error(ArgumentError, 'string too small 0')
@@ -69,40 +65,40 @@ describe AllYourBase::Are do
69
65
 
70
66
  describe "#convert_from_base_10" do
71
67
  it "should raise if input is not base 10" do
72
- ayb = AllYourBase::Are.new(AllYourBase::Are::BASE_78_CHARSET, {:radix => 5})
68
+ ayb = AllYourBase::Are.new({:radix => 5})
73
69
  lambda {ayb.convert_from_base_10('foo')}.should raise_error("invalid characters")
74
70
  end
75
71
  it "should convert from base 10" do
76
- @ayb = AllYourBase::Are.new(AllYourBase::Are::BASE_78_CHARSET)
72
+ @ayb = AllYourBase::Are.new()
77
73
  @ayb.convert_from_base_10(855149198991141649141572449638390201857110945891509).should eql('somebody_set_up_us_the_bomb')
78
74
  end
79
75
  it "should return '0' if value is 0" do
80
- @ayb = AllYourBase::Are.new(AllYourBase::Are::BASE_78_CHARSET)
76
+ @ayb = AllYourBase::Are.new()
81
77
  @ayb.convert_from_base_10(0).should eql('0')
82
78
  end
83
79
  it "should return a string with a - at the beginning if value is negative and negation is honored" do
84
- @ayb = AllYourBase::Are.new(AllYourBase::Are::BASE_64_CHARSET, {:honor_negation => true})
80
+ @ayb = AllYourBase::Are.new({:charset => AllYourBase::Are::BASE_64_CHARSET, :honor_negation => true})
85
81
  @ayb.convert_from_base_10(-100).should eql('-Bk')
86
82
  end
87
83
  it "should return value if radix is 1" do
88
- @ayb = AllYourBase::Are.new(AllYourBase::Are::BASE_64_CHARSET, {:radix =>1})
84
+ @ayb = AllYourBase::Are.new({:charset => AllYourBase::Are::BASE_64_CHARSET, :radix =>1})
89
85
  @ayb.convert_from_base_10(11).should eql('AAAAAAAAAAA')
90
86
  end
91
87
  it "should return other value if radix is not 1" do
92
- @ayb = AllYourBase::Are.new(AllYourBase::Are::BASE_64_CHARSET,{:radix =>12})
88
+ @ayb = AllYourBase::Are.new({:charset => AllYourBase::Are::BASE_64_CHARSET, :radix => 12})
93
89
  @ayb.convert_from_base_10(11).should eql('L')
94
90
  end
95
91
  end
96
92
 
97
93
  describe ".convert_to_base_10" do
98
94
  it "should allow you to convert to base 10 without initializing an instance of AllYourBase::Are" do
99
- result = AllYourBase::Are.convert_to_base_10('A', AllYourBase::Are::BASE_78_CHARSET)
95
+ result = AllYourBase::Are.convert_to_base_10('A')
100
96
  result.should eql(10)
101
97
  end
102
98
  end
103
99
  describe ".convert_from_base_10" do
104
100
  it "should allow you to convert from base 10 without initializing an instance of AllYourBase::Are" do
105
- result = AllYourBase::Are.convert_from_base_10(10, AllYourBase::Are::BASE_78_CHARSET)
101
+ result = AllYourBase::Are.convert_from_base_10(10)
106
102
  result.should eql('A')
107
103
  end
108
104
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: all-your-base
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rusty Burchfield
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-14 00:00:00 -07:00
12
+ date: 2009-10-19 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -43,6 +43,8 @@ files:
43
43
  - lib/all_your_base.rb
44
44
  - lib/all_your_base/are.rb
45
45
  - lib/all_your_base/are/belong_to_us.rb
46
+ - scripts/brute.rb
47
+ - scripts/demo.rb
46
48
  - spec/all_your_base/are/belong_to_us_spec.rb
47
49
  - spec/all_your_base/are_spec.rb
48
50
  - spec/spec_helper.rb