Skip to Content Skip to Search

Builds rows keyed by new_columns out of rows keyed by old_columns.

When column_map is given, the new rows are laid out by the slot of each column in it, and columns it doesn’t have are given indexes after its last one (see ExtendedIndexes). Without one, every column is extra, so the new row is in the order of new_columns.

Methods
B
N

Class Public methods

new(initial_indexes, old_columns, new_columns = old_columns, column_map = EMPTY)

: (Hash[String, Integer] | ExtendedIndexes, Array, ?Array, ?(Hash[String, Integer] | ExtendedIndexes)) -> void

# File activemodel/lib/active_model/indexed_row.rb, line 211
def initialize(initial_indexes, old_columns, new_columns = old_columns, column_map = EMPTY)
  # Handle duplicate keys
  pairs = new_columns.zip(old_columns).to_h

  extra = nil
  last_slot = nil

  # [slot in the new row, index in the original row]
  slots = pairs.map do |new_column, old_column|
    unless slot = column_map[new_column]
      extra ||= {}
      last_slot ||= IndexedRow.max_slot(column_map)
      slot = extra[new_column] = (last_slot += 1)
    end

    [slot, initial_indexes.fetch(old_column)]
  end
  slots.sort_by!(&:first)

  @new_indexes = if extra.nil?
    column_map
  elsif column_map.empty?
    extra.freeze
  else
    ExtendedIndexes.new(column_map, extra.freeze)
  end

  # If the new row has no gaps, it can be built with a single
  # values_at. Otherwise fill in an unset row by position.
  if slots.each_with_index.all? { |(slot, _), i| slot == i }
    @indexes_to_extract = slots.map(&:last)
    @slots = nil
  else
    @slots = slots
    @width = slots.last.first + 1
  end
end

Instance Public methods

build(original_row)

# File activemodel/lib/active_model/indexed_row.rb, line 250
def build(original_row)
  values = original_row.row

  if @slots
    row = IndexedRow.unset_row(@width)
    @slots.each { |slot, index| row[slot] = values[index] }
  else
    row = values.values_at(*@indexes_to_extract)
  end

  IndexedRow.new(@new_indexes, row.freeze)
end