Skip to content

Cookbook

Common patterns and recipes for Wyn.

Read a File Line by Line

wyn
content = File.read("data.txt")
for line in content.lines() {
    print(line)
}

Parse JSON

wyn
data = "{\"name\": \"Alice\", \"age\": 25}".parse_json()
print(data.get_string("name"))    // Alice
print("${data.get_int("age")}")  // 25

HTTP Server with JSON API

wyn
server = Http.listen(3000)
while true {
    req = Http.accept(server)
    path = req.split("|")[1]

    if path == "/api/hello" {
        Http.respond(req, 200, "application/json", Json.stringify({"message": "hello"}))
    } else {
        Http.respond(req, 404, "application/json", "{\"error\": \"not found\"}")
    }
}

Concurrent Map

wyn
fn process(item: string) -> string {
    return item.upper()
}

items = ["hello", "world", "wyn"]
futures = []
for item in items {
    futures.push(spawn process(item))
}

results = []
for f in futures {
    results.push(await f)
}
// results: ["HELLO", "WORLD", "WYN"]

CSV Processing

wyn
csv = Csv.parse(File.read("data.csv"))
for i in 1..Csv.row_count(csv) {
    name = Csv.get_field(csv, i, "name")
    age = Csv.get_field(csv, i, "age")
    print(name + " is " + age + " years old")
}

String Manipulation

wyn
s = "  Hello, World!  "
print(s.trim())                    // "Hello, World!"
print(s.trim().upper())           // "HELLO, WORLD!"
print(s.trim().replace("World", "Wyn"))  // "Hello, Wyn!"
print(s.trim().split(", ").join(" | "))  // "Hello | World!"

HashMap

wyn
m = HashMap.new()
HashMap.set(m, "name", "Alice")
HashMap.set(m, "city", "NYC")
print(HashMap.get(m, "name"))     // Alice
print("${HashMap.len(m)}") // 2

Logging

wyn
Log.set_level(1)  // INFO and above
Log.info("starting")
Log.debug("hidden")  // suppressed
Log.warn("careful")
Log.error("failed")

Base64

wyn
encoded = Base64.encode("secret data")
print(encoded)                         // c2VjcmV0IGRhdGE=
print(Base64.decode(encoded))          // secret data

Command-Line Arguments

wyn
name = Args.get("name")
verbose = Args.has("v")
if name != "" {
    print("Hello, " + name)
}

Benchmarking

wyn
fn fib(n: int) -> int {
    if n <= 1 { return n }
    return fib(n - 1) + fib(n - 2)
}

// Run with: wyn bench fib.wyn --iterations 10
fib(35)

HTTP Client

Make GET and POST requests with headers:

wyn
// Simple GET
body = Http.get("https://api.example.com/users")
print(body)

// POST with JSON body
// Http.post takes (url, body). For custom request headers, set them first with
// Http.set_header(name, value) - there is no headers argument.
resp = Http.post("https://api.example.com/users",
    Json.stringify({"name": "Alice", "role": "admin"}))
print(resp)

JSON Parsing and Building

Parse nested JSON, build new objects, and handle missing keys:

wyn
raw = File.read("config.json")
cfg = Json.parse(raw)

host = Json.get(cfg, "server.host")
port = Json.get_int(cfg, "server.port")
tags = Json.get_array(cfg, "tags")

// Build a new JSON object
out = Json.new()
Json.set_string(out, "status", "ok")
Json.set_int(out, "count", Json.array_len(tags))
print(Json.stringify(out))

CSV Processing with Filtering

Read a CSV, filter rows, and write results:

wyn
csv = Csv.parse(File.read("sales.csv"))
total = 0.0

for i in 1..Csv.row_count(csv) {
    region = Csv.get_field(csv, i, "region")
    amount = Csv.get_field(csv, i, "amount").to_float()
    if region == "US" {
        total = total + amount
    }
}

print("US total: $${total}")
File.write("report.txt", "US sales total: $${total}\n")

File Watcher

Poll a directory for changes and react:

Wyn has no File.modified / mtime function, so watch the content hash instead. That is also more correct than mtime: a touched-but-unchanged file will not trigger a reload, and a file rewritten within the same clock tick will.

wyn
var last = ""

while true {
    if File.exists("config.json") {
        stamp = Crypto.sha256(File.read("config.json"))
        if stamp != last {
            println("Config changed, reloading...")
            cfg = Json.parse(File.read("config.json"))
            last = stamp
        }
    }
    Time.sleep(1000)
}

CLI Argument Parsing

Build a CLI tool with named flags and positional args:

wyn
args = Args.positional()
cmd = ""
if args.len() > 0 {
    cmd = args[0]
}
output = Args.get("output")
verbose = Args.has("verbose")

if cmd == "" {
    print("Usage: mytool <command> [--output file] [--verbose]")
    return 1
}

if verbose {
    Log.set_level(0)  // DEBUG
}

Log.debug("Running command: ${cmd}")
Log.info("Output: ${output}")

Run it: wyn run tool.wyn -- process --output data.csv --verbose

SQLite CRUD

Full create/read/update/delete with a SQLite database:

wyn
db = Db.open("app.db")
Db.exec(db, "CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, name TEXT, email TEXT)")

// Create
Db.exec_p(db, "INSERT INTO users(name, email) VALUES(?, ?)", ["Alice", "[email protected]"])

// Read
// Db.query returns ONE string: rows separated by "\n", columns by "|"
rows = Db.query(db, "SELECT id, name, email FROM users")
for row in rows.trim().split("\n") {
    cols = row.split("|")
    print("${cols[0]}: ${cols[1]} <${cols[2]}>")
}

// Update
Db.exec_p(db, "UPDATE users SET email = ? WHERE name = ?", ["[email protected]", "Alice"])

// Delete
Db.exec_p(db, "DELETE FROM users WHERE name = ?", ["Alice"])
Db.close(db)

Regex Extraction

Extract patterns from text using regex:

wyn
text = "Contact us at [email protected] or [email protected]"
// Regex.find_all returns ONE string, one match per line
emails = Regex.find_all(text, "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}")

for email in emails.trim().split("\n") {
    print("Found: ${email}")   // Found: [email protected] / Found: [email protected]
}

// match / find / replace / split are the whole surface - there are no capture groups
log = "2026-04-23 ERROR: disk full"
if Regex.match(log, "^[0-9]{4}-[0-9]{2}-[0-9]{2} ERROR") {
    print("error line")
}
print("at: ${Regex.find(log, "ERROR")}")                        // at: 11
print(Regex.replace(log, "[0-9]{4}-[0-9]{2}-[0-9]{2}", "<date>"))  // <date> ERROR: disk full

Environment Variables

Read config from the environment with defaults:

wyn
// Env.get takes ONE argument - there is no default-value form, so default explicitly.
raw_port = Env.get("PORT")
port = raw_port == "" ? 8080 : raw_port.to_int()
raw_db = Env.get("DATABASE_URL")
db_url = raw_db == "" ? "app.db" : raw_db
debug = Env.get("DEBUG") == "true"

if debug {
    Log.set_level(0)
    Log.debug("Debug mode on")
}

print("Starting on port ${port}")
print("Database: ${db_url}")

See Also

MIT License - v1.21.0