flat_out

Create fixed length records with fixed length data fields to write a flat file.

Install

Install flat_out like any other ruby gem:

gem install flat_out

Overview of usage

flat_out creates a fixed length record with desired formatting of variable fields.
It was created to export a fixed length format file to send to an organization
using legacy computers and softwares.

* Create a new FlatOut object of desired length using FlatOut.new.
* Format this instance using various put methods based upon your input type.
* The final result is available via the to_s method of the object.

Important note on base

The positions specified in flat_out are 1 based, which is what most
flat file specifications I am dealing with use, and not Ruby's zero based. For example,
the first, second, and third characters in a ruby string are considered
positions 0, 1, and 2 respectively. In flat_out, these would be considered
positions 1, 2, and 3 respectively.

You can change the base by providing an option value when creating the object.

Commands

Available Commands:

FlatOut.new(rec_length, options)
put(len, pos, fld)
to_s

reset
reset(rec_length)
reset(rec_length, options)

FlatOut.digits_only(fld)
FlatOut.phone_squeeze(fld)

Command:

FlatOut.new(length)

Description:
  This command will create a blank string of specified length.
  example:
    myline = FlatOut.new(80)             # initializes an 80 character blank string in myline.

  Optionally, you can provide a base. This will change the base for position specifications.
  It is also useful while working with layouts that are specified with an offset.
  example:
    myline = FlatOut.new(80, :base => 0)             # Set the base to zero.
    myline = FlatOut.new(80, :base => 1)             # Set the base to 1(default).

  You can also change the order of the input parameters for the put statement.
  All six combinations of len, pos, fld are available.
  example:
    myline = FlatOut.new(80, :base => 0, :format => :fld_len_pos) # default is :len_pos_fld

Command:

myline.reset
myline.reset(new_length)

Description:
  This command will blank out the string in the myline object. If no length is provided, the string's
  length remains unchanged. You can change the length of the string in myline by specifying it here.

  example:
    myline = FlatOut.new(80)             # initializes an 80 character blank string in myline.
    myline.reset                         # re-initializes an 80 character blank string in myline.
    myline.reset(132)                    # myline now has a 132 character blank string.

Command:

myline.put(len, pos, fld)

Descriptions and examples:
  This command puts the provided field(fld) at starting position(pos) for (len) bytes.

  String fld:
    If the fld is shorter than specified len, it is padded with trailing spaces.
    If the fld is longer than specified len, it is left justified and truncated.

    Example:
                                              # '123456789012'
      myline = FlatOut.new(12)                # '            '
      myline.put(4, 2, 'ABCDEFG')             # ' ABCD       '
      myline.put(4, 2, 'ABCD')                # ' ABCD       '
      myline.put(4, 2, 'AB')                  # ' AB         '

  Integer fld:
    If the fld is shorter than specified len, it is padded with leading zeroes.
    If the fld is longer than specified len, it is right justified and truncated.
      myline = FlatOut.new(12)                # '            '
      myline.put(4, 2, 1234)                  # ' 1234       '
      myline.put(4, 2, 12)                    # ' 0012       '
      myline.put(4, 2, 123456)                # ' 3456       '

  Float fld with integer len:
    The decimal part of the fld is truncated and only the integer part is processed.
    It is useful when only the dollar part of an amount is to be reported.
      myline = FlatOut.new(12)                # '            '
      myline.put(4, 2, 1234.45)               # ' 1234       '
      myline.put(4, 2, 12.45)                 # ' 0012       '
      myline.put(4, 2, 123456.78)             # ' 3456       '

  Float fld with x.y length with explicit decimal point:
    Here x is the number of integer digits and y is the number of places after the decimal.
    The total length of this field in the output is going to be x + y + 1.
    If the fld is shorter than specified length, it is padded with leading and trailing zeroes.
    If the fld is longer than specified length, it is decimal justified and truncated.
      myline = FlatOut.new(12)                # '            '
      myline.put(4.2, 2, 1234.56)             # ' 1234.56    '
      myline.put(4.2, 2, 12.3)                # ' 0012.30    '
      myline.put(4.2, 2, 123456.789)          # ' 3456.79    '

  Float fld with -x.y length with implicit decimal:
    The format of the output has be specified in -x.y format where x is the number of integer
    digits and y is the number of places after the decimal. The total length of this field
    in the output is going to be x + y.
    This is the format used for decimal numbers by most legacy systems using fixed length records.
    example:
      myline = FlatOut.new(12)                # '            '
      myline.put(-4.2, 2, 1234.56)            # ' 123456     '
      myline.put(-4.2, 2, 12.3)               # ' 001230     '
      myline.put(-4.2, 2, 123456.789)         # ' 345679     '

  Entire record in an array:
    To specify the entire record in a single array, you have to use option :len_fld or :fld_len,
    and the array should contain the fields in strict sequence. Also see 'Working With Templates'.
    example 1:
      myline = FlatOut.new(21, :format => :len_fld)
      val = [5, 'ABCD',
             5,  10,
             4.2, 10.23,
             3, 'EFG']
      myline.put(val)                         # 'ABCD 000100010.23EFG '

    example 2:
      myline = FlatOut.new(21, :format => :fld_len)
      val = ['ABCD', 5,
              10,    5,
             10.23,  4.2,
             'EFG',  3]
      myline.put(val)                         # 'ABCD 000100010.23EFG '

Command:

myline.to_s

Description:
  This will return the formatted fixed length record which you can write to a file.
  It will blank fill or truncate the output to the correct length. Reset and put also
  return myline.to_s.

Command:

FlatOut.digits_only(fld)

Description:
  This helper method strips all non-digits from a given string. It is useful to
  convert formatted SSNs, EINs, Phone numbers etc to their numeric only equivalents.

example:
  FlatOut.digits_only('012-345-6789')       # '0123456789'
  FlatOut.digits_only('(800) 555-1212')     # '8005551212'

Command:

FlatOut.phone_squeeze(fld)

Description:
  This helper method strips the commonly used special characters and spaces from phone
  numbers, but leaves the alphabets alone. It is useful to standardize phone numbers fields.

example:
  FlatOut.phone_squeeze('(800) 555-1212') == "8005551212"
  FlatOut.phone_squeeze('(800) 555-1212 Ext 234') == "8005551212Ext234"
  FlatOut.phone_squeeze('(800) GOT-MILK') == "800GOTMILK"

Working with Templates

 You can also specify a template during initialization, and then put values in the template
 with an array. Templates can have length and positions as follows:

example:
  f = FlatOut.new(18, :template => [[5,1],[5,6],[4.2,11]])    #  '123456789012345678'
  val = ['ABCD',10,10.23]
  f.put(val)                                                  #  'ABCD 000100010.23 '

 You can also skip the position specification if the fields are specified in strict sequence
 in the template.
example:
  f = FlatOut.new(18, :template => [5,5,4.2])                 #  '123456789012345678'
  val = ['ABCD',10,10.23]
  f.put(val)                                                  #  'ABCD 000100010.23 '

Full Cycle Example:

myline = FlatOut.new(80)
myline.put(10, 1, Time.now.strftime("%m/%d/%Y"))
myline.put(30, 30, "TEST REPORT PRINTED")
myline.put(6, 70, "PAGE:")
myline.put(2, 79, 1)
puts myline.to_s

users = %w[Anil Mark Jake]

users.each do |user|
  myline.reset
  myline.put(12, 4, "USERNAME :")
  myline.put(12, 16, user)
  puts myline.to_s
end

myline.reset
myline.put(30, 30, "END OF REPORT")
puts myline.to_s

Issues, Suggestions

Contributing to flat_out

  • Check out the latest master to make sure the feature hasn’t been implemented or the bug hasn’t been fixed yet.

  • Check out the issue tracker to make sure someone already hasn’t requested it and/or contributed it.

  • Fork the project.

  • Start a feature/bugfix branch.

  • Commit and push until you are happy with your contribution.

  • Make sure to add tests for it. This is important so I don’t break it in a future version unintentionally.

  • Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.

Copyright © 2012 Anil Sharma. See LICENSE for further details.