dvmonroe/box-office

View on GitHub
lib/box/office/showing.rb

Summary

Maintainability
A
2 hrs
Test Coverage
# frozen_string_literal: true

module Box
  module Office
    class Showing
      include Connection

      attr_accessor :track_fulfilled, :showings, :capacity
      attr_reader :name, :booth

      delegate :config, to: Box::Office

      def initialize(name: config.default_name, track_fulfilled: config.track_fulfilled,
                     showings: config.showings, capacity: config.capacity)
        @name              = name
        @track_fulfilled   = track_fulfilled
        @showings          = showings
        @capacity          = capacity

        @booth             = Booth.new(showing: self)

        setup_reserved_queues
      end

      Box::Office.config.single_queues.each do |que|
        define_method que do
          Queue.new send("#{que}_key")
        end
      end

      def fulfill(queue, msg)
        send(config.fulfilled) << msg if track_fulfilled?
        queue >> msg
      end

      def push(*msg)
        with_connection { |conn| conn.lpush(send("#{config.standby}_key"), *msg) }
      end
      alias << push

      def reserve(capacity: self.capacity, block_unlock: true)
        with_connection do |conn|
          booth.first_available_opening(conn) do |opening|
            Janitor.lock(opening.name) if config.lock_reserved?
            conn.rpoplpush(send("#{config.standby}_key"), opening.name) while openings?(opening, capacity)

            if block_given?
              yield opening, opening.members(limit: capacity)
              Janitor.unlock(opening.name) if config.lock_reserved? && block_unlock
            end
          rescue
            Janitor.unlock(opening.name)
            raise
          end
        end
      end
      alias pop reserve

      private

      Box::Office.config.single_queues.each do |que|
        define_method "#{que}_key" do
          "box-office:#{name.parameterize}:#{que}"
        end
      end

      Box::Office.config.reserved.tap do |que|
        define_method "#{que}_key" do |idx|
          "box-office:#{name.parameterize}:#{que}-#{idx}"
        end
      end

      def openings?(queue, capacity)
        queue.length < capacity && !send(config.standby).empty?
      end

      def setup_reserved_queues
        Box::Office.config.reserved.tap do |que|
          define_singleton_method que do |idx = 1|
            raise OutOfRange, "#{idx} is out of range of available showings" unless (1..showings).to_a.include? idx

            Queue.new send("#{que}_key", idx)
          end
        end
      end
    end
  end
end