lib/more_math/numberify_string_function.rb



module MoreMath
  module NumberifyStringFunction
    Functions = MoreMath::Functions

    module_function

    def numberify_string(string, alphabet = 'a'..'z')
      alphabet = NumberifyStringFunction.convert_alphabet alphabet
      s, k = string.size, alphabet.size
      result = 0
      for i in 0...s
        c = string[i, 1]
        a = (alphabet.index(c) || raise(ArgumentError, "#{c.inspect} not in alphabet")) + 1
        j = s - i - 1
        result += a * k ** j
      end
      result
    end

    def stringify_number(number, alphabet = 'a'..'z')
      case
      when number < 0
        raise ArgumentError, "number is required to be >= 0"
      when number == 0
        return ''
      end
      alphabet = NumberifyStringFunction.convert_alphabet alphabet
      s = NumberifyStringFunction.compute_size(number, alphabet.size)
      k, m = alphabet.size, number
      result = ' ' * s
      q = m
      s.downto(1) do |i|
        r = q / k
        q = r * k < q ? r : r - 1
        result[i - 1] = alphabet[m - q * k - 1]
        m = q
      end
      result
    end

    class << self
      memoize function:
      def compute_size(n, b)
        i = 0
        while n > 0
          i += 1
          n -= b ** i
        end
        i
      end

      def convert_alphabet(alphabet)
        if alphabet.respond_to?(:to_ary)
          alphabet.to_ary
        elsif alphabet.respond_to?(:to_str)
          alphabet.to_str.split(//)
        else
          alphabet.to_a
        end
      end
    end
  end
end