diff options
| author | Julian Hurst <ark@mansus.space> | 2024-11-15 01:14:07 +0100 |
|---|---|---|
| committer | Julian Hurst <ark@mansus.space> | 2024-11-15 01:14:07 +0100 |
| commit | 4da35965e4ba31cacd90776bffbf36d7f585c645 (patch) | |
| tree | eb834f3d3b71cb38b7aac77c9b12a0e144293839 | |
| parent | 189c3af4052d543ce816637d97fed926fefa5c47 (diff) | |
| download | hatask-4da35965e4ba31cacd90776bffbf36d7f585c645.tar.gz | |
tsv -> format::tsv and add tests
| -rw-r--r-- | cmd.ha | 2 | ||||
| -rw-r--r-- | format/tsv/README | 6 | ||||
| -rw-r--r-- | format/tsv/reader.ha | 52 | ||||
| -rw-r--r-- | format/tsv/writer.ha | 63 | ||||
| -rw-r--r-- | tsv/tsv.ha | 22 |
5 files changed, 122 insertions, 23 deletions
@@ -7,7 +7,7 @@ use path; use os::exec; use strconv; use ascii; -use tsv; +use format::tsv; type error = !(!str | io::error | path::error | exec::error | strconv::error); diff --git a/format/tsv/README b/format/tsv/README new file mode 100644 index 0000000..67d9d71 --- /dev/null +++ b/format/tsv/README @@ -0,0 +1,6 @@ +format::tsv supports writing and reading text in TSV (Tab Separated Values) format: + + name\tdescription + Hare\tThe Hare programming language + +TSV doesn't allow tabs to be used as anything other than a separator. Due to this, any existing tabs are removed when writing. diff --git a/format/tsv/reader.ha b/format/tsv/reader.ha new file mode 100644 index 0000000..df2ba35 --- /dev/null +++ b/format/tsv/reader.ha @@ -0,0 +1,52 @@ +use bufio; +use io; +use encoding::utf8; +use strings; +use memio; +use fmt; + +// Reads records from an io::handle and returns them. +export fn readrecords(r: io::handle) ([][]str | io::error | utf8::invalid) = { + const sc = bufio::newscanner(r); + defer bufio::finish(&sc); + + let records: [][]str = []; + for (const line: str => bufio::scan_line(&sc)?) { + append(records, strings::dupall(strings::split(line, "\t"))); + }; + return records; +}; + +// Frees all the records. +export fn freerecords(records: [][]str) void = { + for (const record .. records) { + strings::freeall(record); + }; + free(records); +}; + +@test fn readnormal() void = { + const b = strings::toutf8("col1\tcol2\tcol3 +1\t2\t3 +4\t5\t6\n" +); + const st = memio::fixed(b); + + const expected = [ + ["col1", "col2", "col3"], + ["1", "2", "3"], + ["4", "5", "6"], + ]; + + const actual = readrecords(&st)!; + defer freerecords(actual); + for (let i = 0z; i < len(expected); i += 1) { + for (let j = 0z; j < len(actual); j += 1) { + const exp = expected[i][j]; + const act = actual[i][j]; + fmt::errorfln("exp: {}", exp)!; + fmt::errorfln("act: {}", act)!; + assert(exp == act); + }; + }; +}; diff --git a/format/tsv/writer.ha b/format/tsv/writer.ha new file mode 100644 index 0000000..f1f045b --- /dev/null +++ b/format/tsv/writer.ha @@ -0,0 +1,63 @@ +use io; +use strings; +use fmt; +use memio; + +// Writes a slice strings to a handle in TSV format. Existing tabs in the record +// are removed. +export fn writerecord(w: io::handle, record: []str) (void | io::error) = { + let sep = ""; + for (const field .. record) { + const pfield = strings::replace(field, "\t", ""); + defer free(pfield); + fmt::fprintf(w, "{}{}", sep, pfield)!; + sep = "\t"; + }; + fmt::fprintln(w)!; +}; + +// Writes a slice of string slices to a handle in TSV format. Existing tabs in +// the records are removed. +export fn writerecords(w: io::handle, records: [][]str) (void | io::error) = { + for (const record .. records) { + writerecord(w, record)?; + }; +}; + +@test fn writenormal() void = { + const expected = "col1\tcol2\tcol3 +1\t2\t3 +4\t5\t6\n"; + const input: [][]str = [ + ["col1", "col2", "col3"], + ["1", "2", "3"], + ["4", "5", "6"], + ]; + const st = memio::dynamic(); + defer io::close(&st)!; + writerecords(&st, input)!; + const actual = memio::string(&st)!; + fmt::errorfln("expected: {}EOF", expected)!; + fmt::errorln()!; + fmt::errorfln("actual: {}EOF", actual)!; + assert(actual == expected); +}; + +@test fn writetabs() void = { + const expected = "col1\tcol2\tcol3 +1\t2\t3 +4\t5\t6\n"; + const input: [][]str = [ + ["col1\t", "co\tl2", "col3"], + ["1", "2", "\t3"], + ["4\t", "\t\t5\t", "6"], + ]; + const st = memio::dynamic(); + defer io::close(&st)!; + writerecords(&st, input)!; + const actual = memio::string(&st)!; + fmt::errorfln("expected: {}EOF", expected)!; + fmt::errorln()!; + fmt::errorfln("actual: {}EOF", actual)!; + assert(actual == expected); +}; diff --git a/tsv/tsv.ha b/tsv/tsv.ha deleted file mode 100644 index 85015a1..0000000 --- a/tsv/tsv.ha +++ /dev/null @@ -1,22 +0,0 @@ -use io; -use strings; -use fmt; - -export type error = !(str | io::error); - -export fn writerecord(w: io::handle, record: []str) (void | error) = { - let sep = ""; - for (const field .. record) { - const pfield = strings::replace(field, "\t", ""); - defer free(pfield); - fmt::fprintf(w, "{}{}", sep, pfield)!; - sep = "\t"; - }; - fmt::fprintln(w)!; -}; - -export fn writerecords(w: io::handle, records: [][]str) (void | error) = { - for (const record .. records) { - writerecord(w, record)?; - }; -}; |
