37 comments

[ 4.9 ms ] story [ 108 ms ] thread
Sixteen disgustingly ugly minified lines don't count.
He, I was about to say the same. I could probably compress the worlds entire JS libraries into a single line.
But you can't do that with Coffeescript due to the lack of semi-colons.
What's the point of minimizing a server-side script anyways? It doesn't need to be transferred over the wire. Silly.
_why begs to differ
It's just minified. There are some half-decent ideas in there, it appears to be a half-hearted, lame joke.
(comment deleted)
You win nothing by minifying CoffeeScript. This "Framework" is more a few hundred than 18 lines.
Because it only includes the minified code.
Wait, how's this different from Express?

The whole "in X lines" makes a lot more sense in the browser context (as it needs to download the script), not so much on the server side.

16 lines, not really, 16 x 80 characters = 16 lines.

Otherwise, cool project.

Can we see the real source please?
Will real, lasting apps be built in this?

I'm not sure why languages need to put on a programming pageant.

If it works for you, great, use it to build something cool. I've regularly used about a dozen languages in the last decade. End user Customers don't care what I code in as long as I make their life easier, not just my own.

By taking the time to learn what I'm using for yourself these kinds of comparisons would be a lot more productive than trying to build up the coolness factor. Many Languages were made in the 90's. Even more frameworks come and go, most aim to do similar things, over and over. Maybe it's just me, bulls something for the world.

If you prefer synchronous server side JavaScript, I would recommend also checking out Stick, a CommonJS compatible Sinatra like framework that can also be used from CoffeeScript: https://github.com/olegp/stick
For those that don't see the context: This was written at eurucamp, where we had a talk about a minimal Sinatra in 8 lines. (Almost Sinatra)
For those who wish to see the non-minified source:

The code has not been minified, except perhaps for the replacement of the (carriage return+indent) by semi-columns. Most variable names are semantic.

For sure, the 16 LoC thing is misleading, but the whole thing weights around 3.5 KB, which is impressive for the amount of functionality packed in it.

Let's take the first two lines:

    [J,M,duc,euc,n,e,w]=[JSON,Math,decodeURIComponent,encodeURIComponent,((p)->p.replace(/\/*$/,'').replace /^\/?/,'/'),((d,s)->d[k]=(if d[k]instanceof Array then d[k].concat v else v)for k,v of s;d),(s,c)->s.split(/\s+/).map c]
    [http,url,qs,fs,async,WS,E,haml,ejs,mime]=w 'http url querystring fs async faye-websocket vault/node/aes haml ejs mime',require
For iOS readers, you can scroll the code box using two fingers.

So:

    [J,M,duc,euc]=[JSON,Math,decodeURIComponent,encodeURIComponent]
is quite obvious. So is the second line except perhaps for the use of the w function. It splits the input string on spaces in an array and maps the callback passed as second argument (in this case, require, if you didn't scroll til the end of the line). We'll come to its meaning later.

    n = (p)->p.replace(/\/*$/,'').replace /^\/?/,'/' 
    # normalize?(path??) not sure about his one. 
    # p is also used elsewhere as a generic name.

    e = (d,s)->d[k]=(if d[k]instanceof Array then d[k].concat v else v)for k,v of s;d)
    # extend(destination, source)
    # k and v are obviously key and value.

    w = (s,c)->s.split(/\s+/).map c]
    # w(string, callback)
In Ruby, w%foo bar baz% is a shortcut for creating an array of strings ["foo","bar","baz"]. The w method here is enhanced version of this, and a nod to _why, who often used it to require a bunch of libraries at the top of his scripts. See for example https://github.com/camping/camping/blob/ddea5760289a4de3c270...

For those who don't know about him, _why is the author of Camping, the grand-father of golf Web microframeworks. The current version doesn't use the w trick anymore because the reduction of dependencies made the normal method shorter. Here's the code (possibly NSFL for some...):

https://github.com/camping/camping/blob/master/lib/camping.r...

and its heavily commented (but as terse, codewise) version:

https://github.com/camping/camping/blob/master/lib/camping-u...

Camping used to be the go to ruby microframework until _why's disappearance. Then dev stalled for a while and Sinatra took its place. It has since been revamped and is actively maintained.

Neither Camping nor Berliner are meant for professional use, obviously.

I'm sorry, but I don't get this part:

    something.replace /^\/?/,'/' 
I'm a little sleepy, so maybe I'm missing something, but doesn't it replace a possible '/' at the beginning of some lines with '/'? Isn't that just a waste of CPU cycles? It effectively does nothing.
The key is the question mark. The regexp also adds a slash if none is present initially.
> For iOS readers, you can scroll the code box using two fingers.

You've been able to do it with a single finger for a little while, which makes it a lot easier.

Thanks, I didn't get the memo since I'm still using an iPhone 3G.
Is there a good reason for defining 'J' and 'M' variables instead of just calling JSON and Math directly? It seems to me like that's a poor trade-off of readability for a few measly characters, but I'd love to hear an argument for it.
>Camping used to be the go to ruby microframework until _why's disappearance. Then dev stalled for a while and Sinatra took its place. It has since been revamped and is actively maintained.

I don't recall there being any stalling when _why left? Camping was already a community entrenched project well before _why disappeared.

> Neither Camping nor Berliner are meant for professional use, obviously.

I think the Camping developers & users would disagree.

Here's an HN Post which highlights why they think Camping is better designed than Sinatra: http://news.ycombinator.com/item?id=1532178

I'm disappointed that this is mostly a joke. I really like the docs and have been looking for something along these lines lately.
? What's wrong with express?
Do you know how much boilerplate crap is required before you can do hello world with express?
(comment deleted)
>Do you know how much boilerplate crap is required before you can do hello world with express?

This much:

var app = require('express')(); app.get('*', function(req, res) { res.send('hello world'); }); app.listen(8080);

Hello world probably a bad example.

Zappa[0] is a cool Coffeescript wrapper around Express. Unfortunately, Maurice Machado[1] dropped off the radar last October so some other people stepped in to maintain it at https://github.com/zappajs/zappajs.

Maurice also wrote Coffeekup[2] (a Coffeescript Jade) which has also been taken over by the community as a project called Coffeecup[3].

(Sincerely hope Maurice is ok. He was real active and put a lot of effort into his projects up until his disappearance.)

    [0]: http://zappajs.org/docs/crashcourse/
    [1]: http://twitter.com/mauricemach
    [2]: http://coffeekup.org/ && https://github.com/mauricemach/coffeekup
    [3]: https://github.com/gradus/coffeecup
Yeah, the thing that gave it way for me was: * Since this is such a small module, it’s almost certainly bug-free
Warning: shameless self-promotion ahead:

   db = require('./your_sexy_data_access_module')
   server = require('lazorse').server port: 3000, ->
     # in this context we register resources the app using @resource
     @resource '/things/{thingId}':
       shortName: "Things"
       GET: ->
         db.getThing @thingId, @data
       POST: ->
         db.getThing @thingId, (err, thing) =>
           return @next(err) if err
           thing.update(@req, @data)
Where @data is node-style callback function taking (err, data), and the data will be rendered by a separate middleware layer that inspects Accept headers and does the Right Thing.

There's a lot more than should be covered in an HN comment, but in interest of DRYing out the above example, let's rewrite it to use a coercion to retrieve "thing" instances.

   db = require('./your_sexy_data_access_module')
   server = require('lazorse').server port: 3000, ->

     @coerce 'thing', "Things are whatever this app deals in", db.getThing

     @resource '/things/{thing}':
       shortName: "Things"
       GET: ->
         # Use @ok because we won't get here if there was an error retrieving
         # the thing
         @ok @thing
       POST: ->
         @thing.update @req, @data
 
See http://betsmartmedia.github.com/Lazorse for full API docs and examples. Bug reports, pull requests, flame comments etc. are all very welcome :)
This was written in response to a talk at Eurucamp over the weekend, about re-writing Sinatra in as few lines of code as possible.

While somewhat tongue in cheek it was as much about being creative with the language as it was about obfuscation and writing 'bad' code.

https://github.com/rkh/almost-sinatra