module ETL #:nodoc:
module Parser #:nodoc:
# Parser for fixed with files
class FixedWidthParser < ETL::Parser::Parser
# Initialize the parser
# * source: The source object
# * options: Parser options Hash
def initialize(source, options={})
super
configure
end
# Return each row
def each
Dir.glob(file).each do |file|
open(file).each do |line|
row = {}
lines_skipped = 0
fields.each do |name, f|
if lines_skipped < source.skip_lines
lines_skipped += 1
next
end
# TODO make strip optional?
row[name] = line[f.field_start, f.field_length].strip
end
yield row
end
end
end
# Return a map of defined fields
def fields
@fields ||= {}
end
private
def configure
source.definition.each do |field, options|
fields[field] = FixedWidthField.new(
options[:name], options[:start], options[:end], options[:length]
)
end
end
end
class FixedWidthField #:nodoc:
attr_reader :name, :field_start, :field_end, :field_length
# Initialize the field.
def initialize(name, field_start, field_end=nil, field_length=nil)
@name = name
@field_start = field_start - 1
if field_end
@field_end = field_end
@field_length = @field_end - @field_start
elsif field_length
@field_length = field_length
@field_end = @field_start + @field_length
else
raise DefinitionError, "Either field_end or field_length required"
end
end
end
end
end