lib/axiom/relation/operation/offset.rb

Summary

Maintainability
A
0 mins
Test Coverage
# encoding: utf-8

module Axiom
  class Relation
    module Operation

      # A class representing an offset relation
      class Offset < Relation
        include Unary
        include Equalizer.new(:operand, :offset)

        # Return the offset
        #
        # @example
        #   offset = offset_relation.offset
        #
        # @return [Integer]
        #
        # @api public
        attr_reader :offset

        # The relation sort order
        #
        # @return [Operation::Sorted::DirectionSet]
        #
        # @api private
        attr_reader :directions

        # Instantiate a new Offset
        #
        # @example
        #   offset_relation = Offset.new(operand, offset)
        #
        # @param [Relation] operand
        #   the relation to offset
        # @param [Integer] offset
        #   the offset of the operand to drop
        #
        # @return [Offset]
        #
        # @api public
        def self.new(operand, offset)
          assert_sorted_operand(operand)
          assert_valid_offset(offset)
          super
        end

        # Assert the operand is sorted
        #
        # @param [Relation] operand
        #
        # @return [undefined]
        #
        # @raise [SortededRelationRequiredError]
        #   raised if the operand is unsorted
        #
        # @api private
        def self.assert_sorted_operand(operand)
          if operand.header.size != operand.directions.size
            fail SortededRelationRequiredError, 'can only offset a sorted operand'
          end
        end

        # Assert the offset is valid
        #
        # @param [Integer] offset
        #
        # @return [undefined]
        #
        # @raise [InvalidOffsetError]
        #   raised if the offset is less than 0
        #
        # @api private
        def self.assert_valid_offset(offset)
          if offset.nil? || offset < 0
            fail InvalidOffsetError, "offset must be greater than or equal to 0, but was #{offset.inspect}"
          end
        end

        private_class_method :assert_sorted_operand, :assert_valid_offset

        # Initialize an Offset
        #
        # @param [Relation] operand
        #   the relation to offset
        # @param [Integer] offset
        #   the offset of the operand to drop
        #
        # @return [undefined]
        #
        # @api private
        def initialize(operand, offset)
          super(operand)
          @offset     = offset
          @directions = operand.directions
        end

        # Iterate over each tuple in the set
        #
        # @example
        #   offset_relation = Offset.new(operand, offset)
        #   offset_relation.each { |tuple| ... }
        #
        # @yield [tuple]
        #
        # @yieldparam [Tuple] tuple
        #   each tuple in the set
        #
        # @return [self]
        #
        # @api public
        def each
          return to_enum unless block_given?
          operand.each_with_index do |tuple, index|
            yield tuple if index >= @offset
          end
          self
        end

        # Raise an exception when inserting into the Offset
        #
        # @example
        #   offset.insert(other)  # => ImmutableRelationError raised
        #
        # @return [undefined]
        #
        # @raise [ImmutableRelationError]
        #   raised when inserting into the offset
        #
        # @api public
        def insert(*)
          fail ImmutableRelationError, 'inserting into an offset is impossible'
        end

        # Raise an exception when deleting from the Offset
        #
        # @example
        #   offset.delete(other)  # => ImmutableRelationError raised
        #
        # @return [undefined]
        #
        # @raise [ImmutableRelationError]
        #   raised when deleting from the offset
        #
        # @api public
        def delete(*)
          fail ImmutableRelationError, 'deleting from an offset is impossible'
        end

        module Methods

          # Return a relation with n tuples
          #
          # @example
          #   offset_relation = relation.drop(5)
          #
          # @param [Integer] offset
          #   the offset of the relation to drop
          #
          # @return [Offset]
          #
          # @api public
          def drop(offset)
            Offset.new(self, offset)
          end

        end # module Methods

        Relation.class_eval { include Methods }

      end # class Offset
    end # module Operation
  end # class Relation
end # module Axiom