Current section

Files

Jump to
posexional lib posexional.ex
Raw

lib/posexional.ex

defmodule Posexional do
@moduledoc """
Posexional is a library to manage positional files in elixir.
Positional files are the most bad and **terrifying file format** you ever want to work with, believe me, it's utter crap. Still some *web services* use this format to expose data services, and if you are here reading this, probably you are in luck like us!
A positional file has a *format specification* like this:
| field name | offset | length | notes |
|------------|--------|--------|-------------------------------------------------|
| code | 0 | 5 | request code fill with 0 and align on the right |
| prog | 0 | 5 | progressive number (fill with spaces) |
| type | 21 | 2 | AA |
| number | 24 | 2 | 01 |
| name | 27 | 10 | person name (fill with -) |
| future use | 38 | 2 | leave empty |
| end | 41 | 1 | ! |
The expected results should be something like this:
000B1 1AA01george---- !
000B2 2AA01john------ !
000B3 3AA01ringo----- !
000B4 4AA01paul------ !
cool uh?
With Posexional you can produce this file with
alias Posexional.Field
beatles_row = Posexional.Row.new(:beatles, [
Field.Value.new(:code, 5, ?0, :right),
Field.ProgressiveNumber.new(5),
Field.Value.new(:type, 2),
Field.Value.new(:number, 2),
Field.Value.new(:name, 10, ?-),
Field.Empty.new(2),
Field.Value.new(:end, 1, ?!)
])
file = Posexional.File.new([beatles_row])
Posexional.write(file, [beatles: [
code: "B1", type: "AA", number: "01", name: "george"
], beatles: [
code: "B2", type: "AA", number: "01", name: "john"
], beatles: [
code: "B2", type: "AA", number: "01", name: "ringo"
], beatles: [
code: "B2", type: "AA", number: "01", name: "paul"
]])
In the first part we **define the structure**. We are not saying what the content or the number of rows there will be, we are just saying that there is a row called :beatles with the named field in it.
Then we create a Posexional.File struct and say that only the beatles row will be in there.
Then we can call Posexional.write/2, we pass the Posexional.File struct just defined and we feed the real data that should be written there. **Just the relevant data**, The empty fields or the progressive number is managed by the library itself.
And even better, with the Posexional.File struct that we defined, we can even **read a positional file**
"""
@doc """
write a positional file with the given stuct and data
"""
@spec write(%Posexional.File{}, Keyword.t) :: binary
def write(positional_file, values) do
Posexional.File.write(positional_file, values)
end
@doc """
same as write/2, but with a path to a new file to write the result to
"""
@spec write_file!(%Posexional.File{}, Keyword.t, binary) :: nil
def write_file!(positional_file, values, path) do
Posexional.File.write_path!(positional_file, values, path)
end
@doc """
read a positional stream of data with the given struct, returns a keyword list of the extracted data
"""
@spec read(%Posexional.File{}, binary) :: Keyword.t
def read(positional_file, content) do
Posexional.File.read(positional_file, content)
end
@doc """
same as read/2, but with a path to a file to read the stream from
"""
@spec read_file!(%Posexional.File{}, binary) :: Keyword.t
def read_file!(file, path) do
content = File.read! path
read(file, content)
end
end