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; OpenStruct 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
125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/csv-mapper.rb', line 125 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
259 260 261 262 263 264 265 266 267 268 269 |
# File 'lib/csv-mapper.rb', line 259 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.
122 123 124 |
# File 'lib/csv-mapper.rb', line 122 def mapped_attributes @mapped_attributes end |
Instance Method Details
#_SKIP_ ⇒ Object
Convenience method to ‘move’ the cursor skipping the current index.
181 182 183 |
# File 'lib/csv-mapper.rb', line 181 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
220 221 222 223 224 |
# File 'lib/csv-mapper.rb', line 220 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
214 215 216 |
# File 'lib/csv-mapper.rb', line 214 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
207 208 209 |
# File 'lib/csv-mapper.rb', line 207 def before_row(*befores) self.add_filters(@before_filters, *befores) end |
#cursor ⇒ Object
The current cursor location
227 228 229 |
# File 'lib/csv-mapper.rb', line 227 def cursor # :nodoc: @cursor ||= 0 end |
#delimited_by(delimiter = nil) ⇒ Object
Specify the CSV column delimiter. Defaults to comma.
186 187 188 189 |
# File 'lib/csv-mapper.rb', line 186 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; OpenStruct 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
144 145 146 147 148 149 150 |
# File 'lib/csv-mapper.rb', line 144 def map_to(klass, defaults={}) @map_to_klass = klass defaults.each do |name, value| self.add_attribute(name, -99).map lambda{|row| value} end end |
#move_cursor(positions = 1) ⇒ Object
Move the cursor relative to it’s current position
232 233 234 |
# File 'lib/csv-mapper.rb', line 232 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
237 238 239 240 241 242 243 244 245 246 247 248 249 |
# File 'lib/csv-mapper.rb', line 237 def parse(csv_row) target = self.map_to_class.new @before_filters.each {|filter| filter.call(csv_row, target) } self.mapped_attributes.inject(target) do |result, attr_map| result.send("#{attr_map.name}=".to_sym, attr_map.parse(csv_row)) result 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
175 176 177 178 |
# File 'lib/csv-mapper.rb', line 175 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)
161 162 163 164 165 166 167 168 169 170 |
# File 'lib/csv-mapper.rb', line 161 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.
193 194 195 196 |
# File 'lib/csv-mapper.rb', line 193 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.
199 200 201 202 |
# File 'lib/csv-mapper.rb', line 199 def stop_at_row(row_number=nil) @stop_at_row = row_number if row_number @stop_at_row end |