Follow the Brass

lib/progressive_press.rb

70 lines · ruby

Project files
# frozen_string_literal: true

require_relative "placement"
require_relative "press_results"

class ProgressivePress
  def initialize(stations:)
    @stations = stations.dup.freeze
    @plate = Array.new(@stations.length)
    @completed = []
  end

  def feed(work)
    return Placement.new(item: work, reason: :position_occupied) if @plate[0]

    @plate[0] = work
    Placement.new(item: work, reason: nil)
  end

  def cycle
    outcomes = stroke
    return CycleResult.new(advanced: false, outcomes: outcomes, ejected: nil) if faulted?(outcomes)

    CycleResult.new(advanced: true, outcomes: outcomes, ejected: advance)
  end

  def positions
    @stations.zip(@plate).map { |station, work| PositionSnapshot.new(station:, work:) }.freeze
  end

  def completed
    @completed.dup.freeze
  end

  def empty?
    @plate.compact.empty?
  end

  private

  def stroke
    @stations.each_with_index.map { |station, index| strike(station, index) }
  end

  def strike(station, index)
    work = @plate[index]
    return PositionOutcome.new(station: station.name, status: :empty, fault: nil) unless work

    record_strike(index, station.apply(work))
  end

  def record_strike(index, result)
    name = @stations[index].name
    return PositionOutcome.new(station: name, status: :faulted, fault: result.fault) if result.fault

    @plate[index] = result.work
    PositionOutcome.new(station: name, status: :completed, fault: nil)
  end

  def faulted?(outcomes)
    outcomes.any? { |outcome| outcome.status == :faulted }
  end

  def advance
    ejected = @plate.last
    @plate = [nil, *@plate[0..-2]]
    @completed << ejected if ejected
    ejected
  end
end

Read along in the manual: The Reloading Lab · Download the project (zip)