README.md

# tysv

[![Package Version](https://img.shields.io/hexpm/v/tysv)](https://hex.pm/packages/tysv)
[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/tysv/)

```sh
gleam add tysv
```

## Standard CSV

```gleam
import gleam/float
import gleam/int
import gleam/string
import tysv
import tysv/text

const data = "Vanilla,23,0.5
Strawberry,24,0.75
Mango,34,1.75"

const rows = [
  #("Vanilla", 23, 0.5),
  #("Strawberry", 24, 0.75),
  #("Mango", 34, 1.75),
]

pub fn standard_csv() {
  // Build typed list from CSV
  assert Ok(rows)
    == tysv.build({
      use flavor <- tysv.parsed
      use price <- tysv.parsed
      use kg <- tysv.parsed
      #(flavor, price, kg)
    })
    |> tysv.col(Ok)
    |> tysv.col(int.parse)
    |> tysv.col(float.parse)
    |> tysv.from(data)

  // Build CSV from typed list
  assert data
    == text.build(fn(row) {
      let #(flavor, price, kg) = row
      [flavor, int.to_string(price), float.to_string(kg)]
    })
    |> text.from(rows)
}
```

## Skip Header

```gleam
// Dependencies and constants from the standard case are omitted for brevity.

pub fn skip_header() {
  let data = "Flavor,Price,Kg\n" <> data

  // Build typed list from CSV (with header)
  assert Ok(rows)
    == tysv.build({
      use flavor <- tysv.parsed
      use price <- tysv.parsed
      use kg <- tysv.parsed
      #(flavor, price, kg)
    })
    |> tysv.col(Ok)
    |> tysv.col(int.parse)
    |> tysv.col(float.parse)
    |> tysv.skip_header(True)
    |> tysv.from(data)

  // Build CSV (with header) from typed list
  assert data
    == text.build(fn(row) {
      let #(flavor, price, kg) = row
      [flavor, int.to_string(price), float.to_string(kg)]
    })
    |> text.headers(["Flavor", "Price", "Kg"])
    |> text.from(rows)
}
```

## Custom Separators

```gleam
// Dependencies and constants from the standard case are omitted for brevity.

pub fn custom_separators() {
  let data =
    string.replace(data, ",", ";")
    |> string.replace("\n", "|")

  // Build typed list from CSV (with custom separators)
  assert Ok(rows)
    == tysv.build({
      use flavor <- tysv.parsed
      use price <- tysv.parsed
      use kg <- tysv.parsed
      #(flavor, price, kg)
    })
    |> tysv.col(Ok)
    |> tysv.col(int.parse)
    |> tysv.col(float.parse)
    |> tysv.col_sep(";")
    |> tysv.row_sep("|")
    |> tysv.from(data)

  // Build CSV (with custom separators) from typed list
  assert data
    == text.build(fn(row) {
      let #(flavor, price, kg) = row
      [flavor, int.to_string(price), float.to_string(kg)]
    })
    |> text.col_sep(";")
    |> text.row_sep("|")
    |> text.from(rows)
}
```

## With remaining columns

```gleam
pub fn standard_csv() {
  let data =
    data |> string.replace("\n", ",wibble,wobble\n") <> ",wibble,wobble"
  let rows = {
    use row <- list.map(rows)
    #(row, ["wibble", "wobble"])
  }

  // Build typed list from CSV
  assert Ok(rows)
    == tysv.build({
      use flavor <- tysv.parsed
      use price <- tysv.parsed
      use kg <- tysv.parsed
      #(flavor, price, kg)
    })
    |> tysv.col(Ok)
    |> tysv.col(int.parse)
    |> tysv.col(float.parse)
    |> tysv.from_with_rest(data)
}
```

Further documentation can be found at <https://hexdocs.pm/tysv>.

## Development

```sh
gleam test  # Run the tests
```

## Provenance
All code in this project is written naturally. **No** AI generation or assistance is used to implement any functionality.

## LICENSE
tysv is made available under the terms of the EUPL-1.2 License.