Class: FixedLengthEncoder::Encoder

Inherits:
Object
  • Object
show all
Defined in:
lib/fixed_length_encoder.rb

Instance Method Summary collapse

Constructor Details

#initialize(alphabet, encode_map, decode_map) ⇒ Encoder

Returns a new instance of Encoder.



34
35
36
37
38
39
# 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

Instance Method Details

#array_to_integer(message) ⇒ Object



106
107
108
109
110
# 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) ⇒ Object

Raises:

  • (ArgumentError)


56
57
58
59
60
61
62
# 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) ⇒ Object

Raises:

  • (ArgumentError)


46
47
48
49
50
51
52
53
54
# 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) ⇒ Object



96
97
98
99
100
101
102
103
104
# 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) ⇒ Object



90
91
92
93
94
# 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) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
88
# 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) ⇒ Object



64
65
66
67
# 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) ⇒ Object



69
70
71
72
73
74
# 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) ⇒ Object



41
42
43
44
# 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) ⇒ Object



112
113
114
115
116
117
118
119
120
# 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