module Crockford

Encodes and decodes Crockford's Base32 variation.

Constants

DECODER
ENCODER
VERSION

Public Class Methods

decode_number(string) click to toggle source
# File lib/crockford.rb, line 21
def decode_number(string)
  clean_code(string).each_char.inject(0) do |result, char|
    val = DECODER[char]
    return nil if val.nil?

    (result << 5) + val
  end
end
decode_string(string) click to toggle source
# File lib/crockford.rb, line 35
def decode_string(string)
  number = decode_number(string)
  return nil if number.nil?

  number.to_s(2).each_char.reverse_each.each_slice(8).map do |byte|
    byte.reverse.join.to_i(2)
  end.reverse.pack("C*")
end
encode_number(number, **kwargs) click to toggle source
# File lib/crockford.rb, line 13
def encode_number(number, **kwargs)
  string = number.to_s(2).each_char.reverse_each.each_slice(5).map do |bits|
    ENCODER[bits.reverse.join.to_i(2)]
  end.reverse.join

  format_code(string, **kwargs)
end
encode_string(string, **kwargs) click to toggle source
# File lib/crockford.rb, line 30
def encode_string(string, **kwargs)
  number = string.bytes.map { |byte| format("%08b", byte) }.join.to_i(2)
  encode_number(number, **kwargs)
end
generate(length:, split: false) click to toggle source
# File lib/crockford.rb, line 55
def generate(length:, split: false)
  encode_number(SecureRandom.random_number(32**length), split: split, length: length)
end
normalize(string, unknown: "?", **kwargs) click to toggle source
# File lib/crockford.rb, line 44
def normalize(string, unknown: "?", **kwargs)
  string = clean_code(string).each_char.inject("") do |memo, char|
    memo + ((index = DECODER[char]) ? ENCODER[index] : unknown)
  end
  format_code(string, **kwargs)
end
valid?(string) click to toggle source
# File lib/crockford.rb, line 51
def valid?(string)
  !decode_number(string).nil?
end

Private Class Methods

clean_code(string) click to toggle source
# File lib/crockford.rb, line 61
def clean_code(string)
  string.delete("-").upcase
end
format_code(string, length: nil, split: false) click to toggle source
# File lib/crockford.rb, line 65
def format_code(string, length: nil, split: false)
  string = string.rjust(length, "0") if length

  if split
    string = string
      .each_char
      .reverse_each
      .each_slice(split)
      .map { |segment| segment.reverse.join }
      .reverse
      .join("-")
  end

  string
end