The purpose of gem parseline is to help the developers to load external CSV and fixed width files.

Installation

sudo gem sources --add http://gems.github.com
sudo gem install shairontoledo-parseline

or from rubyforge

sudo gem install parseline

How to Use

A single data mapper

With ActiveRecord

Using CSV

You can use the files delimited by a character or using regexp. To demonstrate its we’ll use a migration/table

class CreateProducts < ActiveRecord::Migration
 def self.up
   create_table :products do |t|
     t.integer :code
     t.string  :name
     t.boolean :in_stock
     t.date    :date
     t.float   :price
   end
 end

 def self.down
   drop_table :products
 end
end

and a given file called ‘data.csv’ with the content below.

1;PRODUT 1;Y;;11/21/2008;90.00
2;PRODUT 2;N;;11/22/2008;341.33
3;PRODUT 3;N;;11/01/2008;1.99
4;PRODUT 4;Y;;11/15/2008;34.98
5;PRODUT 5;N;;11/14/2008;130.44
6;PRODUT 6;Y;;11/05/2008;20.11

The descriptions of data layout are

product's code;name;if it is in stock;*reserved for future use*;date;price

As you can see we need format the column ‘in stock’ to boolean format and convert the date format from MM/DD/YYYY to YYYY-MM-DD. For every parse.field call, you receive the field to format using a lambda block.

so, take a look at the ActiveRecord definition using the module ParseLine::CSV

require 'parseline'

class Product < ActiveRecord::Base
  extend ParseLine::CSV
  csv_layout :delimiter => ";" do |parse|
    parse.field :code
    parse.field :name
    parse.ignore_field
    parse.field :in_stock, lambda {|s| s == 'Y' }
    parse.field :date ,    lambda {|d| d.gsub(/(\d{2})\/(\d{2})\/(\d{4})/,'\3-\1-\2') }
    parse.field :price
  end
end

Each column will be mapped into a field, except the column after :name that is being ignored.

Loading external file

There are two ways that load data, by line use method Product.load_line to return an instance of Product

data_file=File.readlines("data.csv")
@product=Product.load_line data_file.first
@product.save #data will go to database

or loading from file with all records returns an array of Products

@products=Product.load_lines "data.csv"

Using Fixed Width

To load data with Fixed Width we need do a extend the module ParseLine::FixedWidth. It uses the same class methods to load data, the load_line and load_lines. See the file Fixed Width

000001PRODUT  1       Y 11/21/2008000090.00
000002PRODUT  2       N 11/22/2008000341.33
000003PRODUT  3       N 11/01/2008000001.99
000004PRODUT  4       Y 11/15/2008000034.98
000005PRODUT  5       N 11/14/2008000130.44
000006PRODUT  6       Y 11/05/2008000020.11

let’s split those lines and define a model like

require 'parseline'

class Product < ActiveRecord::Base
  extend ParseLine::FixedWidth
  fixed_width_layout do |parse|
    parse.field :code , 0..5
    parse.field :name,  6..21
    parse.field :in_stock, 22..22, lambda {|s| s == 'Y' }
    parse.field :date , 24..33,    lambda {|d| d.gsub(/(\d{2})\/(\d{2})\/(\d{4})/,'\3-\1-\2') }
    parse.field :price, 34..42
  end
end

After that

@products=Product.load_lines "data.txt"

With whatever class

Using Fixed Width

require 'rubygems'
require 'parseline'

class Person

  attr_accessor :id
  attr_accessor :age

  extend ParseLine::FixedWidth

  fixed_width_layout do |parse|
    parse.field :id, 0..4
    parse.field :age, 5..6
  end
end

After that

@people=Person.load_lines "data.txt"

and

@people.each{|person| p "id=#{person.id} and age=#{person.age}" }

Remember to use the parse module It’s easy to do, so enjoy and make money with it!