class Flat::File
Flat::File
¶ ↑
Flat
files are typically plain/text files containing many lines of text, or data. Each line, or record, consists of one or more fields. However, unlike CSV (comma separated value) files, there are no delimiters to define where values end or begin. Flat
provides a mechanism of defining a file’s record structure, allowing users to iterate over a given file and access its data as typical Ruby objects (String
, Numeric
, Date, Booleans, etc.).
Specification¶ ↑
A flat file’s specification is defined within the subclass of Flat::File
. The use of add_field
and pad
define and document the record structure.
# Actual plain text, flat file data, 29 bytes # # 10 20 # 012345678901234567890123456789 # Walt Whitman 18190531 # Linus Torvalds 19691228 class People < Flat::File add_field :first_name, width: 10, filter: :trim add_field :last_name, width: 10, filter: ->(v) { v.strip } add_field :birthday, width: 8, filter: BirthdayFilter pad :autoname, width: 2 def self.trim(v) v.strip end end
You will notice the minimum required information is field name and width. The special case is with pad
; you can specify a name but the general approach is to let Flat::File
name it for you.
An alternate method of specifying fields is to pass a block to the add_field
method. When using the block method you do not have to specify the name first. However, you do need to set the name inside the block. The value yielded to the block is an instance of Field::Definition
.
class People < Flat::File add_field do |fd| fd.name = :first_name fd.width = 10 fd.add_filter ->(v) { v.strip } fd.add_formatter ->(v) { v.strip } end add_field :last_name do |fd| fd.width = 10 fd.add_filter ->(v) { v.strip } fd.add_formatter ->(v) { v.strip } end end
Reading Data¶ ↑
After your Flat::File
has been defined you will be able to read data from an actual file. Flat::File
does not manage the opening and closing of Files or other IO instances (e.g. StringIO).
data_file = File.open('somefile.dat', 'r') People.new.each_record(data_file) do |person| puts "First Name: #{person.first_name}" # => Walter puts "Last Name : #{person.last_name}" # => White puts "Birthday : #{person.birthday}" # => 19590907 end data_file.close
each_record
yields a Record::Definition
and the line of text that produced it. This object will respond to the field names defined by add_field
. Plus, depending on the filters defined, the resulting data can be nearly any Ruby type: String
, Symbol, Boolean, Date, etc. This allows you to deal with the data as it was intended.
Writing Data¶ ↑
Slated for a future release.
Filters¶ ↑
When adding new fields you can specify a filter through which the incoming data will be passed. In the absence of a filter the resulting values from the Record::Definition
will be the raw text as found in the flat file.
You can define filters in 1 of four ways: Symbol, Proc, Class, or Object
.
Operationally they all function the same way: used when reading the raw text in the file to produce a filtered value for storage in a Record::Definition
.
Defined as a Symbol¶ ↑
add_field :first_name, width: 10, filter: :trim
trim
, in this case, must be defined on the Flat::File
subclass.
def self.trim(v) v.strip end
Use this method when more control over the filtering is required, such as handling Date parsing errors.
Defined as a Proc¶ ↑
add_field :last_name, width: 10, filter: ->(v) { v.strip }
The proc is stored and later called when needed. If the filtering requirements are easy and direct, this method is appropriate.
Defined as a Class or Object
¶ ↑
add_field :birthday, width: 8, filter: BirthdayFilter add_field :birthday, width: 8, filter: BirthdayFilter.new
The Class or Object
used must respond to filter
. This method is very similar to the Symbol
method, expect there is only 1 method to define.
def self.filter(v) date = Date.parse(v) rescue $! return date unless date.is_a? ArgumentError nil end def filter(v) self.class.filter(v) end
Formatters¶ ↑
Slated for a future release.
Layouts¶ ↑
Slated for a future release.
Exceptions¶ ↑
-
FlatFileError
- Generic error class and superclass of all other errors raised byFlat
. -
LayoutConstructorError
- The specified layout definition was not valid. -
RecordLengthError
- Generic error having to do with line lengths not meeting expectations. -
ShortRecordError
- The incoming line was shorter than expectations defined. -
LongRecordError
- The incoming line was longer than expectations defined.