all-your-base 0.2.1 → 0.3.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 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