Skip to content
Open
Show file tree
Hide file tree
Changes from 61 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
262df0a
Port to CoffeeScript.
jcoglan Aug 18, 2012
72631f8
Return 404 on route not found.
jcoglan Aug 18, 2012
b90b072
Parse form-urlencoded bodies.
jcoglan Aug 18, 2012
20395a6
Allow user to set headers and status codes.
jcoglan Aug 18, 2012
0759198
Make cookies safer.
jcoglan Aug 19, 2012
e99065e
Remove an unneeded space.
jcoglan Aug 19, 2012
5ad7a65
Incorporate map() call into w().
jcoglan Aug 19, 2012
b18205d
Respond to HEAD and OPTIONS.
jcoglan Aug 19, 2012
cb5b527
Cleaner params parsing.
jcoglan Aug 19, 2012
c7973a5
Remove a redundant helper function.
jcoglan Aug 19, 2012
a29b940
Remove .rvmrc.
jcoglan Aug 19, 2012
83c7f87
Remove some unneeded parens.
jcoglan Aug 19, 2012
9359f13
Move parens in a helper function.
jcoglan Aug 19, 2012
e8d6c90
Add path-parameter parsing.
jcoglan Aug 19, 2012
4cc3c45
Don't parse URLs twice.
jcoglan Aug 19, 2012
208f16f
Make helper functions visible in HAML and EJS.
jcoglan Aug 19, 2012
a190754
Let the user pick a port.
jcoglan Aug 19, 2012
8698e7b
Change port variable name.
jcoglan Aug 19, 2012
0b2412e
Remove some parens we don't need.
jcoglan Aug 19, 2012
efb0304
Add WebSocket support.
jcoglan Aug 19, 2012
aa563b7
Documentation.
jcoglan Aug 19, 2012
083c14d
Add EventSource support.
jcoglan Aug 19, 2012
31b0235
Include query string params in WebSocket and EventSource handlers.
jcoglan Aug 19, 2012
79e8726
Golf the request-dispatching code a bit.
jcoglan Aug 19, 2012
9a69b43
Correct Content-Type header in README.
jcoglan Aug 19, 2012
125926d
Support params.splat.
jcoglan Aug 19, 2012
2f4b339
Pass params into the request handlers as arguments.
jcoglan Aug 19, 2012
b374989
Lose 4 characters.
jcoglan Aug 19, 2012
6bbf935
Highlight code in the readme appropriately.
jcoglan Aug 20, 2012
305e469
Example code for accessing the session in a WebSocket handler.
jcoglan Aug 20, 2012
dd04d84
Reduce line count by 10.
jcoglan Aug 20, 2012
86ece34
Single-letter class names.
jcoglan Aug 20, 2012
0a691f6
Use self-contained sessions.
jcoglan Aug 20, 2012
95b06b6
Correct description of sessions in readme.
jcoglan Aug 20, 2012
f044309
Make before-filters happen when the request is fully processed, and m…
jcoglan Aug 20, 2012
699c133
Use full words @request and @response.
jcoglan Aug 20, 2012
d06b9c1
Merge two lines.
jcoglan Aug 20, 2012
c23db3c
Shouldn't be a space between args.
jcoglan Aug 20, 2012
92cf012
Add cookie support.
jcoglan Aug 20, 2012
cb807e4
Fix 404 handling.
jcoglan Aug 20, 2012
e5bc952
Shave a few characters off.
jcoglan Aug 20, 2012
41d1fc6
Serve static files, and render views from files.
jcoglan Aug 20, 2012
185820a
Fix readme code formatting.
jcoglan Aug 20, 2012
1795995
Merge documentation for sockets.
jcoglan Aug 20, 2012
fdc79b8
Commit missing example app.
jcoglan Aug 20, 2012
f9d2ef0
Remove an unneeded route handler from the example app.
jcoglan Aug 21, 2012
5529034
Place all the browser-accessible route handlers up top.
jcoglan Aug 21, 2012
b632b3e
Accommodate route matchers with no leading slash, or with a trailing …
jcoglan Aug 21, 2012
8ed84b8
Add context groups for shorter routes and contextual before-blocks.
jcoglan Aug 21, 2012
2806c99
Add Content-Length to static file responses, and golf things down a bit.
jcoglan Aug 21, 2012
d79277c
Don't allow '..' as a path segment.
jcoglan Aug 21, 2012
cc9588d
Add redirect() method.
jcoglan Aug 21, 2012
8a8b922
Cookies should go through URI codec on the wire.
jcoglan Aug 21, 2012
9bbc67f
URI-encode session cookies, otherwise they decode badly.
jcoglan Aug 21, 2012
0b28889
Make a docs website, change the name of the project.
jcoglan Aug 21, 2012
8880e2f
CoffeeScript is a dev dependency.
jcoglan Aug 21, 2012
839a191
Plug Mongo.
jcoglan Aug 21, 2012
88463b0
Correct documentation of empty OPTIONS reponse.
jcoglan Aug 21, 2012
01aaad3
Add Analytics tracking.
jcoglan Aug 21, 2012
e1e134f
Link to source.
jcoglan Aug 22, 2012
47fd2c8
Switch to vault-cipher for encrypting sessions.
jcoglan Jan 12, 2013
1abab94
Remove analytics from the site.
jcoglan May 22, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
annoying people
node_modules
6 changes: 6 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.git
.gitignore
.npmignore
.redcar

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this line to make it merge cleanly

node_modules
site
48 changes: 0 additions & 48 deletions .rvmrc

This file was deleted.

26 changes: 26 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Berliner

A lightweight web framework. [Read the online docs.](http://berliner.jcoglan.com)

## License

(The MIT License)

Copyright (c) 2012 James Coglan

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the 'Software'), to deal in
the Software without restriction, including without limitation the rights to use,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what

copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
110 changes: 0 additions & 110 deletions README.md

This file was deleted.

8 changes: 0 additions & 8 deletions almost_sinatra.rb

This file was deleted.

17 changes: 17 additions & 0 deletions berliner.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[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]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty sure this should be [K,M,dfm,euc,n,e,w]=

[http,url,qs,fs,async,WS,E,haml,ejs,mime]=w 'http url querystring fs async faye-websocket vault-cipher haml ejs mime',require
class A
constructor:(@request,@response,@_m)->
[h,c]=[{},(@request.headers.cookie||'').split /\s*;\s*/];c.map((p)->q=p.split '=';h[duc q[0]]=duc q[1]);A.cipher().decrypt h.session||'',(x,j)=>
delete h.session;@params={splat:[]};@cookies=h;@session=(if x then{}else J.parse(j));@_u=url.parse(@request.url,true);@_h='Set-Cookie':[];e @,A.h;@_b=A.r.filter((r)=>r[0]==@_m&&r[2].test @_u.pathname)[0]
@_c if @_b then[@_a,d]=[[],@_u.pathname.match @_b[2]];(v=duc d[i+1];@_a.push v;if k=='*' then @params.splat.push v else @params[k]=v)for k,i in @_b[1];e @params,(if /\bapplication\/x-www-form-urlencoded\b/.test @request.headers['content-type']then qs.parse @request.body else @_u.query)
_x:(c)->@_c= =>p=@_u.pathname;if p.split('/').indexOf('..')>=0 then @response.writeHead 400,{};@response.end() else async.series A.b.filter((f)=>p.substr(0,f.c.length)==f.c).map((f)=> =>f.apply @,arguments).concat =>if @_b then c.call @,(=>@_b[3].apply @,@_a)else fs.readFile (A.public||'./public')+p,(x,f)=>if x then @response.writeHead 404,{};@response.end()else @response.writeHead 200,'Content-Length':f.length,'Content-Type':mime.lookup(p)+'; charset=utf-8';@response.end f
render:(s)->s=(if s==undefined then ''else String s);A.cipher().encrypt J.stringify(@session),(x,j)=>h={};e h,'Set-Cookie':['session=' + euc(j) + '; Path=/; HttpOnly'],'Content-Type':'text/html; charset=utf-8','Content-Length':new Buffer(s,'utf8').length if s;e h,@_h;@response.writeHead @_s||200,h;@response.end s
cookie:(c)->(v=if typeof v=='string'then value:v else v;s=euc(k)+'='+euc(v.value)+'; Path='+v.path||'/';s+='; Domain='+v.domain if v.domain;s+='; Expires='+v.expires.toGMTString() if v.expires;s+='; HttpOnly' if v.http;s+='; Secure' if v.secure;e @_h,'Set-Cookie':s)for k,v of c
e A.prototype,headers:((o)->e @_h,o),status:((n)->@_s=parseInt n,10),redirect:((u,s=303)->@status s;@headers 'Location':u;@render()),haml:((n)->A.v 'haml',n,(x,t)=>@render haml(t) @),ejs:((n,o)->A.v 'ejs',n,(x,t)=>@render ejs.render t,e o?.locals||{},A.h),puts:(s)->console.log s
e A,r:[],c:[''],context:((p,f)->@c.push n p;f @;@c.pop()),b:[],before:((b)->[email protected] '';@b.push b),h:{},helpers:((o)->e @h,o),t:{},template:((n,t)->@t[n]=t),v:((t,n,c)->if f=@t[n+'.'+t]then c null,f else fs.readFile (@views||'./views')+'/'+n+'.'+t,(x,f)->c null,f.toString()),run:((q)->http.createServer(@call).on('upgrade',@ws).listen q||4567),cipher:->new E(@session_secret)
w 'get post put delete patch head options websocket eventsource',(v)->A[v]=(p,f)->p=n(@c.join('')+n p);o=(p.match(/[\/\.](\*|:[a-z\_\$][a-z0-9\_\$]*)/g)||[]).map((s)->s.replace /^[^a-z0-9\_\$\*]*/,'');m=new RegExp('^'+p.replace(/([\/\.])/g,'\\$1').replace(/\*|:[a-z\_\$][a-z0-9\_\$]*/ig,'(.+?)')+'$');@r.push [v.toUpperCase(),o,m,f]
A.call=(req,res)->req.setEncoding 'utf8';b='';req.on('data',(s)->b+=s);req.on 'end',->req.body=b;ES=WS.EventSource;k=ES.isEventSource req;a=new A(req,res,if k then 'EVENTSOURCE' else req.method);if k then(a._x (h)->s=a.socket=new ES req,res;h();s.addEventListener 'close',->s=null)else(a._x (h)->r=h();if typeof r=='string'then @render r)
A.ws=(r,s,h)->a=new A(r,s,'WEBSOCKET');a._x (H)->w=a.socket=new WS r,s,h;H();w.addEventListener 'close',->w=null
module.exports=A

53 changes: 0 additions & 53 deletions example.rb

This file was deleted.

78 changes: 78 additions & 0 deletions example/app.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
app = require '../berliner'

app.public = __dirname + '/public'
app.views = __dirname + '/views'
app.session_secret = 'abc123'

app.helpers
inc_counter: ->
@session.counter ||= 0
@session.counter += 1

site_name: ->
'Awesome.net'

app.before (next) ->
@puts @request.method + ' ' + @request.url
next()

app.get '/', ->
@cookie message: {value: 'Sinatra; it’s a framework', path: '/hello'}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no.

@title = 'Almost Sinatra'
@haml 'index'

app.get 'hello', ->
@ejs 'hello', locals: {name: @params.name, message: @cookies.message}

app.get '/counter', ->
@inc_counter()
@render @session.counter

app.context '/auth', (auth) ->
auth.before (next) ->
if @request.headers.authorization
next()
else
@status 401
@render 'Authorization required'

auth.get '/', ->
'Secret stuff'

auth.delete 'info', ->
@status 418
'I am a teapot'

app.get '/words/:category/:id.:format', ->
JSON.stringify @params

app.get '/download/*.*', ->
@params.splat.join ', '

app.put '/download/*.*', (path, ext) ->
[path, ext].join ' // '

app.post '/', ->
@status 201
@headers 'Content-Type': 'application/json'
JSON.stringify @params

app.get '/legacy', ->
@redirect '/hello'

app.options '/', ->
@headers 'Access-Control-Allow-Methods': 'GET, PUT, DELETE'
@render ''

app.websocket '/ws/:name', ->
@socket.onmessage = (e)=>
@socket.send @params.name + ': ' + e.data

app.eventsource '/ws/:name', ->
setInterval (=> @socket.send @params.name + ': PUSH!'), 5000

app.template 'hello.ejs', """
Hello <%= name %>, welcome to <%= site_name() %>! Cookie: “<%= message %>”
"""

app.run 4567
20 changes: 20 additions & 0 deletions example/public/socket.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
var write = function(data) {
var log = document.getElementById('log'),
li = document.createElement('li');

li.innerHTML = data;
log.appendChild(li);
};

var ws = new WebSocket('ws://localhost:4567/ws/awesome');
ws.onmessage = function(e) {
write(e.data);
setTimeout(function() { ws.send('Loop') }, 2000)
};
ws.onopen = function() { ws.send('Ping!') };

var es = new EventSource('http://localhost:4567/ws/eurucamp');
es.onmessage = function(e) {
write(e.data);
};

9 changes: 9 additions & 0 deletions example/views/index.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
%html
%head
%title= title
%body
%p= site_name()
%a{href: '/hello?name=World'} Say hello!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I refuse.

%a{href: '/counter'} Show Counter
%ul{id: 'log'}
%script{src: '/socket.js'}
Loading