Berliner: Sinatra like Framework written in 16 lines of CoffeeScript.(berliner.jcoglan.com)
berliner.jcoglan.com
Berliner: Sinatra like Framework written in 16 lines of CoffeeScript.
http://berliner.jcoglan.com/
15 comments
Sixteen disgustingly ugly minified lines don't count.
What's the point of minimizing a server-side script anyways? It doesn't need to be transferred over the wire. Silly.
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.
_why begs to differ
Funny that so many commenters don't recognize trolling of CoffeeScript developers/frameworks
I'm disappointed that this is mostly a joke. I really like the docs and have been looking for something along these lines lately.
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.)
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/coffeecupWarning: shameless self-promotion ahead:
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, ->
# 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 :)Yeah, the thing that gave it way for me was: * Since this is such a small module, it’s almost certainly bug-free
? What's wrong with express?
Do you know how much boilerplate crap is required before you can do hello world with express?
>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.
This much:
var app = require('express')(); app.get('*', function(req, res) { res.send('hello world'); }); app.listen(8080);
Hello world probably a bad example.
[deleted]
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)
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.
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.
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:
So:
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.
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.
>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 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
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.
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
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
It's just minified. There are some half-decent ideas in there, it appears to be a half-hearted, lame joke.
[deleted](2)
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
16 lines, not really, 16 x 80 characters = 16 lines.
Otherwise, cool project.
Otherwise, cool project.
well, at first i was excited because i would love an express like router/framework with a code base that i can grok in <15 minutes.
then i saw the code https://github.com/jcoglan/berliner/blob/coffee/berliner.cof... and think this is just lame.
would like to see the real code.
then i saw the code https://github.com/jcoglan/berliner/blob/coffee/berliner.cof... and think this is just lame.
would like to see the real code.
[deleted](1)
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.
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.
Umm, "lines"?