coffeescript essence
TRANSCRIPT
ESSENCE:
var BankAccount = function(balance) { return function(cmd,amount) { amount || (amount = 0); if(cmd == "withdraw") return BankAccount(balance - amount) else if(cmd == "deposit") return BankAccount(balance + amount) else if(cmd == "balance") return balance.toFixed(2) else return "What kind of person would try to " + cmd + " a bank account?" }};
var BankAccount = function(balance) { balance || (balance = 0); return function(cmd,amount) { amount || (amount = 0); if(cmd === "withdraw") return BankAccount(balance - amount) else if(cmd === "deposit") return BankAccount(balance + amount) else if(cmd === "balance") return balance.toFixed(2) else return "What kind of person would try to " + cmd + " a bank account?" }};
λ
ACCIDENT
var BankAccount = function(balance) { balance || (balance = 0); return function(cmd,amount) { amount || (amount = 0); if(cmd === "withdraw") return BankAccount(balance - amount); else if(cmd === "deposit") return BankAccount(balance + amount); else if(cmd === "balance") return balance.toFixed(2); else return "What kind of person would try to " + cmd + " a bank account?"; }};
ESSENCE
BankAccount = (balance = 0) -> (cmd, amount = 0) -> if cmd == "withdraw" then BankAccount balance - amount else if cmd == "deposit" then BankAccount balance + amount else if cmd == "balance" then balance.toFixed 2 else "What kind of person would try to #{cmd} a bank account?"
var winners = function(race) { race || (race = "today's race"); return "Results of " + race ":\n" + [].slice.call(arguments,1).join("\n");};
var keywordArgs = function(args) { foo = args.foo; bar = args.bar; };
winners = (race = "today's race",winners...) -> "Results of #{race}:\n#{ winners.join("\n") }"
keywordArgs = ({foo,bar}) ->
The Zen of Python, PEP: 20
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Readability counts.
There should be one obvious way to do it.
// null guardpossiblyNull && possiblyNull.foo;
// chained comparisonvar valid = foo > 5 && foo < 10;
wasDisplayed = this.displayed;this.displayed = this.hidden;this.hidden = wasDisplayed;
possiblyNull?.foo
valid = 5 < foo < 10
[@hidden,@displayed] = [@displayed,@hidden]
for (var key in anObject) { if(anObject.hasOwnProperty(key) { value = anObject[key]; console.log(key, value); }}
for own key, value of anObject console.log key, value
var transformed = [];for (var index=0, length = listOfThings.length; index < length; index++) { transformed.push(transform(listOfThings[index]));};
var squared = list.map(function(item) { return item * item; });
transformed = (transform item for item in listOfThings)
squared = (item * item for item in list)
squared = list.map (item) -> item * item
var Widget = function(el) { this.sayHi = function() { this.el.show() }; this.el = el; this.el.click(this.sayHi.bind(this));};
var Widget = function(el) { self = this; this.sayHi = function() { self.el.show() }; this.el = el; this.el.click(this.sayHi);};
Widget = (@el) -> @sayHi = => @el.show() @el.click @sayHi
class Widget constructor: (@el) -> @el.click @sayHi sayHi: => @el.show()
var Animal = Actor.extend({ initialize: ... override: function() { this.__super__.override.apply(this,arguments) }});_.extend Animal.prototype, ai.instinctive;
dojo.provide("my.actors.Animal");dojo.declare("my.actors.Animal",[Actor,ai.instinctive],{ constructor: ... override: function() { this.inherited(arguments); }});
var Animal = new JS.Class(Actor,{ init: ... override: function() { this.callSuper(arguments) }});Animal.include(ai.instinctive);
class Animal extends SuperClass constructor: -> override: -> super _.extend Animal::, ai.instinctive
"" == "0" // false0 == "" // true0 == "0" // truefalse == "false" // falsefalse == "0" // truefalse == undefined // falsefalse == null // falsenull == undefined // true" \t\r\n" == 0 // true
http://bonsaiden.github.com/JavaScript-Garden/
var values = { foo: 1, bar: 2,};values.foo = 3;
var maxSize = 2.pow(8);
var alerter = function(value) { alert(value);}(5).times(function() { alerter("hello")});
var greeting = "hello"(10).times(function() { alert(greeting)});
HALTING PROBLEMS
+-----------------------------------------------------+--------------+-------------------+----------+---------------+| File | Coffee Lines | Coffee Characters | JS Lines | JS Characters |+-----------------------------------------------------+--------------+-------------------+----------+---------------+| app/coffee/plv/accessors.coffee | 17 | 320 | x 1.9 | x 1.8 || app/coffee/plv/clock.coffee | 30 | 671 | x 1.6 | x 1.6 || app/coffee/plv/collection.coffee | 38 | 1089 | x 1.9 | x 1.4 || app/coffee/plv/comparison.coffee | 13 | 192 | x 1.5 | x 1.6 || app/coffee/plv/config.coffee | 24 | 597 | x 1.3 | x 1.1 || app/coffee/plv/console.coffee | 8 | 162 | x 1.9 | x 1.7 || app/coffee/plv/controller.coffee | 1 | 41 | x 3.0 | x 1.5 || app/coffee/plv/controllers/main.coffee | 12 | 371 | x 1.8 | x 1.2 || app/coffee/plv/ext/backbone.coffee | 16 | 514 | x 1.9 | x 1.6 || app/coffee/plv/ext/class.coffee | 10 | 288 | x 3.3 | x 2.0 || app/coffee/plv/ext/core.coffee | 126 | 2178 | x 1.7 | x 1.6 || app/coffee/plv/ext/date.coffee | 57 | 1206 | x 1.8 | x 1.5 || app/coffee/plv/layers/core.coffee | 1 | 67 | x 1.0 | x 1.0 || app/coffee/plv/model.coffee | 115 | 3194 | x 1.9 | x 1.5 |....| app/coffee/plv/models/entry_handler.coffee | 10 | 302 | x 1.9 | x 1.2 || app/coffee/plv/models/event.coffee | 15 | 399 | x 1.8 | x 1.6 || app/coffee/plv/models/football/point_in_game.coffee | 113 | 2262 | x 1.5 | x 1.4 || app/coffee/plv/models/football.coffee | 35 | 1272 | x 1.9 | x 1.4 || app/coffee/plv/models/game.coffee | 2 | 71 | x 1.5 | x 1.3 |...| app/coffee/plv/polling.coffee | 30 | 560 | x 1.9 | x 1.8 || app/coffee/plv/procs/boot.coffee | 40 | 1000 | x 1.3 | x 1.1 || app/coffee/plv/share.coffee | 15 | 702 | x 2.1 | x 1.2 || app/coffee/plv/spec/factory.coffee | 194 | 4686 | x 1.1 | x 1.2 || app/coffee/plv/spec/fake_game.coffee | 211 | 5742 | x 1.7 | x 1.2 || app/coffee/plv/spec/fake_server.coffee | 44 | 2360 | x 2.2 | x 1.3 || app/coffee/plv/sync.coffee | 12 | 352 | x 2.0 | x 1.3 || app/coffee/plv/ui.coffee | 42 | 903 | x 1.6 | x 1.7 || app/coffee/plv/view.coffee | 9 | 299 | x 1.6 | x 1.3 || app/coffee/plv/views/avatar_picker.coffee | 12 | 385 | x 1.6 | x 1.4 || app/coffee/plv/views/backup_players.coffee | 5 | 142 | x 1.6 | x 1.3 || app/coffee/plv/views/backup_toggle.coffee | 25 | 729 | x 1.4 | x 1.6 || app/coffee/plv/views/big_game.coffee | 71 | 2623 | x 1.3 | x 1.3 |...| app/coffee/plv/views/loading.coffee | 42 | 1067 | x 1.0 | x 1.3 || app/coffee/plv/views/main.coffee | 336 | 9290 | x 1.3 | x 1.3 || app/coffee/plv/views/message.coffee | 39 | 954 | x 1.8 | x 1.6 || app/coffee/plv/views/nav.coffee | 44 | 931 | x 1.4 | x 1.3 |....| app/coffee/plv/views/sounds.coffee | 85 | 2239 | x 1.5 | x 1.4 || app/coffee/plv/views/standings.coffee | 78 | 2501 | x 1.5 | x 1.4 || app/coffee/plv/views/tutorial.coffee | 81 | 2817 | x 1.7 | x 1.4 || app/coffee/plv/web.coffee | 18 | 461 | x 2.7 | x 2.2 |+-----------------------------------------------------+--------------+-------------------+----------+---------------+| Total | 3552 | 98736 | 5563 | 134774 || Diff | | | + 2011 | + 36038 |+-----------------------------------------------------+--------------+-------------------+----------+---------------+| Ratios JS/Coffee | | | x 1.566 | x 1.365 |+-----------------------------------------------------+--------------+-------------------+----------+---------------+
+------------------+--------------+-------------------+----------+---------------+| | Coffee Lines | Coffee Characters | JS Lines | JS Characters |+------------------+--------------+-------------------+----------+---------------+| Total | 3552 | 98736 | 5563 | 134774 || Diff | | | + 2011 | + 36038 |+------------------+--------------+-------------------+----------+---------------+| Ratios JS/Coffee | | | x 1.566 | x 1.365 |+------------------+--------------+-------------------+----------+---------------+
$ ./bin/coffee -te 'console.log "hello world"'[IDENTIFIER console] [. .] [IDENTIFIER log] [CALL_START (] [STRING "hello world"] [CALL_END )] [TERMINATOR \n]
TOKENS
$ ./bin/coffee -en 'console.log "hello world"'Block Call Value "console" Access "log" Value ""hello world""
NODES
GOAL
coffee> 300 <=> 500-1
coffee> arrogant = {">": -> true}{ '>': [Function] }
coffee> arrogant > Infinitytrue
coffee> [1,4,2,3,5,6,7].map (val) -> val <=> 5[ -1, -1, -1, -1, 0, 1, 1 ]
LEXER.COFFEE
OPERATOR = /// ^ ( ?: [-=]> # function+ | <=> # our new op | [-+*/%<>&|^!?=]= # compound assign / compare... # Comparison tokens.-COMPARE = ['==', '!=', '<', '>', '<=', '>=']+COMPARE = ['<=>', '==', '!=', '<', '>', '<=', '>=']
GRAMMAR.COFEE
+ isComparison: ->+ @operator in ['<', '>', '>=', '<=', '===', '!==', '<=>'] - code = @first.compile(o, LEVEL_OP) + ' ' + @operator + ' ' + - @second.compile(o, LEVEL_OP)+ code = if @isComparison()+ utility("comparison") + "(" + @first.compile(o, LEVEL_OP) + ", " ++ @second.compile(o, LEVEL_OP) + ", '#{@operator}')"+ else+ @first.compile(o, LEVEL_OP) + ' ' + @operator + ' ' ++ @second.compile(o, LEVEL_OP) if o.level <= LEVEL_OP then code else "(#{code})"
GRAMMAR.COFFEE
+ comparison: -> """+ function(a,b,op) {+ if(!a || !b || !a[op]) {+ switch(op) {+ case "===":+ return a === b;+ case ">=":...+ case "<=>":+ if(a === b) return 0;+ return a > b ? 1 : -1;+ default:+ throw "Unknown operator: " + op;+ }+ } else {+ return a[op](b);+ }+ }+ """
ALL TOGETHER NOW
$ ./bin/coffee -et '5 <=> 6'[NUMBER 5] [COMPARE <=>] [NUMBER 6] [TERMINATOR \n]
$ ./bin/coffee -en '5 <=> 6'Block Op <=> Value "5" Value "6"
$ ./bin/coffee -epb '5 <=> 6'var __comparison = function(a,b,op) { ...};
__comparison(5, 6, '<=>');
coffee> 300 <=> 500-1
coffee> arrogant = {">": -> true}{ '>': [Function] }
coffee> arrogant > Infinitytrue
coffee> [1,4,2,3,5,6,7].map (val) -> val <=> 5[ -1, -1, -1, -1, 0, 1, 1 ]
λ λSame power, 40% less code
Less noise
Less ?!?!
Familiar, clean syntax
No need to wait for IE (took 6.3 years for JS 1.5)
If you fancy it, add your own language features
;{
{foo:bar,}"\n" == 0