Every repository with this icon (
Every repository with this icon (
tree 86422436fea10b5e2a507b461d68c9b1e774a151
parent 2f354677b1023cea9a2ce54402e9be06c88bf285
| name | age | message | |
|---|---|---|---|
| |
CHANGELOG.rdoc | ||
| |
LICENSE | ||
| |
README.rdoc | ||
| |
flexible_csv.gemspec | ||
| |
lib/ | ||
| |
test/ |
FlexibleCsv
Chris Powers, The Killswitch Collective (killswitchcollective.com/blog/authors/chris_powers)
The FlexibleCsv gem uses the FasterCSV gem to parse user created CSV files that may not have standard headers. For example, you know there’s an email address column somewhere in there, but it may be called "Email" or "Email Address" or "email-address", and it might be in the first column, but it might be in the third.
Examples
These CSV data snippets have the same data but are formatted much differently. Using FlexibleCsv to map possible column names to data nodes, these differences become negligible.
require 'flexible_csv'
# Arbitrary CSV data
csv_data1 = %Q{Full Name, Email Address\nJohn Doe, john@doe.com}
csv_data2 = %Q{Email, Name\njohn@doe.com, John Doe}
parser = FlexibleCsv.new do |csv|
csv.column :full_name, "Name", "Full Name", "Client Name"
csv.column :email, "Email", "Email Address"
end
parser.parse(csv_data1).each do |row|
puts row.full_name #=> 'John Doe'
puts row.email #=> 'john@doe.com'
end
parser.parse(csv_data2).each do |row|
puts row.full_name #=> 'John Doe'
puts row.email #=> 'john@doe.com'
end
Using Adapters
What if simply mapping header names to values is not enough? What if you need more translation logic? Instead of baking in complex rule functionality into FlexibleCsv, I am strongly suggesting users use their own adapter classes to wrap up this logic.
For example, let’s say that some of your CSV files have a column for each contact’s full name, but other have a separate column for first and last name:
require 'flexible_csv'
# Arbitrary CSV data
csv_data1 = %Q{Full Name\nJohn Doe}
csv_data2 = %Q{First Name, Last Name\nJohn,Doe}
parser = FlexibleCsv.new do |csv|
csv.column :full_name, "Name", "Full Name", "Client Name"
csv.column :first_name, "First Name", "First"
csv.column :last_name, "Last Name", "Last", "Surname"
end
class CsvAdapter
def initialize(row)
@row = row
end
def full_name
row.full_name || "#{row.first_name} #{row.last_name}"
end
def last_name
row.last_name || row.full_name.split(' ').last
end
def first_name
row.first_name || row.full_name.split(' ').first
end
def method_missing(method_name, *args)
row.send(method_name, *args)
end
end
parser.parse(csv_data1).each do |row|
ad_row = CsvAdapter.new(row)
puts ad_row.full_name #=> 'John Doe'
puts ad_row.first_name #=> 'John'
puts ad_row.last_name #=> 'Doe'
end
parser.parse(csv_data2).each do |row|
ad_row = CsvAdapter.new(row)
puts ad_row.full_name #=> 'John Doe'
puts ad_row.first_name #=> 'John'
puts ad_row.last_name #=> 'Doe'
end








