What's New — Per Version
Each version of Frankie ships a runnable whats_new_vX.fk example file that demonstrates every new feature introduced in that release. Run any of them with:
frankiec run examples/whats_new_v118.fk
v1.18 — whats_new_v118.fk
Theme: "From projects to products" — edit (LSP), ship (bundle), connect (WebSockets), debug (breakpoint). Pure Python stdlib underneath, zero external dependencies, as always.
| Feature | Summary |
|---|---|
frankiec lsp |
Language Server over stdio — live diagnostics, completion, hover docs in VS Code, Neovim, Helix, Zed |
frankiec bundle |
Compile a program + all require/import/stitch targets into ONE self-contained .py — runs anywhere with Python 3.8+ |
| WebSockets | app.websocket("/ws/:room") do \|ws\| ... end server + ws_connect(url) client — hand-rolled RFC 6455 |
breakpoint |
Pause into a scoped debug REPL — vars, where, any Frankie expression; skipped when stdin isn't a tty |
enum Status(pending, active, done) |
Named symbolic values — Status.pending, .values, .include?, case/when matching |
benchmark "label" do ... end |
Time a block — prints ⏱ label: 12.3ms, returns elapsed ms |
| Set operations | .union / .intersect / .difference — order-preserving, deduplicating |
| Numeric literals | Underscores 1_250_000 + scientific notation 6.022e23 |
| Project-wide tooling | frankiec check . and frankiec fmt --write . recurse into directories |
| Stitch lockfile | stitch.lock with sha256 pins — frankiec stitch verify / update |
v1.17 — whats_new_v117.fk
Theme: "Programs that grow" — namespacing, real static checking, typed errors, first-class ranges, easy concurrency, TCP sockets, and a stitch installer. Everything still pure Python stdlib, zero dependencies.
| Feature | Summary |
|---|---|
import "path" as name |
Load a .fk file into its own namespace — geo.circle_area(5), geo.PI; modules cached; require unchanged |
error TypeName |
User-defined error types — raise ValidationError, "msg", caught with rescue ValidationError => e |
rescue Type => e |
New Ruby-style rescue binding (old rescue Type e form still works) |
| First-class ranges | r = 1..10 prints as 1..10; .to_vec, .include?, .step(n), .sum, .first, .last |
Range case/when |
when 90..100 tests membership — works with range values in variables too |
| Record dot access | p1.x instead of p1["x"] — hash-style access still works |
parallel_map |
parallel_map(urls, workers: 8) do \|u\| ... end — thread-pool map, results in input order |
| TCP sockets | tcp_connect / tcp_listen / tcp_serve — send_line, recv_line, peer, threaded server loop |
frankiec check |
Real static analysis — undefined names, wrong arg counts, unused locals; --strict for CI |
| Cross-file tracebacks | Runtime errors point at the right file and line, in requires, imports and stitches |
test groups |
test "name", tags: ["slow"] do ... end — filter with --filter / --tag |
stub / unstub |
Swap any global function during tests — stub("shell", ->(cmd) { fake }) |
| Stitch installer | frankiec stitch install frankiecolor [--global], frankiec stitch list |
| REPL upgrades | Bare expressions echo => value, _ holds last result, help <function> shows docs |
v1.16.2 — whats_new_v116.fk
Theme: System Integration & Scripting Power — shell commands, environment loading, infinite loops, nil-coalescing assign, richer hash and string tools, and three new stitches for email, CLI parsing, and caching.
| Feature | Summary |
|---|---|
shell(cmd) |
Run an OS command — returns {stdout, stderr, exit_code, ok} |
dotenv(path) |
Load a .env file into the process environment — returns hash of loaded vars |
loop do...end |
Infinite loop, exits only via break — cleaner than while true |
\|\|= |
Nil-coalescing assign — config \|\|= load_defaults() |
Hash#transform_values |
New hash with same keys, block-transformed values |
Hash#transform_keys |
New hash with block-transformed keys, same values |
Hash#deep_merge |
Recursive nested hash merge — unlike shallow .merge / \| |
String#scan |
Extract all regex matches as a vector |
frankiemail stitch |
Send email via SMTP — plain text, HTML, CC/BCC — zero deps |
frankiecli stitch |
CLI argument parsing — flags, options, subcommands — zero deps |
frankiecache stitch |
In-memory TTL cache — set/get/delete/clear/size — zero deps |
v1.15 — whats_new_v115.fk
Theme: Language Polish & Developer Ergonomics — cleaner syntax, more powerful stdlib, and two new web stitches.
| Feature | Summary |
|---|---|
Ternary operator |
x > 0 ? "pos" : "neg" — right-associative, valid in any expression position |
Keyword default params |
def connect(host, port: 5432, ssl: true) — : syntax now accepted alongside = |
Splat in multi-assign |
a, *rest = [1,2,3] and first, *mid, last = arr — capture remaining elements |
const keyword |
Explicit constant declaration — reassignment warns and preserves original value |
fn.(args) everywhere |
Lambda call syntax now works in all contexts, not just web middleware |
json_encode |
Preferred name for json_dump; accepts pretty: true |
hmac_sign / hmac_verify |
Promoted from internal _fk_* to public stdlib — signed tokens and webhook verification |
base64_encode / base64_decode |
Standard Base64 encode/decode — useful for HTTP Basic Auth headers |
String#format |
Named placeholder substitution: "Hello, {name}!".format({name: "Alice"}) |
.chars / .bytes |
Unicode-aware character vector and byte values from a string |
| Path helpers | path_join, path_dirname, path_basename, path_extname, path_stem, path_absolute |
| Date arithmetic | Date objects support + / - (days) and comparison operators |
zip_with block |
a.zip_with(b) do \|x, y\| x + y end — element-wise combination |
assert_not_nil / assert_in |
New test assertions for nil checks and membership |
req.query_int/float/bool |
Typed query parameter helpers with defaults |
frankieauth stitch |
HTTP Basic Auth + Bearer token auth — zero dependencies |
frankieratelimit stitch |
Per-IP sliding-window rate limiting — zero dependencies |
frankiec check |
Parse without executing — useful in CI |
frankiec new |
Scaffold a complete project layout |
frankiec watch |
Official file watcher — re-run on save |
v1.14 — whats_new_v114.fk
Theme: Frankie for real web apps — concurrency, templates, signed cookies, middleware, static files, and two language upgrades that make working with data cleaner everywhere.
| Feature | Summary |
|---|---|
spawn { } |
Run a block in a background thread — response goes out immediately, work continues behind the scenes |
timeout(n) { } |
Kill a block that exceeds n seconds — raises TimeoutError, wrap in begin/rescue for graceful fallback |
Async routes |
app.get_async / app.post_async etc. — non-blocking handlers, use await inside for slow I/O |
Middleware stack |
app.use do |req, next_fn| — chain auth, logging, and rate-limiting; call next_fn.(req) to continue or return early to short-circuit |
Static file serving |
app.static("./public") — serve a directory at /; app.static("./assets", "/static") for a URL prefix |
frankietemplate |
Mustache-compatible template stitch — {{ var }}, {{{ raw }}}, {{# section }}, {{^ inverted }}, {{> partial }}, {{! comment }} |
frankiecookie |
HMAC-signed cookies via Python's hmac stdlib — set_signed_cookie / get_signed_cookie returns nil if tampered |
Hash destructuring |
{name, age} = user — pull symbol keys directly into variables; missing keys become nil |
Shape pattern matching |
case user when {role: "admin"} — when now accepts hash literals, matches on subset of keysfrankiec new scaffold |
Global stitch install |
install.py now correctly copies all stitches to ~/.frankie/stitches/ and lists each file installed |
page_links docs |
Full web pagination example added — paginate + page_slice + page_links + frankietemplate working together |
v1.13.1 — whats_new_v1131.fk
Theme: Gap closers — no new syntax, everything real programs needed and didn't have.
| Feature | Summary |
|---|---|
frankiestring v2 |
Rewritten stitch: pad_left, pad_right, truncate, slugify, word_wrap, indent_lines — replaces clunky lfill/rfill API |
Vector .sum do \|x\| |
Block form now works — projected sum without a two-step .map + sum |
Vector .flat_map do \|x\| |
Multi-line block bodies now parse correctly |
assert_approx_eq(a, b, delta, msg) |
Float comparison in tests with configurable delta (default 0.001) |
run_tests() |
Now a public stdlib function — callable from any .fk file, not just frankiec test |
session(req, resp) |
Cookie-backed session hash — read, mutate, .save(). Zero server state, single JSON cookie _fk_session |
frankiec fmt blank lines |
Intentional blank lines between statement groups inside function bodies now preserved |
frankiec fmt multi-line threshold |
Hashes/vectors whose inline form exceeds 60 chars auto-expand to one element per line |
frankiec fmt idempotency |
Running fmt --write twice now produces identical output — safe for pre-commit hooks and CI |
Heredoc in do...end blocks |
Fixed lexer bug — heredocs now work anywhere a string expression is valid |
Hash.each do \|k, v\| |
Two-parameter block iteration confirmed and end-to-end tested |
Symbol key round-trip in fmt |
{host: "x"} no longer becomes {"host": "x"} after formatting |
v1.13 — whats_new_v113.fk
Theme: Stitches — a zero-dependency, zero-registry package system.
| Feature | Summary |
|---|---|
stitch "name" keyword |
Load a package by name — resolves from ./stitches/ then ~/.frankie/stitches/ |
frankieforms |
Form field validation — required, min_length, max_length, email, numeric, alpha, matches_pattern |
frankietable |
ASCII table rendering from a vector of hashes — table(rows) / table(rows, cols) |
frankiecolor |
ANSI color helpers — red, green, yellow, bold, success, error, warn, info, colorize, strip_color |
frankiepager |
Pagination math — paginate(opts), page_slice(items, page, per_page), page_links(pager, url_template) |
frankieconfig |
Layered config loading: defaults → JSON file → env vars → overrides, with type coercion |
frankiestring |
String utilities stitch (v1, superseded by v2 in v1.13.1) |
? in function names |
def even?(n) now works — ? compiled transparently to _q in generated Python |
v1.12 — whats_new_v112.fk
Theme: Filling stdlib gaps, fixing error handling, tooling polish.
| Feature | Summary |
|---|---|
String .gsub with block |
Transform each regex match via a block — "hello".gsub("[aeiou]") do \|m\| m.upcase end |
Hash .map_hash |
Transform a hash into a new hash — block returns [new_key, new_value] |
round(x, n) |
Round to n decimal places — round(3.14159, 2) → 3.14 |
Vector .product(other) |
Cartesian product — [1,2].product([3,4]) → [[1,3],[1,4],[2,3],[2,4]] |
String .chars |
Promoted to first-class documented method — chains into iterators |
each_with_object + Hash |
Hash accumulator now explicitly documented and tested |
assert_match / assert_nil |
Two new test runner assertions |
rescue FileNotFoundError |
file_read and file_lines now raise the correct type |
frankiec watch |
Re-run on save — frankiec watch main.fk |
frankiec repl --no-banner |
Headless REPL for scripts and pipes |
| Friendlier runtime errors | Type errors now say "Integer and String", not Python internals |
v1.11 — whats_new_v111.fk (in docs/13_v111_features.md)
Theme: Ergonomics — removing paper cuts, making the common case obvious.
| Feature | Summary |
|---|---|
| Implicit return | Last expression in a function is returned automatically |
Inline if expression |
grade = if score >= 90 then "A" else "B" end |
String .replace(old, new) |
The method new users always reach for first |
String .format(hash) |
"Hello, {name}!".format({name: "Alice"}) |
.zip_with do \|a, b\| |
Pair-wise transform two vectors in one pass |
| Multiple return values | lo, hi = min_max(data) — destructuring from functions |
frankiec check boxed errors |
Parse errors now use the same box as runtime errors |
| REPL multi-line history | ↑ recalls a full def...end block |
frankiec fmt heredoc support |
Heredoc bodies preserved verbatim during formatting |
String .delete(chars) |
"hello".delete("l") → "heo" — documented |
v1.10 — whats_new_v110.fk
Theme: Expressiveness — more ways to write less.
| Feature | Summary |
|---|---|
String * n / Vector * n |
"ha" * 3 → "hahaha" · [0] * 5 → [0,0,0,0,0] |
Heredoc <<~TEXT |
Multi-line strings with auto indent-stripping and interpolation |
times() standalone |
times(5) do \|i\| alongside 5.times do |
flatten(depth) |
Flatten exactly n levels — flatten(1) vs deep flatten |
map_with_index |
v.map_with_index do \|x, i\| |
pp — pretty print |
pp({host: "localhost", port: 3000}) |
encode / decode |
"hi".encode → [104, 105] · [104, 105].decode → "hi" |
| Exit codes | exit(0) / exit(1) — propagated to shell |
--help flag |
frankiec run --help etc. |
v1.9 — whats_new_v19.fk
Theme: Safety and tooling.
| Feature | Summary |
|---|---|
Hash .dig |
config.dig("db", "host") — safe nested access, returns nil |
zip() standalone |
zip([1,2,3], ["a","b","c"]) → [[1,"a"],[2,"b"],[3,"c"]] |
| Record types | record Point(x, y) — named data objects built on Hash |
frankiec fmt |
AST-based auto-formatter with --write and --check |
frankiec docs |
Extract ## doc-comments to Markdown |
| REPL readline + history | Arrow keys, Ctrl+R, tab completion, persistent ~/.frankie_history |
.env auto-loading |
.env in the project root is loaded automatically at startup |
v1.8 — whats_new_v18.fk
Theme: Functional programming and collection power.
| Feature | Summary |
|---|---|
| Lambdas | ->(x) { x * 2 } — storable, passable first-class functions |
Hash merge \| |
h1 \| h2 — right wins on conflict, chains naturally |
group_by |
Bucket elements into a hash of arrays by block result |
each_slice(n) |
Iterate in non-overlapping chunks |
each_cons(n) |
Iterate with a sliding window |
v1.7 — whats_new_v17.fk
Theme: Safety and real-world utility.
| Feature | Summary |
|---|---|
Nil safety &. |
name&.upcase returns nil instead of crashing |
template(str, hash) |
{{key}} placeholder substitution |
| File system ops | file_mkdir, dir_exists, dir_list, file_copy, file_rename |
assert_raises_typed |
Test that a specific error type is raised |
v1.6 — whats_new_v16.fk
Theme: Control flow completeness.
| Feature | Summary |
|---|---|
| Compound assignment | +=, -=, *=, /=, //=, **=, %= |
| Typed rescue | rescue ZeroDivisionError e — catch specific error types |
.find / .detect |
First element matching a block condition |
frankiec test |
Built-in test runner |
v1.5 — whats_new_v15.fk
Theme: Loop control, randomness, and collection utilities.
| Feature | Summary |
|---|---|
next |
Skip to next iteration — like continue |
break |
Exit a loop early |
break value |
Exit with a result — result = loop.break n * 10 |
| Constants | UPPER_CASE — warn on reassignment |
rand_int, rand_float |
Random number functions |
shuffle, sample |
Random collection operations |
sleep(n) |
Pause execution |
sort_by |
Sort by computed key |
min_by, max_by, sum_by |
Aggregate by key |
unzip |
Split vector of pairs into two vectors |
v1.4 — whats_new_v14.fk
Theme: Built-in web server.
| Feature | Summary |
|---|---|
| Web server | web_app() — Sinatra-style routing |
| Route definitions | .get, .post, .put, .delete, .patch |
| Path parameters | /users/:id → req.params["id"] |
| Query parameters | req.query["page"] |
| JSON body | req.json — auto-parsed |
| Before/after filters | app.before do, app.after do |
| Response helpers | html_response, json_response, redirect, halt |
v1.3 — whats_new_v13.fk
Theme: External data and project structure.
| Feature | Summary |
|---|---|
| JSON | json_read, json_write, json_parse, json_dump |
| CSV | csv_read, csv_write, csv_parse, csv_dump |
| DateTime | now(), today(), date_parse(), date_from() |
| HTTP client | http_get, http_post, http_put, http_delete |
frankiec new |
Project scaffolding |
v1.2 (no whats_new file)
Theme: Database and multi-file programs.
| Feature | Summary |
|---|---|
| SQLite built-in | db_open, db.query, db.insert, db.exec, transactions |
require |
Load other .fk files — each loaded at most once |
v1.1 — whats_new_v11.fk
Theme: Collection power.
| Feature | Summary |
|---|---|
select / reject |
Filter a vector by a condition |
reduce / inject |
Fold a vector into a single value |
any? / all? / none? |
Boolean tests across a collection |
each_with_object |
Iterate with a shared accumulator |
take, drop, chunk, tally, compact |
Collection utilities |
flat_map, zip |
Flattening and pairing |
case / when |
Pattern matching on values |
| Destructuring assignment | a, b, c = [1, 2, 3] |
| New string methods | .chomp, .chop, .center, .ljust, .rjust, .squeeze, .tr |
count with block |
Count elements matching a condition |
v1.0 (initial release)
The foundation: variables, strings with #{} interpolation, integers, floats, booleans, nil, vectors, hashes, if/elsif/else/unless, while/until/for, functions with default params, begin/rescue/ensure, raise, regex (matches, match_all, sub, gsub, =~), file I/O (file_read, file_write), R-style statistics (mean, stdev, median, sum), vectorised arithmetic, the pipe operator |>, seq, linspace, the REPL, and frankiec run/build/check.