Un error que se puede leer, pegar en un correo y mandarle al banco.
Esta librería no devuelve {:error, :invalid}. Cada falla es un
%AnchoFijo.Diagnostico{} que responde cuatro preguntas: dónde pasó
(línea, campo, posiciones), qué se esperaba, qué llegó y cuál es la
causa probable.
iex> alias AnchoFijo.Diagnostico
iex> d = Diagnostico.nuevo(
...> tipo: :largo_de_linea,
...> linea: 42,
...> esperado: "120 caracteres",
...> recibido: "118",
...> causa_probable: "posible campo faltante o archivo delimitado"
...> )
iex> Diagnostico.mensaje(d)
"línea 42: se esperaban 120 caracteres, llegaron 118; posible campo faltante o archivo delimitado"La causa probable es una hipótesis, no un veredicto. Existe porque en una integración bancaria el ciclo de feedback es de días: quien lee el error a las 3 AM necesita una pista de dónde mirar, no solo la constatación de que algo falló.
Summary
Functions
Redacta el diagnóstico como una sola línea de texto en español.
Construye un diagnóstico desde una keyword list o mapa de atributos.
Redacta una lista de diagnósticos como texto multilínea, uno por renglón.
Types
@type t() :: %AnchoFijo.Diagnostico{ campo: atom() | nil, causa_probable: String.t() | nil, contenido: String.t() | nil, esperado: String.t() | nil, linea: pos_integer() | nil, posicion: {pos_integer(), pos_integer()} | nil, recibido: String.t() | nil, tipo: tipo() }
@type tipo() :: :layout | :entrada | :largo_de_linea | :encoding | :campo_invalido
Familia del problema, para poder filtrar o agrupar sin parsear el mensaje.
:layout— la definición del formato es inconsistente consigo misma.:entrada— no se pudo leer el archivo o el argumento no es un binario.:largo_de_linea— la línea no mide lo que el layout declara.:encoding— hay bytes que no corresponden al encoding declarado.:campo_invalido— el contenido del campo no calza con su tipo.
Functions
Redacta el diagnóstico como una sola línea de texto en español.
iex> alias AnchoFijo.Diagnostico
iex> d = Diagnostico.nuevo(
...> tipo: :campo_invalido,
...> linea: 7,
...> campo: :monto,
...> posicion: {21, 32},
...> esperado: "12 dígitos",
...> recibido: "\"0001234A567\"",
...> causa_probable: "hay un carácter no numérico en el monto"
...> )
iex> Diagnostico.mensaje(d)
"línea 7, campo :monto (posiciones 21-32): se esperaban 12 dígitos, llegaron \"0001234A567\"; hay un carácter no numérico en el monto"Sin causa probable el mensaje simplemente la omite:
iex> AnchoFijo.Diagnostico.nuevo(tipo: :entrada, esperado: "un archivo legible", recibido: ":enoent")
...> |> AnchoFijo.Diagnostico.mensaje()
"entrada: se esperaba un archivo legible, llegó :enoent"
@spec nuevo(Enumerable.t()) :: t()
Construye un diagnóstico desde una keyword list o mapa de atributos.
Los valores de :esperado y :recibido se normalizan a texto: lo que no sea
binario pasa por inspect/1, para que un diagnóstico nunca falle al armarse.
iex> AnchoFijo.Diagnostico.nuevo(tipo: :campo_invalido, campo: :monto, esperado: 12, recibido: nil)
%AnchoFijo.Diagnostico{tipo: :campo_invalido, campo: :monto, esperado: "12", recibido: nil}
Redacta una lista de diagnósticos como texto multilínea, uno por renglón.
iex> alias AnchoFijo.Diagnostico
iex> [
...> Diagnostico.nuevo(tipo: :largo_de_linea, linea: 3, esperado: "40 bytes", recibido: "38"),
...> Diagnostico.nuevo(tipo: :largo_de_linea, linea: 9, esperado: "40 bytes", recibido: "41")
...> ]
...> |> Diagnostico.reporte()
...> |> String.split("\n")
["línea 3: se esperaban 40 bytes, llegaron 38", "línea 9: se esperaban 40 bytes, llegaron 41"]