jpmckinney/copy_paste_pdf

View on GitHub
lib/copy_paste_pdf/table.rb

Summary

Maintainability
A
3 hrs
Test Coverage
module CopyPastePDF
  class Table < Array
    # Removes all empty rows from the table.
    def remove_empty_rows!
      reject! do |row|
        row.all?(&:nil?)
      end
    end

    # Copies the values of the given cells from a line to any following lines
    # whose corresponding cells are empty.
    #
    # @param [Array] indices the cell indices to copy
    # @yieldparam [Array] row a row in the table
    # @yieldreturn [Boolean] whether to skip the row from the table
    # @raise [CopyPastePDF::MissingSourceError] if a destination has no source
    # @raise [CopyPastePDF::CopyToNonEmptyCellError] if a destination cell
    #   already has a value
    # @raise [CopyPastePDF::InvalidRowError] if a row is neither a source nor a
    #   destination
    def copy_into_cell_below(*indices)
      source = nil
      each do |row|
        if !block_given? || !yield(row)
          values = row.values_at(*indices)
          case values.count(&:nil?)
          when 0
            source = values
          when indices.size
            if source
              indices.each_with_index do |index,i|
                if row[index]
                  raise CopyToNonEmptyCellError, "destination cell #{index} already has a value #{row[index]}"
                else
                  row[index] = source[i]
                end
              end
            else
              raise MissingSourceError, "#{row} is a destination, but it has no source"
            end
          else
            raise InvalidRowError, "#{row} is neither a source nor a destination"
          end
        end
      end
    end

    # Merges the values of the given cells from a line, whose other cells are 
    # empty, into the corresponding cells of the prececeding line.
    #
    # @param [Array] indices the cell indices to merge
    # @raise [CopyPastePDF::MergeWithEmptyCellError] if a destination cell is empty
    def merge_into_cell_above(*indices)
      each_with_index.reverse_each do |row,i|
        if row.each_with_index.all?{|value,j| value.nil? || indices.include?(j)}
          indices.each do |index|
            if self[i - 1][index]
              self[i - 1][index] = "#{self[i - 1][index]}\n#{row[index]}"
            else
              raise MergeWithEmptyCellError, "cell #{index} is empty and can't be merged"
            end
          end
          delete_at(i)
        end
      end
    end
  end
end