File I/O

Weave treats structured file formats as first-class citizens. Reading and writing CSV, JSON, JSONL, YAML, TOML, and INI requires no imports or libraries.

Reading Files

Use read() with a path and a format symbol:

csv_data = read("data.csv", :csv)
json_data = read("config.json", :json)
json_data = read("config.json", :jsonl)
yaml_data = read("settings.yaml", :yaml)
toml_data = read("app.toml", :toml)
ini_data = read("config.ini", :ini)

Each format returns a Container with appropriate structure.

CSV

CSV rows are automatically parsed with the header row as keys:

sales = read("sales.csv", :csv)

# Each row is a container with header-based keys
sales *> ^(row) { puts(row[:name] + ": " + row[:amount]) }

# Access the first row's keys to discover the columns
columns = sales[0].keys

JSON

JSON objects become keyed containers, arrays become indexed containers:

config = read("config.json", :json)

# Access nested structure
config[:database][:host]
config[:database][:port]

Plain Text

Read plain text by calling read() with no format symbol:

text = read("notes.txt")

Writing Files

Use write() with a filename, data, and format:

data = [
    [name: "Alice", score: 95],
    [name: "Bob", score: 87]
]

write("outfile.csv", data, :csv)

See Custom Parsers for a deeper guide including customizing builtin parsers/formatters or building your own for custom file formats!

Combining File I/O with Pipelines

File I/O is most powerful when combined with pipeline operators:

# Sum a column from CSV
sum = ^(v, acc: 0) { acc + v } 

# select just the given keys from a Container
select = ^(*keys) { ^(row) { keys &> ^(k, acc: []) { acc[k] = row[k]; acc } } } 

read("sales.csv", :csv)
    *> select(:amount)
    &> sum
    |> print

# Transform JSON and write as CSV
read("users.json", :json)[:users]
    |> select(:name, :email)
    |> ^(users) { write("users.csv", users, :csv) }