forresty
3/3/2015 - 6:32 PM

base64.rb

#!/usr/bin/env ruby

module Base64
  extend self

  CHAR_MAP = Hash[(0..25).map { |i| [[i,(65+i).chr], [i+26, (97+i).chr]] }.flatten(1) + (0..9).map { |i| [i+52, i.to_s] }  + [[62,'+'], [63,'/']]]

  def encode(input)
    result = input.bytes.each_slice(3).map do |a, b, c|
      r1 = a >> 2

      if b.nil?
        r2 = ((a & 3) << 4)

        CHAR_MAP.values_at(r1, r2) + ['=', '=']
      elsif c.nil?
        r2 = ((a & 3) << 4) + (b >> 4)
        r3 = ((b & 15) << 2)

        CHAR_MAP.values_at(r1, r2, r3) << '='
      else
        r2 = ((a & 3) << 4) + (b >> 4)
        r3 = ((b & 15) << 2) + (c >> 6)
        r4 = c & 63

        CHAR_MAP.values_at(r1, r2, r3, r4)
      end
    end.flatten.join
  end
end

tests = {
  'any carnal pleasure.' => 'YW55IGNhcm5hbCBwbGVhc3VyZS4=',
  'any carnal pleasure'  => 'YW55IGNhcm5hbCBwbGVhc3VyZQ==',
  'any carnal pleasur'   => 'YW55IGNhcm5hbCBwbGVhc3Vy',
  'any carnal pleasu'    => 'YW55IGNhcm5hbCBwbGVhc3U=',
  'any carnal pleas'     => 'YW55IGNhcm5hbCBwbGVhcw==',
}

tests.each do |origin, encoded|
  unless Base64.encode(origin) == encoded
    raise "failed: expecting
      #{encoded}
      got
      #{Base64.encode(origin)}
    "
  end
end

puts "success"