Class: CsvMapper::RowMap
Overview
CsvMapper::RowMap provides a simple, DSL-like interface for constructing mappings. A CsvMapper::RowMap provides the main functionality of the library. It will mostly be used indirectly through the CsvMapper API, but may be useful to use directly for the dynamic CSV mappings.
Constant Summary collapse
- Infinity =
1.0/0
Instance Attribute Summary collapse
-
#mapped_attributes ⇒ Object
readonly
Returns the value of attribute mapped_attributes.
Instance Method Summary collapse
-
#_SKIP_ ⇒ Object
Convenience method to ‘move’ the cursor skipping the current index.
-
#add_attribute(name, index = nil) ⇒ Object
Add a new attribute to this map.
-
#after_row(*afters) ⇒ Object
Declare method name symbols and/or lambdas to be executed before each row.
-
#before_row(*befores) ⇒ Object
Declare method name symbols and/or lambdas to be executed before each row.
-
#cursor ⇒ Object
The current cursor location.
-
#delimited_by(delimiter = nil) ⇒ Object
Specify the CSV column delimiter.
-
#initialize(context, csv_data = nil, &map_block) ⇒ RowMap
constructor
Create a new instance with access to an evaluation context.
-
#map_to(klass, defaults = {}) ⇒ Object
Each row of a CSV is parsed and mapped to a new instance of a Ruby class; Struct by default.
-
#move_cursor(positions = 1) ⇒ Object
Move the cursor relative to it’s current position.
-
#parse(csv_row) ⇒ Object
Given a CSV row return an instance of an object defined by this mapping.
-
#parser_options(opts = nil) ⇒ Object
Specify a hash of FasterCSV options to be used for CSV parsing.
-
#read_attributes_from_file(aliases = {}) ⇒ Object
Allow us to read the first line of a csv file to automatically generate the attribute names.
-
#start_at_row(row_number = nil) ⇒ Object
Declare what row to begin parsing the CSV.
-
#stop_at_row(row_number = nil) ⇒ Object
Declare the last row to be parsed in a CSV.
Constructor Details
#initialize(context, csv_data = nil, &map_block) ⇒ RowMap
Create a new instance with access to an evaluation context
15 16 17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/csv-mapper/row_map.rb', line 15 def initialize(context, csv_data = nil, &map_block) @context = context @csv_data = csv_data @before_filters = [] @after_filters = [] @parser_options = {} @start_at_row = 0 @stop_at_row = Infinity @delimited_by = FasterCSV::DEFAULT_OPTIONS[:col_sep] @mapped_attributes = [] self.instance_eval(&map_block) if block_given? end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args) ⇒ Object (protected)
The Hacktastic “magic” Used to dynamically create CsvMapper::AttributeMaps based on unknown method calls that should represent the names of mapped attributes.
An optional first argument is used to move this maps cursor position and as the index of the new AttributeMap
148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/csv-mapper/row_map.rb', line 148 def method_missing(name, *args) # :nodoc: if index = args[0] self.move_cursor(index - self.cursor) else index = self.cursor self.move_cursor end add_attribute(name, index) end |
Instance Attribute Details
#mapped_attributes ⇒ Object (readonly)
Returns the value of attribute mapped_attributes.
12 13 14 |
# File 'lib/csv-mapper/row_map.rb', line 12 def mapped_attributes @mapped_attributes end |
Instance Method Details
#_SKIP_ ⇒ Object
Convenience method to ‘move’ the cursor skipping the current index.
71 72 73 |
# File 'lib/csv-mapper/row_map.rb', line 71 def _SKIP_ self.move_cursor end |
#add_attribute(name, index = nil) ⇒ Object
Add a new attribute to this map. Mostly used internally, but is useful for dynamic map creation. returns the newly created CsvMapper::AttributeMap
110 111 112 113 114 |
# File 'lib/csv-mapper/row_map.rb', line 110 def add_attribute(name, index=nil) attr_mapping = CsvMapper::AttributeMap.new(name.to_sym, index, @context) self.mapped_attributes << attr_mapping attr_mapping end |
#after_row(*afters) ⇒ Object
Declare method name symbols and/or lambdas to be executed before each row. Each method or lambda must accept to parameters: csv_row
, target_object
Methods names should refer to methods available within the RowMap’s provided context
104 105 106 |
# File 'lib/csv-mapper/row_map.rb', line 104 def after_row(*afters) self.add_filters(@after_filters, *afters) end |
#before_row(*befores) ⇒ Object
Declare method name symbols and/or lambdas to be executed before each row. Each method or lambda must accept to parameters: csv_row
, target_object
Methods names should refer to methods available within the RowMap’s provided context
97 98 99 |
# File 'lib/csv-mapper/row_map.rb', line 97 def before_row(*befores) self.add_filters(@before_filters, *befores) end |
#cursor ⇒ Object
The current cursor location
117 118 119 |
# File 'lib/csv-mapper/row_map.rb', line 117 def cursor # :nodoc: @cursor ||= 0 end |
#delimited_by(delimiter = nil) ⇒ Object
Specify the CSV column delimiter. Defaults to comma.
76 77 78 79 |
# File 'lib/csv-mapper/row_map.rb', line 76 def delimited_by(delimiter=nil) @delimited_by = delimiter if delimiter @delimited_by end |
#map_to(klass, defaults = {}) ⇒ Object
Each row of a CSV is parsed and mapped to a new instance of a Ruby class; Struct by default. Use this method to change the what class each row is mapped to.
The given class must respond to a parameter-less #new and all attribute mappings defined. Providing a hash of defaults will ensure that each resulting object will have the providing name and attribute values unless overridden by a mapping
34 35 36 37 38 39 40 |
# File 'lib/csv-mapper/row_map.rb', line 34 def map_to(klass, defaults={}) @map_to_klass = klass defaults.each do |name, value| self.add_attribute(name, -99).map lambda{|row, index| value} end end |
#move_cursor(positions = 1) ⇒ Object
Move the cursor relative to it’s current position
122 123 124 |
# File 'lib/csv-mapper/row_map.rb', line 122 def move_cursor(positions=1) # :nodoc: self.cursor += positions end |
#parse(csv_row) ⇒ Object
Given a CSV row return an instance of an object defined by this mapping
127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/csv-mapper/row_map.rb', line 127 def parse(csv_row) target = self.map_to_class.new @before_filters.each {|filter| filter.call(csv_row, target) } self.mapped_attributes.each do |attr_map| target.send("#{attr_map.name}=", attr_map.parse(csv_row)) end @after_filters.each {|filter| filter.call(csv_row, target) } return target end |
#parser_options(opts = nil) ⇒ Object
Specify a hash of FasterCSV options to be used for CSV parsing
Can be anything FasterCSV::new() accepts
65 66 67 68 |
# File 'lib/csv-mapper/row_map.rb', line 65 def (opts=nil) @parser_options = opts if opts @parser_options.merge :col_sep => @delimited_by end |
#read_attributes_from_file(aliases = {}) ⇒ Object
Allow us to read the first line of a csv file to automatically generate the attribute names. Spaces are replaced with underscores and non-word characters are removed.
Keep in mind that there is potential for overlap in using this (i.e. you have a field named files+ and one named files- and they both get named ‘files’).
You can specify aliases to rename fields to prevent conflicts and/or improve readability and compatibility.
i.e. read_attributes_from_file(‘files+’ => ‘files_plus’, ‘files-’ => ‘files_minus)
51 52 53 54 55 56 57 58 59 60 |
# File 'lib/csv-mapper/row_map.rb', line 51 def read_attributes_from_file aliases = {} attributes = FasterCSV.new(@csv_data, @parser_options).readline @start_at_row = [ @start_at_row, 1 ].max @csv_data.rewind attributes.each_with_index do |name, index| name.strip! use_name = aliases[name] || name.gsub(/\s+/, '_').gsub(/[\W]+/, '').downcase add_attribute use_name, index end end |
#start_at_row(row_number = nil) ⇒ Object
Declare what row to begin parsing the CSV. This is useful for skipping headers and such.
83 84 85 86 |
# File 'lib/csv-mapper/row_map.rb', line 83 def start_at_row(row_number=nil) @start_at_row = row_number if row_number @start_at_row end |
#stop_at_row(row_number = nil) ⇒ Object
Declare the last row to be parsed in a CSV.
89 90 91 92 |
# File 'lib/csv-mapper/row_map.rb', line 89 def stop_at_row(row_number=nil) @stop_at_row = row_number if row_number @stop_at_row end |