Kapusta
Kapusta is a Lisp for the Ruby runtime.
It is inspired by Fennel. Kapusta aims to bring the simplicity and joy of Lisp to Ruby. Where Fennel uses Lua's stdlib and runtime, Kapusta uses Ruby's.
For more information about Kapusta, see the official Fennel documentation and tutorials, but replace Lua with Ruby.
Features
- Compiles to readable Ruby.
- Compiled
.rbfiles don't depend on Kapusta. Run with plainruby, or load.kapfiles at runtime viarequire 'kapusta'. - Two-way Ruby interop.
Install
gem install kapusta
It installs three executables:
kapustakapfmtkapusta-ls
Use
kapusta examples/fizzbuzz.kap
or
exe/kapusta examples/fizzbuzz.kap
or
kapusta --compile examples/fizzbuzz.kap > examples/fizzbuzz.rb
ruby examples/fizzbuzz.rb
For mruby 3 compatible output, such as DragonRuby, use:
kapusta --compile --target=mruby3 examples/match.kap > examples/match-mruby3.rb
Use from Ruby
Ruby can require a .kap file and use it directly.
require 'kapusta'
Kapusta.require('./bank-account', relative_to: __FILE__)
account = BankAccount.new('Ada', 100)
See examples/bank-account.kap and examples/use_bank_account.rb.
Examples
See examples/ and examples-compiled/.
(fn ack [m n]
(if (= m 0) (+ n 1)
(= n 0) (ack (- m 1) 1)
(ack (- m 1) (ack m (- n 1)))))
(print (ack 2 3))
(print (ack 3 3))
Compiles to:
def ack(m, n)
if m == 0
n + 1
elsif n == 0
ack(m - 1, 1)
else
ack(m - 1, ack(m, n - 1))
end
end
p ack(2, 3)
p ack(3, 3)
Comparison with Fennel
Kapusta keeps most core Fennel forms. The main differences come from Ruby's runtime and object model.
| Fennel | Kapusta |
|---|---|
| Lua stdlib | Ruby stdlib |
:foo is a Lua string |
:foo is a Ruby symbol |
(. xs 1) is the first element |
(. xs 0) is the first element |
string.format, table.insert, etc. |
use Ruby methods and stdlib instead |
values uses Lua multiple returns |
values lowers to a Ruby array, usually destructured |
(print x) is Lua's print (bare) |
(print x) is Ruby's p (inspect-style) |
with-open, tail! |
not provided |
Kapusta-specific additions:
moduleandclassfor Ruby host structure, including file-header forms(end)closes a bodyless file-header(defn name ...)or(fn class.name ..)ivaror@var/cvaror@@var/gvaror$vartry/catch/finallyplusraisefor exceptions(ruby "...")raw host escape hatch- pass Ruby keyword arguments by ending a call with a symbol-keyed hash:
(File.open path "r" {:encoding "UTF-8"}) - pass a Ruby block by ending a call with a
(fn ...)or#(...)literal:(File.open path "r" (fn [io] (: io :read)))
Format
kapfmt --fix examples/fizzbuzz.kap
LSP
Use kapusta-ls in the editor of your choice.
Syntax highlight
For Vim, you can use vim-syntax/.