⚑ It's alive!

_____               _    _
    |  ___| __ __ _ _ __ | | _(_) ___
    | |_ | '__/ _` | '_ \| |/ / |/ _ \
    |  _|| | | (_| | | | |   <| |  __/
    |_|  |_|  \__,_|_| |_|_|\_\_|\___| 

The Frankie Language

A procedural programming language lovingly stitched together from Ruby, Python, R, and Fortran. Zero dependencies. Proudly monstrous.

Ruby syntax Python semantics R statistics Fortran power
Get Started β†’ Download v1.6 β˜… Star on GitHub

β–Ό scroll

What it can do

Everything you need.
Nothing you don't.

Proudly procedural β€” functions, data, loops, logic. No classes, no self, no inheritance. Runs on Python 3.10+ with zero external dependencies.

βž•

Compound Assignment v1.6

+= -= *= /= //= **= %= β€” all operators, including Fortran-style integer division and exponentiation. Works on variables and vector elements.

πŸ›‘οΈ

Typed Rescue v1.6

rescue ZeroDivisionError e, rescue TypeError e β€” multiple typed clauses on one begin…end block. Catch exactly what you mean.

πŸ”

.find / .detect v1.6

Return the first element where the block is true, or nil. Works on any vector including vectors of hashes. Chains naturally with .select, .sort_by, and the pipe operator.

πŸ§ͺ

frankiec test v1.6

Built-in test runner. assert_true, assert_eq, assert_neq, assert_raises β€” no imports. Live βœ“ / βœ— output per assertion. Exits 1 on failure for CI.

πŸ“Š

R-style Statistics

Built-in mean, stdev, median, variance. Vectorised arithmetic. Pipe operator |> for clean data pipelines.

🌐

Built-in Web Server

Sinatra-style routing with web_app(). Path params, JSON bodies, before/after filters, custom 404 β€” zero external deps.

πŸ—„οΈ

SQLite Built-in

Open databases, run queries, insert rows with clean Frankie syntax. No ORM, no driver, no setup required.

πŸ”—

HTTP, JSON & CSV

Make HTTP requests, parse JSON and CSV, work with DateTime β€” all in the stdlib, all zero-dependency.

🎲

Randomness

rand, rand_int, rand_float, shuffle, sample, rand_seed β€” everything for games and simulations.

πŸ”

Rich Iterators

.map, .select, .find, .sort_by, .reduce, .min_by, .max_by with do |x| end blocks.

⏭️

Loop Control

next to skip iterations, break to exit early, break value to exit with a result. Postfix forms work too.

πŸ”’

Constants

UPPER_SNAKE_CASE names are constants. Reassignment warns and preserves the original value automatically.

The language

Familiar. Expressive.
A little monstrous.

compound.fk v1.6
# Compound assignment operators
score = 0
score += 10   # score = 10
score *= 2    # score = 20
score -= 3    # score = 17
score **= 2   # score = 289 (Fortran!)
score %= 100  # score = 89

# Works on vector elements too
v = [10, 20, 30]
v[0] += 5     # [15, 20, 30]
v[2] //= 4    # [15, 20, 7]

# Idiomatic loop accumulation
total = 0
[3, 7, 2, 9].each do |n|
  total += n
end
puts total  # 21
rescue.fk v1.6
# Typed rescue clauses
def safe_divide(a, b)
  begin
    return a // b
  rescue ZeroDivisionError e
    puts "division by zero"
    return 0
  rescue TypeError e
    puts "wrong type: #{e}"
    return 0
  rescue e
    puts "unexpected: #{e}"
    return 0
  ensure
    puts "always runs"
  end
end

puts safe_divide(10, 2)   # 5
puts safe_divide(10, 0)   # 0
find.fk v1.6
nums = [3, 7, 2, 11, 4, 9]

# First element matching the block
big = nums.find do |n|
  n > 8
end
puts big  # 11

# .detect is an alias
even = nums.detect do |n|
  n % 2 == 0
end
puts even  # 2

# Returns nil when nothing matches
huge = nums.find do |n|
  n > 100
end
p huge  # (Nil) nil
test.fk v1.6
# frankiec test β€” built-in test runner
# No imports needed. Run: frankiec test

x = 10
x += 5
assert_eq(x, 15, "+= works")

result = [1, 3, 5, 7].find do |n|
  n > 4
end
assert_eq(result, 5, ".find works")

caught = nil
begin
  y = 1 // 0
rescue ZeroDivisionError e
  caught = "zero"
end
assert_eq(caught, "zero", "typed rescue")

# βœ“  += works
# βœ“  .find works
# βœ“  typed rescue
# βœ“  All 3 test(s) passed  (1.4ms)
stats.fk
# R-style stats + pipe operator
data = [23, 45, 12, 67, 34, 89]

puts mean(data)    # 45.0
puts stdev(data)   # 27.9
puts median(data)  # 39.5

data |> sum |> puts  # 270

top3 = data.sort_by do |x|
  -x
end.take(3)
puts top3  # [89, 67, 45]
iterators.fk
words = ["banana", "fig", "cherry"]

long = words.select do |w|
  w.length > 4
end  # [banana, cherry]

# next / break
[1,2,3,4,5,6].each do |n|
  next if n % 2 == 0
  break if n > 5
  puts n  # 1 3 5
end

# Constants
MAX_SIZE = 100
PI       = 3.14159

Web server

Build APIs in Frankie.
No framework required.

Sinatra-inspired routing built into the language. Define routes with blocks, handle JSON, path params, filters and custom 404s β€” all zero external dependencies.

webapp.fk
app = web_app()

app.get("/") do |req|
  html_response("<h1>Hello from Frankie! 🧟</h1>")
end

app.get("/greet/:name") do |req|
  name = req.params["name"]
  response("Hello, #{name}!")
end

app.get("/api/status") do |req|
  json_response({status: "ok", version: "1.6"})
end

store = {notes: []}

app.post("/notes") do |req|
  data = req.json
  if data == nil
    return halt(400, "Expected JSON")
  end
  note = {id: length(store["notes"]) + 1, text: data["text"]}
  store["notes"].push(note)
  json_response(note, 201)
end

app.not_found do |req|
  halt(404, "No route for #{req.path}")
end

app.run(3000)  # 🧟 Frankie web server running on http://0.0.0.0:3000
Response helpers: response(body)   html_response(html)   json_response(data)   redirect(url)   halt(status, body)

The donors

Stitched from four
legendary languages.

Ruby
  • do…end syntax
  • if / unless
  • String interpolation
  • begin / rescue
  • Iterators & blocks
  • Postfix conditions
Python
  • Clean semantics
  • Dict / list model
  • Execution model
  • Rich data types
  • Standard library
  • Zero-dep philosophy
R
  • Vectors
  • Pipe operator |>
  • mean / stdev / median
  • seq / linspace
  • Vectorised arithmetic
  • Statistical mindset
Fortran
  • do…while loops
  • Integer division //
  • Exponentiation **
  • Numeric heritage
  • Loop pragmatism
  • Computational roots

Get started

Up and running
in 30 seconds.

Requirements: Python 3.10+. That's it.

01
# Clone the repo
git clone https://github.com/atejada/Frankie && cd Frankie
02
# Install (creates bin/frankiec)
python3 install.py
export PATH="/path/to/Frankie/bin:$PATH"
03
# Run a program, launch the REPL, or run your tests
frankiec run examples/hello.fk
frankiec repl
frankiec test
VersionHighlightsStatus
v1.6Compound assign +=/-=/*= etc., typed rescue, .find/.detect, frankiec testLatest
v1.5next / break, constants, randomness, sort_by, sleep, unzipStable
v1.4Built-in web server, routes, JSON API, filters, custom 404Old
v1.3JSON, CSV, DateTime, HTTP client, project scaffoldingOld
v1.2SQLite built-in, transactions, multi-file with requireOld
v1.1Rich iterators, REPL, case/when, destructuringOld
v1.0Initial release β€” core language, stdlib, error handlingOld