soma.cell

CSV split/join — parse rows and project columns

Splits a CSV body into rows (by newline) and each row into fields (by comma), then maps header names to a list of record Maps. Demonstrates split on "\n" and ",", zipping headers to values, and join to re-serialize a row. Run: soma run csv.cell --signal parse "name,age\nAlice,30\nBob,25"

A Soma program from the text part of the verified corpus: 54 lines, cells Csv, CsvTest. It passes soma check with soma 3.2.4.

How it is built

The cell Csv declares 3 signals in its face: parse(body: String) -> List<Map>, row_to_line(row: List<String>) -> String and column(body: String, field: String) -> List<String>. Handlers: parse (line 18), row_to_line (line 34) and column (line 39).

The file also holds 1 test cell (CsvTest) with 5 assertions, run by soma test.

Generated from soma describe on this file.

The source

csv.cell

// ============================================================================
// CSV split/join — parse rows and project columns
// ============================================================================
//
// Splits a CSV body into rows (by newline) and each row into fields (by comma),
// then maps header names to a list of record Maps. Demonstrates split on "\n"
// and ",", zipping headers to values, and join to re-serialize a row.
//
// Run: soma run csv.cell --signal parse "name,age\nAlice,30\nBob,25"

cell Csv {
    face {
        signal parse(body: String) -> List<Map>
        signal row_to_line(row: List<String>) -> String
        signal column(body: String, field: String) -> List<String>
    }

    on parse(body: String) {
        let lines = split(body, "\n") |> filter(l => len(l) > 0)
        if len(lines) == 0 { return list() }
        let headers = split(lines[0], ",")
        let rows = list()
        for r in range(1, len(lines)) {
            let cells = split(lines[r], ",")
            let rec = map()
            for c in range(0, len(headers)) {
                rec[headers[c]] = cells[c]
            }
            rows = push(rows, rec)
        }
        return rows
    }

    on row_to_line(row: List<String>) {
        return join(row, ",")
    }

    // Pull a single column out as a list of strings.
    on column(body: String, field: String) {
        let rows = parse(body)
        return rows |> map(r => r[field])
    }
}

cell test CsvTest {
    rules {
        assert len(parse("name,age\nAlice,30\nBob,25")) == 2
        assert parse("name,age\nAlice,30\nBob,25")[0]["name"] == "Alice"
        assert parse("name,age\nAlice,30\nBob,25")[1]["age"] == "25"
        assert row_to_line(list("a", "b", "c")) == "a,b,c"
        assert column("city\nParis\nRome", "city")[1] == "Rome"
    }
}

What the toolchain says

Run on a fresh copy of the program at build time; the outputs are pasted unedited.

$ soma check csv.cell
✓ All checks passed.
$ soma test csv.cell
test CsvTest ...
  ✓ assert len(parse("name,age\nAlice,30\nBob,25")) == 2
  ✓ assert parse("name,age\nAlice,30\nBob,25")[0]["name"] == "Alice"
  ✓ assert parse("name,age\nAlice,30\nBob,25")[1]["age"] == "25"
  ✓ assert row_to_line(list("a", "b", "c")) == "a,b,c"
  ✓ assert column("city\nParis\nRome", "city")[1] == "Rome"

5 tests: 5 passed, 0 failed
$ soma verify csv.cell
Verifying csv.cell...
No state machine in this program: nothing to prove beyond `soma check` (invariants and lifecycles are what verify proves).
VERIFY OK (vacuous — no state machine)

Builtins used

filter, join, len, list, map, push, range, split

Source file: /corpus/text/csv.cell · examples/corpus/text/csv.cell