Module: CsvMapper

Extended by:
CsvMapper
Included in:
CsvMapper
Defined in:
lib/csv-mapper.rb,
lib/csv-mapper/row_map.rb,
lib/csv-mapper/attribute_map.rb

Overview

This module provides the main interface for importing CSV files & data to mapped Ruby objects.

Usage

Including CsvMapper will provide two methods:

  • import

  • map_csv

See csv-mapper.rb for method docs.

Import From File

results = import('/path/to/file.csv') do
  # declare mapping here
end

Import From String or IO

results = import(csv_data, :type => :io) do
  # declare mapping here
end

Mapping

Mappings are built inside blocks. All three of CsvMapper’s main API methods accept a block containing a mapping. Maps are defined by using map_to, start_at_row, before_row, and after_row (methods on CsvMapper::RowMap) and by defining your own mapping attributes. A mapping block uses an internal cursor to keep track of the order the mapping attributes are declared and use that order to know the corresponding CSV column index to associate with the attribute.

The Basics
  • map_to - Override the default Struct target. Accepts a class and an optional hash of default attribute names and values.

  • start_at_row - Specify what row to begin parsing at. Use this to skip headers.

  • before_row - Accepts an Array of method name symbols or lambdas to be invoked before parsing each row.

  • after_row - Accepts an Array of method name symbols or lambdas to be invoked after parsing each row.

  • delimited_by - Accepts a character to be used to delimit columns. Use this to specify pipe-delimited files.

  • _SKIP_ - Use as a placehold to skip a CSV column index.

  • parser_options - Accepts a hash of FasterCSV options. Can be anything FasterCSV::new() understands

Attribute Mappings

Attribute mappings are created by using the name of the attribute to be mapped to.

The order in which attribute mappings are declared determines the index of the corresponding CSV row.

All mappings begin at the 0th index of the CSV row.

foo  # maps the 0th CSV row position value to the value of the 'foo' attribute on the target object.
bar  # maps the 1st row position to 'bar'

This could also be a nice one liner for easy CSV format conversion

[foo, bar]  # creates the same attribute maps as above.

The mapping index may be specifically declared in two additional ways:

foo(2)     # maps the 2nd CSV row position value to 'foo' and moves the cursor to 3
bar        # maps the 3rd CSV row position to 'bar' due to the current cursor position
baz.at(0)  # maps the 0th CSV row position to 'baz' but only increments the cursor 1 position to 4

Each attribute mapping may be configured to parse the record using a lambda or a method name

foo.map lambda{|row| row[2].strip } # maps the 2nd row position value with leading and trailing whitespace removed to 'foo'.
bar.map :clean_bar  # maps the result of the clean_bar method to 'bar'. clean_bar must accept the row as a parameter.

Attribute mapping declarations and “modifiers” may be chained

foo.at(4).map :some_transform

Create Reusable Mappings

The import method accepts an instance of RowMap as an optional mapping parameter.

The easiest way to create an instance of a RowMap is by using map_csv.

a_row_map = map_csv do 
  # declare mapping here
end

Then you can reuse the mapping

results = import(some_string, :type => :io, :map => a_row_map)
other_results = import('/path/to/file.csv', :map => a_row_map)

Defined Under Namespace

Classes: AttributeMap, RowMap

Instance Method Summary collapse

Instance Method Details

#import(data, options = {}, &map_block) ⇒ Object

Load CSV data and map the values according to the definition in the given block. Accepts either a file path, String, or IO as data. Defaults to file path.

The following options may be used:

:type

defaults to :file_path. Use :io to specify data as String or IO.

:map

Specify an instance of a RowMap to take presidence over a given block defintion.



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/csv-mapper.rb', line 97

def import(data, options={}, &map_block)
  csv_data = options[:type] == :io ? data : File.new(data, 'r')

  config = { :type => :file_path,
             :map => map_csv_with_data(csv_data, &map_block) }.merge!(options)

  map = config[:map]
  
  results = []
  FasterCSV.new(csv_data, map.parser_options ).each_with_index do |row, i|
    results << map.parse(row) if i >= map.start_at_row && i <= map.stop_at_row
  end
  
  results
end

#map_csv(&map_block) ⇒ Object

Create a new RowMap instance from the definition in the given block.



86
87
88
# File 'lib/csv-mapper.rb', line 86

def map_csv(&map_block)
  CsvMapper::RowMap.new(self, &map_block)
end