-- content.wo — the tutorial chapters, seeded into the Chapter table on
-- first boot (types.wo's seed_if_empty). Model CONTENT, so it sits in
-- the root module beside types.wo: it inserts rows. Bodies are HTML fragments
-- BUILT with the writeonce-view dep — prose in el(), code samples through
-- code_block() which escapes them. Editing a chapter later (the admin
-- route) overwrites body/title in place; the WAL keeps the edit across
-- restarts, which is exactly chapter 6's lesson demonstrated by the
-- site that teaches it.
use view
fn ch_hello() -> Text {
let b = el("p", "leading-relaxed mb-4",
"A writeonce program is one directory of .wo files and one entry: a free " .. "function named main. It returns the process exit code. There is no " .. "runtime to install separately and no build pipeline — woc build produces " .. "ONE self-contained binary with the VM and your bytecode inside.");
b = b .. code_block("fn main() -> Int {\n print(\"hello, writeonce\");\n return 0;\n}");
b = b .. el("p", "leading-relaxed mt-4",
"Run it: woc build . -o hello && ./hello. " .. "Statements end with ;, blocks use braces, comments start with --.");
return b;
}
fn ch_values() -> Text {
let b = el("p", "leading-relaxed mb-4",
"let binds a value; the type is inferred. Scalars: Int (64-bit), " .. "Float, Bool, Text (bytes, binary-safe). Text " .. "interpolates with \${...} and concatenates with ... " .. "Integer literals speak hex and binary, and the full bitwise set is here: " .. "& | ^ << >> — grouped Go-style, so a mask compare needs no parentheses.");
b = b .. code_block("let port = 8080;\nlet pi = 3.14159;\nlet name = \"writeonce\";\nlet msg = \"listening on \${port}\";\n\nlet flags = 0b1010_0001;\nlet high = flags & 0xF0; -- bitwise AND, then == compares\nlet shifted = 1 << 12; -- 4096\nif flags & 0x80 != 0 {\n print(\"top bit set\"); -- groups (flags & 0x80) != 0\n}");
return b;
}
fn ch_containers() -> Text {
let b = el("p", "leading-relaxed mb-4",
"Two containers: multi T (a growable list) and map<K, V>. " .. "A map read m[k] answers nil when the key is absent — the everyday idiom " .. "for optional lookups like HTTP headers. for .. in walks both.");
b = b .. code_block("let langs: multi Text = [\"c\", \"ocaml\", \"writeonce\"];\npush(langs, \"more\");\nprint(\"count \${len(langs)}\");\n\nlet ages: map = {};\nages[\"ada\"] = 36;\nlet a = ages[\"grace\"]; -- ?Int: nil, no trap\nif a == nil { print(\"unknown\"); }\n\nfor l in langs {\n print(l);\n}\nfor k, v in ages {\n print(\"\${k} is \${v}\");\n}");
return b;
}
fn ch_classes() -> Text {
let b = el("p", "leading-relaxed mb-4",
"Classes hold fields and methods. There are NO function values and NO closures — a " .. "deliberate doctrine: behavior travels as a class satisfying an interface, and " .. "satisfaction is structural (same method name and shape, Go-style, no " .. "implements). This is how porch, the web framework, takes handlers.");
b = b .. code_block("interface Handler {\n fn handle(req: Req) -> Resp\n}\n\nclass Hello {\n greeting: Text\n fn handle(req: Req) -> Resp {\n return ok_text(\"\${self.greeting}, \${req.path}\");\n }\n}\n\n-- any class with a matching handle() satisfies Handler\napp.get(\"/hello\", Hello { greeting: \"hi\" });");
return b;
}
fn ch_optionals() -> Text {
let b = el("p", "leading-relaxed mb-4",
"?T is a value or nil, and the compiler forces the check before use. " .. "Failures are TRAPS: named, catchable, never silent. try ... catch (e) is " .. "an expression; e carries code, line, method and message. Anything " .. "uncaught ends the program with the same structured report.");
b = b .. code_block("let n = parse_int(\"42x\"); -- ?Int\nif n == nil {\n print(\"not a number\");\n}\n\nlet r = try fs.read_all(\"/etc/missing\", 4096) catch (e) e.msg;\nprint(r); -- the file's bytes, or \"No such file or directory\"\n\nlet d = 0;\nlet q = try 10 / d catch (e) 0 - 1; -- DIV0 is a trap, caught here");
return b;
}
fn ch_tables() -> Text {
let b = el("p", "leading-relaxed mb-4",
"The database is IN the language. @table makes a class a table; " .. "insert writes a row; queries are first-class expressions; an UPDATE is a " .. "plain field assignment on a query result. With WO_DATA=<dir> every " .. "commit is WAL-durable before it is acknowledged and replays on restart — this very " .. "site stores these chapters that way, and the admin form's edits survive a kill.");
b = b .. code_block("@table(name: \"notes\", index: [tag])\nclass Note {\n tag: Text @unique\n val: Int\n}\n\ninsert Note { tag: \"first\", val: 1 };\n\nfor n in from x in Note where x.val > 0 order by x.tag select x {\n print(\"\${n.tag} = \${n.val}\");\n}\n\nlet hits = from x in Note where x.tag == \"first\" take 1 select x;\nif len(hits) == 1 {\n hits[0].val = 2; -- an update: assign through the row\n}");
return b;
}
fn ch_actors() -> Text {
let b = el("p", "leading-relaxed mb-4",
"Concurrency is actors on fibers: spawn makes an actor from a class with a " .. "receive method, send delivers one message at a time, and " .. "ownership MOVES with the message — no locks, no shared mutable state, no data races " .. "by construction. Blocking calls park the fiber; the shard serves others meanwhile. " .. "One VM per core by default; mailboxes are bounded (a full one is a catchable trap).");
b = b .. code_block("class Counter {\n total: Int\n fn receive(msg: Tick) {\n self.total = self.total + msg.n;\n print(\"total \${self.total}\");\n }\n}\n\nclass Tick {\n n: Int\n}\n\nfn main() -> Int {\n let c: actor Tick = spawn Counter { total: 0 };\n send(c, Tick { n: 1 });\n send(c, Tick { n: 2 });\n time.sleep(50); -- parks this fiber; the actor runs\n return 0;\n}");
return b;
}
fn ch_deps() -> Text {
let b = el("p", "leading-relaxed mb-4",
"Dependencies are git repositories pinned in wo.toml; wo.lock " .. "records the exact revision, and locked builds work offline. The [deps] KEY names the " .. "module you use. This site has two: porch, the writeonce web framework, and the writeonce-view " .. "library that rendered the page you are reading.");
b = b .. code_block(`
[deps]
porch = { git = "https://github.com/shoneyj/porch", rev = "v0.1.0" }
view = { git = "https://github.com/shoneyj/writeonce-view", rev = "v0.1.0" }`);
b = b .. code_block(`
use porch
use porch/http
use view
-- html's builders + tailwind-style utilities, zero JS, no build step:
let body = el("h1", "text-3xl font-bold", "Hello");
return ok_html(page("Hello", body));`);
return b;
}
fn ch_serving() -> Text {
let b = el("p", "leading-relaxed mb-4",
"The whole stack of this site: routes with :param captures, a middleware " .. "chain, handler classes, @table persistence, and server-rendered HTML — " .. "one binary behind a proxy. This is the site's own main, abbreviated:");
b = b .. code_block("fn main(args: multi Text) -> Int {\n seed_if_empty();\n let app = App { middleware: [], routes: [] };\n app.use_mw(Mw { m: Logging {} });\n app.get(\"/\", Home {});\n app.get(\"/ch/:slug\", ShowChapter {});\n app.post(\"/admin/ch/:slug\", AdminEdit { token: token });\n return app.serve(\"127.0.0.1\", port);\n}");
b = b .. el("p", "leading-relaxed mt-4",
"The admin route checks its bearer token in the handler — mechanism lives in the " .. "framework (bearer_token, constant-time ct_eq), POLICY stays " .. "in the app. Try editing this chapter: " .. "curl -X POST -H \"authorization: Bearer ...\" -d \"title=...&body=...\" /admin/ch/serving.");
return b;
}
-- One seed row per chapter: (ord, slug, title, body-builder above).
pub fn seed_chapters() {
insert Chapter { slug: "hello", ord: 1, title: "Hello, writeonce", body: ch_hello() };
insert Chapter { slug: "values", ord: 2, title: "Values, Text and bitwise", body: ch_values() };
insert Chapter { slug: "containers", ord: 3, title: "multi and map", body: ch_containers() };
insert Chapter { slug: "classes", ord: 4, title: "Classes and interfaces", body: ch_classes() };
insert Chapter { slug: "optionals", ord: 5, title: "Optionals and traps", body: ch_optionals() };
insert Chapter { slug: "tables", ord: 6, title: "@table: the built-in database", body: ch_tables() };
insert Chapter { slug: "actors", ord: 7, title: "Actors and fibers", body: ch_actors() };
insert Chapter { slug: "deps", ord: 8, title: "Dependencies", body: ch_deps() };
insert Chapter { slug: "serving", ord: 9, title: "Serving the web (this site)", body: ch_serving() };
}