class FixedLengthEncoder::Encoder

Public Class Methods

new(alphabet, encode_map, decode_map) click to toggle source
# File lib/fixed_length_encoder.rb, line 34
def initialize(alphabet, encode_map, decode_map)
  @alphabet = alphabet
  @base = alphabet.length
  @encode_map = encode_map
  @decode_map = decode_map
end

Public Instance Methods

array_to_integer(message) click to toggle source
# File lib/fixed_length_encoder.rb, line 106
def array_to_integer(message)
  value = 0
  message.reverse.each { |digit| value = (value * @base) + digit }
  value
end
decode(message) click to toggle source
# File lib/fixed_length_encoder.rb, line 56
def decode(message)
  raise ArgumentError, 'Cannot decode a non-string.' unless message.is_a?(String)
  self.setup(message.length)
  value = self.string_to_integer(message)
  value = self.scramble_value(value, -1)
  self.offset(value, -1)
end
encode(value, message_length) click to toggle source
# File lib/fixed_length_encoder.rb, line 46
def encode(value, message_length)
  raise ArgumentError, 'Cannot encode a non-integer' unless value.is_a?(Integer)
  raise ArgumentError, 'Cannot encode negative values' if value < 0
  self.setup(message_length)
  raise ArgumentError, "Cannot encode #{value} in #{@message_length} characters" if value >= @max_value
  value = self.offset(value, +1)
  value = self.scramble_value(value, +1)
  string = self.integer_to_string(value)
end
integer_to_array(value) click to toggle source
# File lib/fixed_length_encoder.rb, line 96
def integer_to_array(value)
  message = []
  while (value > 0 || message.length < @message_length)
    remainder = value % @base
    message.push remainder
    value /= @base
  end
  message
end
integer_to_string(value) click to toggle source
# File lib/fixed_length_encoder.rb, line 90
def integer_to_string(value)
  message = integer_to_array(value)
  message = message.map { |value| @alphabet[value] }
  message.join
end
map_array(message, map, direction) click to toggle source
# File lib/fixed_length_encoder.rb, line 76
def map_array(message, map, direction)
  indexes = (0..@message_length).to_a.map { |i| i % @message_length }
  indexes = indexes.reverse if direction < 0
  (0...@message_length).each do |index|
    low_index = indexes[index]
    high_index = indexes[index + 1]
    map_index = message[high_index] * @base + message[low_index]
    map_value = map[map_index]
    message[low_index] = map_value / @base
    message[high_index] = map_value % @base
  end
  message
end
offset(value, direction) click to toggle source
# File lib/fixed_length_encoder.rb, line 64
def offset(value, direction)
  offset = (@max_value/2).floor
  (value + direction * offset) % @max_value
end
scramble_value(value, direction) click to toggle source
# File lib/fixed_length_encoder.rb, line 69
def scramble_value(value, direction)
  message = integer_to_array(value)
  message = map_array(message, @encode_map, direction) if direction > 0
  message = map_array(message, @decode_map, direction) if direction < 0
  array_to_integer(message)
end
setup(message_length) click to toggle source
# File lib/fixed_length_encoder.rb, line 41
def setup(message_length)
  @message_length = message_length
  @max_value = (@alphabet.length)**message_length
end
string_to_integer(message) click to toggle source
# File lib/fixed_length_encoder.rb, line 112
def string_to_integer(message)
  value = 0
  message.reverse.split('').map do |digit|
    index = @alphabet.index(digit)
    raise ArgumentError, 'Cannot decode an invalid character (' + digit + ')' if index.nil?
    value = (value * @base) + index
  end
  value
end