# class CSV::Row

A CSV::Row is part Array and part Hash. It retains an order for the fields and allows duplicates just as an Array would, but also allows you to access fields by name just as you could if they were in a Hash.

All rows returned by CSV will be constructed from this class, if header row processing is activated.

### Attributes

row[R]

Internal data format used to compare equality.

### Public Class Methods

new(headers, fields, header_row = false) click to toggle source

Construct a new CSV::Row from `headers` and `fields`, which are expected to be Arrays. If one Array is shorter than the other, it will be padded with `nil` objects.

The optional `header_row` parameter can be set to `true` to indicate, via #header_row? and #field_row?, that this is a header row. Otherwise, the row is assumes to be a field row.

A CSV::Row object supports the following Array methods through delegation:

- empty?()

- length()

- size()

    # File lib/csv.rb, line 235
    def initialize(headers, fields, header_row = false)
      @header_row = header_row
      headers.each { |h| h.freeze if h.is_a? String }

      # handle extra headers or fields
      @row = if headers.size >= fields.size
        headers.zip(fields)
      else
        fields.zip(headers).each(&:reverse!)
      end
    end

### Public Instance Methods

<<( field ) click to toggle source
<<( header_and_field_array )
<<( header_and_field_hash )

If a two-element Array is provided, it is assumed to be a header and field and the pair is appended. A Hash works the same way with the key being the header and the value being the field. Anything else is assumed to be a lone field which is appended with a `nil` header.

This method returns the row for chaining.

    # File lib/csv.rb, line 380
    def <<(arg)
      if arg.is_a?(Array) and arg.size == 2  # appending a header and name
        @row << arg
      elsif arg.is_a?(Hash)                  # append header and name pairs
        arg.each { |pair| @row << pair }
      else                                   # append field value
        @row << [nil, arg]
      end

      self  # for chaining
    end

==(other) click to toggle source

Returns `true` if this row contains the same headers and fields in the same order as `other`.

    # File lib/csv.rb, line 525
    def ==(other)
      return @row == other.row if other.is_a? CSV::Row
      @row == other
    end

[](header_or_index, minimum_index = 0)
Alias for: field
[]=( header, value ) click to toggle source
[]=( header, offset, value )
[]=( index, value )

Looks up the field by the semantics described in #field and assigns the `value`.

Assigning past the end of the row with an index will set all pairs between to `[nil, nil]`. Assigning to an unused header appends the new pair.

    # File lib/csv.rb, line 347
    def []=(*args)
      value = args.pop

      if args.first.is_a? Integer
        if @row[args.first].nil?  # extending past the end with index
          @row[args.first] = [nil, value]
          @row.map! { |pair| pair.nil? ? [nil, nil] : pair }
        else                      # normal index assignment
          @row[args.first][1] = value
        end
      else
        index = index(*args)
        if index.nil?             # appending a field
          self << [args.first, value]
        else                      # normal header assignment
          @row[index][1] = value
        end
      end
    end

delete( header ) click to toggle source
delete( header, offset )
delete( index )

Used to remove a pair from the row by `header` or `index`. The pair is located as described in #field. The deleted pair is returned, or `nil` if a pair could not be found.

    # File lib/csv.rb, line 415
    def delete(header_or_index, minimum_index = 0)
      if header_or_index.is_a? Integer                 # by index
        @row.delete_at(header_or_index)
      elsif i = index(header_or_index, minimum_index)  # by header
        @row.delete_at(i)
      else
        [ ]
      end
    end

delete_if(&block) click to toggle source

The provided `block` is passed a header and field for each pair in the row and expected to return `true` or `false`, depending on whether the pair should be deleted.

This method returns the row for chaining.

If no block is given, an Enumerator is returned.

    # File lib/csv.rb, line 434
    def delete_if(&block)
      block or return enum_for(__method__) { size }

      @row.delete_if(&block)

      self  # for chaining
    end

each(&block) click to toggle source

Yields each pair of the row as header and field tuples (much like iterating over a Hash). This method returns the row for chaining.

If no block is given, an Enumerator is returned.

Support for Enumerable.

    # File lib/csv.rb, line 513
    def each(&block)
      block or return enum_for(__method__) { size }

      @row.each(&block)

      self  # for chaining
    end

fetch( header ) click to toggle source
fetch( header ) { |row| ... }
fetch( header, default )

This method will fetch the field value by `header`. It has the same behavior as Hash#fetch: if there is a field with the given `header`, its value is returned. Otherwise, if a block is given, it is yielded the `header` and its result is returned; if a `default` is given as the second argument, it is returned; otherwise a KeyError is raised.

    # File lib/csv.rb, line 310
    def fetch(header, *varargs)
      raise ArgumentError, "Too many arguments" if varargs.length > 1
      pair = @row.assoc(header)
      if pair
        pair.last
      else
        if block_given?
          yield header
        elsif varargs.empty?
          raise KeyError, "key not found: #{header}"
        else
          varargs.first
        end
      end
    end

field( header ) click to toggle source
field( header, offset )
field( index )

This method will return the field value by `header` or `index`. If a field is not found, `nil` is returned.

When provided, `offset` ensures that a header match occurs on or later than the `offset` index. You can use this to find duplicate headers, without resorting to hard-coding exact indices.

    # File lib/csv.rb, line 284
    def field(header_or_index, minimum_index = 0)
      # locate the pair
      finder = (header_or_index.is_a?(Integer) || header_or_index.is_a?(Range)) ? :[] : :assoc
      pair   = @row[minimum_index..-1].send(finder, header_or_index)

      # return the field if we have a pair
      if pair.nil?
        nil
      else
        header_or_index.is_a?(Range) ? pair.map(&:last) : pair.last
      end
    end

Also aliased as: []
field?(data) click to toggle source

Returns `true` if `data` matches a field in this row, and `false` otherwise.

    # File lib/csv.rb, line 499
    def field?(data)
      fields.include? data
    end

field_row?() click to toggle source

Returns `true` if this is a field row.

    # File lib/csv.rb, line 262
    def field_row?
      not header_row?
    end

fields(*headers_and_or_indices) click to toggle source

This method accepts any number of arguments which can be headers, indices, Ranges of either, or two-element Arrays containing a header and offset. Each argument will be replaced with a field lookup as described in #field.

If called with no arguments, all fields are returned.

    # File lib/csv.rb, line 450
    def fields(*headers_and_or_indices)
      if headers_and_or_indices.empty?  # return all fields--no arguments
        @row.map(&:last)
      else                              # or work like values_at()
        all = []
        headers_and_or_indices.each do |h_or_i|
          if h_or_i.is_a? Range
            index_begin = h_or_i.begin.is_a?(Integer) ? h_or_i.begin :
                                                        index(h_or_i.begin)
            index_end   = h_or_i.end.is_a?(Integer)   ? h_or_i.end :
                                                        index(h_or_i.end)
            new_range   = h_or_i.exclude_end? ? (index_begin...index_end) :
                                                (index_begin..index_end)
            all.concat(fields.values_at(new_range))
          else
            all << field(*Array(h_or_i))
          end
        end
        return all
      end
    end

Also aliased as: values_at
has_key?(header) click to toggle source

Returns `true` if there is a field with the given `header`.

    # File lib/csv.rb, line 327
    def has_key?(header)
      !!@row.assoc(header)
    end

Also aliased as: include?, key?, member?
header?(name) click to toggle source

Returns `true` if `name` is a header for this row, and `false` otherwise.

    # File lib/csv.rb, line 490
    def header?(name)
      headers.include? name
    end

Also aliased as: include?
header_row?() click to toggle source

Returns `true` if this is a header row.

    # File lib/csv.rb, line 257
    def header_row?
      @header_row
    end

headers() click to toggle source

Returns the headers of this row.

    # File lib/csv.rb, line 267
    def headers
      @row.map(&:first)
    end

include?(header)
Alias for: has_key?
index( header ) click to toggle source
index( header, offset )

This method will return the index of a field with the provided `header`. The `offset` can be used to locate duplicate header names, as described in #field.

    # File lib/csv.rb, line 482
    def index(header, minimum_index = 0)
      # find the pair
      index = headers[minimum_index..-1].index(header)
      # return the index at the right offset, if we found one
      index.nil? ? nil : index + minimum_index
    end

inspect() click to toggle source

A summary of fields, by header, in an ASCII compatible String.

    # File lib/csv.rb, line 549
    def inspect
      str = ["#<", self.class.to_s]
      each do |header, field|
        str << " " << (header.is_a?(Symbol) ? header.to_s : header.inspect) <<
               ":" << field.inspect
      end
      str << ">"
      begin
        str.join('')
      rescue  # any encoding error
        str.map do |s|
          e = Encoding::Converter.asciicompat_encoding(s.encoding)
          e ? s.encode(e) : s.force_encoding("ASCII-8BIT")
        end.join('')
      end
    end

key?(header)
Alias for: has_key?
member?(header)
Alias for: has_key?
push(*args) click to toggle source

A shortcut for appending multiple fields. Equivalent to:

    args.each { |arg| csv_row << arg }

This method returns the row for chaining.

    # File lib/csv.rb, line 399
    def push(*args)
      args.each { |arg| self << arg }

      self  # for chaining
    end

to_csv(**options) click to toggle source

Returns the row as a CSV String. Headers are not used. Equivalent to:

    csv_row.fields.to_csv( options )

    # File lib/csv.rb, line 543
    def to_csv(**options)
      fields.to_csv(options)
    end

Also aliased as: to_s
to_hash() click to toggle source

Collapses the row into a simple Hash. Be warned that this discards field order and clobbers duplicate fields.

    # File lib/csv.rb, line 534
    def to_hash
      @row.to_h
    end

to_s(**options)
Alias for: to_csv
values_at(*headers_and_or_indices)
Alias for: fields