Module: RotorMachine::Factory

Extended by:
Factory
Included in:
Factory
Defined in:
lib/rotor_machine/factory.rb

Overview

The Factory provides Factory-pattern helpers to build various parts of the RotorMachine - rotors, reflectors, plugboards, and fully-configured machines.

Instance Method Summary collapse

Instance Method Details

#build_machine(options = {}) ⇒ Object Also known as: make_machine

Build a Machine and return it.

The options hash can provide the following options:

  • :rotors - An array of Rotor objects. This can be constructed manually, or through multiple calls to #build_rotor. Alternatively, you can pass an array of symbols which match the constants in the Rotor class, and Rotor objects will be built from those (using default position and step sizes).

  • :reflector - A Reflector object. Alternatively, a symbol matching one of the reflector type constants can be passed in, and a Reflector of the specified type will be created.j

  • :connections - A Hash of connections to make on the new Machine‘s Plugboard.

Parameters:

  • options (defaults to: {})

    The options for the newly built Machine.

Returns:



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/rotor_machine/factory.rb', line 191

def build_machine(options={})
  rotors    = options.fetch(:rotors,        [])
  reflector = options.fetch(:reflector,     nil)
  connections = options.fetch(:connections, {})

  m = RotorMachine::Machine.new()
  rotors.each do |r|
    if r.is_a? RotorMachine::Rotor
      m.rotors << r
    elsif r.is_a? Symbol
      m.rotors << RotorMachine::Factory.build_rotor(rotor_kind: r)
    else
      raise ArgumentError, "#{r} is not a rotor or a rotor kind symbol"
    end
  end

  unless reflector.nil?
    if reflector.is_a? Symbol
      m.reflector = RotorMachine::Factory.build_reflector(reflector_kind: reflector)
    elsif reflector.is_a? RotorMachine::Reflector
      m.reflector = reflector
    else
      raise ArgumentError, "#{reflector} is not a reflector or reflector kind symbol"
    end
  end

  m.plugboard = build_plugboard()
  unless connections.empty?
    connections.each { |from, to| m.plugboard.connect(from, to) }
  end

  return m
end

#build_plugboard(options = {}) ⇒ Object Also known as: make_plugboard

Build a new Plugboard object and return it.

Returns:

  • The newly built plugboard.



166
167
168
# File 'lib/rotor_machine/factory.rb', line 166

def build_plugboard(options={})
  return RotorMachine::Plugboard.new()
end

#build_reflector(options = {}) ⇒ Object Also known as: make_reflector

Build a new Reflector and return it.

The options hash for this method can accept the following named arguments:

:reflector_kind - The type of reflector to create. Should be a symbol matching a reflector type constant in the Reflector class, or a 26-character string giving the letter sequence for the reflector. Defaults to :REFLECTOR_A if not specified.

:initial_position - The initial position of the reflector (0-based numeric position, or a letter on the rotor.) Defaults to 0 if not specified.

reflector.

Parameters:

  • options (Hash) (defaults to: {})

    The options hash containing the options for the

Returns:

  • The newly-built reflector.



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/rotor_machine/factory.rb', line 124

def build_reflector(options={})
  reflector_kind     = options.fetch(:reflector_kind, nil)
  initial_position   = options.fetch(:initial_position, nil)

  reflector_alphabet = nil
  if reflector_kind.nil?
    raise ArgumentError, "Reflector type not specified"
  end
  if initial_position.nil?
    initial_position = 0
  end

  if reflector_kind.is_a? Symbol
    unless RotorMachine::Reflector.constants.include?(reflector_kind)
      raise ArgumentError, "Invalid reflector kind (symbol #{reflector_kind} not found)"
    end
    reflector_alphabet = RotorMachine::Reflector.const_get(reflector_kind)
  elsif reflector_kind.is_a? String
    raise ArgumentError, "Invalid reflector kind (invalid length)" unless reflector_kind.length == 26
    reflector_alphabet = reflector_kind.upcase
  else
    raise ArgumentError, "Invalid reflector kind (invalid type)"
  end

  if initial_position.is_a? Numeric
    raise ArgumentError, "Invalid position (#{initial_position} out of range)" unless ((0..25).include?(initial_position))
  elsif initial_position.is_a? String
    unless RotorMachine::Reflector::ALPHABET.include?(initial_position)
      raise ArgumentError, "Invalid position (invalid letter '#{initial_position}')"
    end
    initial_position = reflector_alphabet.index(initial_position)
  else
    raise ArgumentError, "Invalid position (invalid type)"
  end

  return RotorMachine::Reflector.new(reflector_alphabet, initial_position)
end

#build_rotor(options = {}) ⇒ Object Also known as: make_rotor

Build a new Rotor and return it.

The options hash for this method can accept the following named arguments:

:rotor_kind - The type of rotor to create. Should be a symbol matching a rotor type constant in the Rotor class, or a 26-character string giving the letter sequence for the rotor. Defaults to :ROTOR_1 if not specified.

:initial_position - The initial position of the rotor (0-based numeric position, or a letter on the rotor.) Defaults to 0 if not specified.

:step_size - How many positions the rotor should advance with each step. Defaults to 1 if not specified.

Parameters:

  • options (Hash) (defaults to: {})

    The options hash containing the options for the rotor.

Returns:

  • The newly-built rotor.



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/rotor_machine/factory.rb', line 67

def build_rotor(options={})
  rotor_kind         = options.fetch(:rotor_kind, nil)
  initial_position   = options.fetch(:initial_position,   0)
  step_size          = options.fetch(:step_size,          1)

  rotor_alphabet = nil
  if rotor_kind.nil?
    raise ArgumentError, "Rotor kind not specified"
  end

  if rotor_kind.is_a? Symbol
    raise ArgumentError, "Invalid rotor kind (symbol #{rotor_kind} not found)" unless RotorMachine::Rotor.constants.include?(rotor_kind)
    rotor_alphabet = RotorMachine::Rotor.const_get(rotor_kind)
  elsif rotor_kind.is_a? String
    raise ArgumentError, "Invalid rotor kind (invalid length)" unless rotor_kind.length == 26
    rotor_alphabet = rotor_kind.upcase
  else
    raise ArgumentError, "Invalid rotor kind (invalid type #{rotor_kind.class.name})"
  end

  if initial_position.is_a? Numeric
    raise ArgumentError, "Invalid position (#{initial_position} out of range)" unless ((0..25).include?(initial_position))
  elsif initial_position.is_a? String
    unless RotorMachine::Rotor::ALPHABET.include?(initial_position)
      raise ArgumentError, "Invalid position (invalid letter '#{initial_position}')"
    end
  else
    raise ArgumentError, "Invalid position (invalid type #{initial_position.class.name})"
  end

  if  step_size.is_a? Numeric
    raise ArgumentError, "Invalid step size (#{step_size} out of range)" unless ((1..25).include?(step_size))
  else
    raise ArgumentError, "Invalid step size (invalid type #{step_size.class.name})"
  end

  return RotorMachine::Rotor.new(rotor_alphabet, initial_position, step_size)
end

#default_machineObject

Generates a default-configuration RotorMachine, with the following state:

  • Rotors I, II, III, each set to A and configured to advance a single step at a time

  • Reflector A

  • An empty plugboard with no connections

The Machine#default_machine method calls this factory method, and is maintained there for backward compatibility.



20
21
22
23
24
25
26
27
# File 'lib/rotor_machine/factory.rb', line 20

def default_machine
  m = build_machine(
    rotors: [:ROTOR_I, :ROTOR_II, :ROTOR_III],
    reflector: build_reflector(reflector_kind: :REFLECTOR_A)
    )
  m.set_rotors("AAA")
  return m
end

#empty_machineObject

Generates an empty-configuration RotorMachine, with the following state:

  • No rotors

  • No reflector

  • An empty plugboard with no connections

A RotorMachine in this state will raise an ArgumentError until you outfit it with at least one rotor and a reflector.

The Machine#default_machine method calls this factory method, and is maintained there for backward compatibility.



42
43
44
# File 'lib/rotor_machine/factory.rb', line 42

def empty_machine
  return build_machine()
end