Kaffeine uses a plugin style approach, with a core/standard stack (order is important)
This is an example taken from production code. It show most of Kaffeine's features:
Edge::add = (nick, name, complete, opts={}) {
@client.select 15
user = User.find! {id: nick}
puzzle = Puzzle.find! {name: name}
err = client.set! "#{user}:#{puzzle}"
if !err, complete()
}
Allows function calls with callbacks to be unwrapped via a ! postfix. E.g:
fish = $.get!('/fish')
$("stomach").append(fish)
ok = stomach.save!()
meal.complete = ok
This is super useful for simplifying nested asynchronous calls (esp with nodejs)
Provide the @ alias for 'this'. E.g:
@legs = legs @color = color
In the case of an unwrapped function, @ will be rewritten to refer to the original this, for convenience. Use this to refer to the actual this
Fish.prototype.eat = {
@food = getFood!()
@stomach.ingest! @food
poop = @stomach.digest! @food
this.next(poop)
}
provides support for omitting the var keyword: the variables will be automagically defined in the closest relevant closure. E.g.
x = null
{
x = 1
y = 2
}
Provide optional brackets for function calls. E.g.
remove eggs.shell mix eggs, milk.off ? milk : null outer inner innermost
keywords such as "for", or "if" can omit their brackets (as long as the statement doesn't become amiguous). The brackets are inserted either before a newline, a left brace '{' or a comma (for one liners)
for i in A
run A[i]
if name == "john", return false
while we_have_time() { run tasks }
Allows for multiline strings:
var html = " <body> <h1>SOY SAUCE</h1> </body> "
Maintains new lines --- but can be suppressed with the \ character (which provides parity with normal javascript):
var html = "\ <body>\ <h1>SOY SAUCE</h1>\ </body>\ "
Allows an 'of' operator for looping through arrays:
for(x of [7,3,4]) sum += x
An optional second parameter will refer to the key:
for(x, i of [7,3,4]) sum += i
Also allows an optional second parameter for the in keyword:
for(key, val in A) zip += "#key:#val"
provides ruby style string interpolation via #{}
letter = "Dear #{name},
I am writing to you to inform you of #{purpose}
Kind Regards
#{sender}
"
the last statement of a function will be automagically returned. E.g.
getName = { @name }
This will only work for variables, objects and functions. I.e. an final if statement will result no return value
provides the # shortcut for referring to the first argument in a function. Additionally, #n refers to the nth argument (n >= 0). Useful for terse function definitions, e.g:
square = { #*# }
times = { #*#1 }
the function keyword can be optionally omitted, along with empty argument lists.
ok = (timeout) {
sendNote()
setTimeout { run() }, timeout
return true
}
Note {} could be a function or an object, so to avoid ambiguity, it's defined to be an object. To express an empty function, use one of the following forms:
{;}
{null}
function() { }
Provides an alternative calling method than can be used for easily chaining (UNIX style passing).
result = input | fn args
Chaining input to output:
result = input | fn a, b | fn2 c | fn3 d
For example, it is very useful for ruby style enumeration chaining without using prototypes, and other utilities
| = require "pipe_utils"
People | map { #.name } | detect { #.length > 3 }
opts = opts | extend default
5 | times { if(!send()) return false }
names | asyncMap (name, fn) {
user = User.find! {name: name}
fn(user)
}, complete
2 extra assignment operators, ||= and .=
location.href .= replace("?old", "?new")
name .= toUpperCase()
opts ||= {}
Also an extend operator <-
a <- b
options = options <- { size: "small", num: 10}
Allows defaults for null or undefined arguments. Nb - uses non strict comparison with null
(x=1, r=[], a=3) {
x + 4
}
npm install kaffeine