Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

First go at 0.3.0.

  • Loading branch information...
commit d66031e7ffa8d7acf7e1c92731dd1920e06b3b78 1 parent e6691e4
@mauricemach mauricemach authored
View
37 CHANGELOG.md
@@ -1,8 +1,33 @@
-**v0.1.5** (2010-05-06):
+**v0.2.0** (2011-07-xx):
- - Compatible with npm 1.x.
+ - Complete rewrite, the main idea/api/capabilities are mostly the same, but implemented and used in a way
+ more harmonized with the node ecosystem.
+
+ - Performance issues worked out, now negligible overhead over express. Gone with the `with` keyword.
-**v0.1.4** (2010-01-05):
+ - Scraped the `zappa` command. One additional `require` line and now zappa apps can be run directly with
+ standard `coffee` and `node` commands, compiled with `coffee`, reloaded with `runjs`/`nodemon` etc,
+ deployed with `forever` or to services such as [nodester](http://nodester.com) and [no.de](http://no.de)
+ with no special steps required.
+
+ - New `app` and `io` variables at the root scope, providing direct access to express and socket.io.
+
+ - Now using the rendering system from express, with all the features it supports (arbitrary engines,
+ partials, etc), while retaining the ability to define templates in-file with the `view` function and
+ pass variables to the template through `@/this`.
+
+ - The `include` function now is implemented through the standard `require`. Files `include`'d files should
+ just add a `module.exports = ->` line.
+
+ - Using the new socket.io 0.7.x API which is a lot closer to how zappa works.
+
+ - Optional client-side zappa with socket.io and sammy.js for routes.
+
+**v0.1.5** (2011-05-06):
+
+ - Reworked packaging for npm 1.x.
+
+**v0.1.4** (2011-01-05):
- Updated to CoffeeScript 1.0.0 and node 0.2.6/0.3.3.
- Soda tests by Nicholas Kinsey.
@@ -12,7 +37,7 @@
- Made defs available to postrenders' scope.
- Bug fixes.
-**v0.1.3** (2010-11-13):
+**v0.1.3** (2010-11-24):
- Updated to CoffeeScript 0.9.5 and node 0.2.5/0.3.1.
- Partials support.
@@ -27,3 +52,7 @@
- bodyDecoder, cookieDecoder and session middleware by default. Configs to turn them off will follow.
- Using new jQuery (1.4.3) npm package instead of jsdom directly.
- Using Socket.IO 0.6.0 (great improvements over the previous version).
+
+**v0.1.1** (2010-10-22):
+
+**v0.1.0** (2010-10-21):
View
186 docs/docco.css
@@ -0,0 +1,186 @@
+/*--------------------- Layout and Typography ----------------------------*/
+body {
+ font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;
+ font-size: 15px;
+ line-height: 22px;
+ color: #252519;
+ margin: 0; padding: 0;
+}
+a {
+ color: #261a3b;
+}
+ a:visited {
+ color: #261a3b;
+ }
+p {
+ margin: 0 0 15px 0;
+}
+h1, h2, h3, h4, h5, h6 {
+ margin: 0px 0 15px 0;
+}
+ h1 {
+ margin-top: 40px;
+ }
+#container {
+ position: relative;
+}
+#background {
+ position: fixed;
+ top: 0; left: 525px; right: 0; bottom: 0;
+ background: #f5f5ff;
+ border-left: 1px solid #e5e5ee;
+ z-index: -1;
+}
+#jump_to, #jump_page {
+ background: white;
+ -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777;
+ -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px;
+ font: 10px Arial;
+ text-transform: uppercase;
+ cursor: pointer;
+ text-align: right;
+}
+#jump_to, #jump_wrapper {
+ position: fixed;
+ right: 0; top: 0;
+ padding: 5px 10px;
+}
+ #jump_wrapper {
+ padding: 0;
+ display: none;
+ }
+ #jump_to:hover #jump_wrapper {
+ display: block;
+ }
+ #jump_page {
+ padding: 5px 0 3px;
+ margin: 0 0 25px 25px;
+ }
+ #jump_page .source {
+ display: block;
+ padding: 5px 10px;
+ text-decoration: none;
+ border-top: 1px solid #eee;
+ }
+ #jump_page .source:hover {
+ background: #f5f5ff;
+ }
+ #jump_page .source:first-child {
+ }
+table td {
+ border: 0;
+ outline: 0;
+}
+ td.docs, th.docs {
+ max-width: 450px;
+ min-width: 450px;
+ min-height: 5px;
+ padding: 10px 25px 1px 50px;
+ overflow-x: hidden;
+ vertical-align: top;
+ text-align: left;
+ }
+ .docs pre {
+ margin: 15px 0 15px;
+ padding-left: 15px;
+ }
+ .docs p tt, .docs p code {
+ background: #f8f8ff;
+ border: 1px solid #dedede;
+ font-size: 12px;
+ padding: 0 0.2em;
+ }
+ .pilwrap {
+ position: relative;
+ }
+ .pilcrow {
+ font: 12px Arial;
+ text-decoration: none;
+ color: #454545;
+ position: absolute;
+ top: 3px; left: -20px;
+ padding: 1px 2px;
+ opacity: 0;
+ -webkit-transition: opacity 0.2s linear;
+ }
+ td.docs:hover .pilcrow {
+ opacity: 1;
+ }
+ td.code, th.code {
+ padding: 14px 15px 16px 25px;
+ width: 100%;
+ vertical-align: top;
+ background: #f5f5ff;
+ border-left: 1px solid #e5e5ee;
+ }
+ pre, tt, code {
+ font-size: 12px; line-height: 18px;
+ font-family: Monaco, Consolas, "Lucida Console", monospace;
+ margin: 0; padding: 0;
+ }
+
+
+/*---------------------- Syntax Highlighting -----------------------------*/
+td.linenos { background-color: #f0f0f0; padding-right: 10px; }
+span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
+body .hll { background-color: #ffffcc }
+body .c { color: #408080; font-style: italic } /* Comment */
+body .err { border: 1px solid #FF0000 } /* Error */
+body .k { color: #954121 } /* Keyword */
+body .o { color: #666666 } /* Operator */
+body .cm { color: #408080; font-style: italic } /* Comment.Multiline */
+body .cp { color: #BC7A00 } /* Comment.Preproc */
+body .c1 { color: #408080; font-style: italic } /* Comment.Single */
+body .cs { color: #408080; font-style: italic } /* Comment.Special */
+body .gd { color: #A00000 } /* Generic.Deleted */
+body .ge { font-style: italic } /* Generic.Emph */
+body .gr { color: #FF0000 } /* Generic.Error */
+body .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+body .gi { color: #00A000 } /* Generic.Inserted */
+body .go { color: #808080 } /* Generic.Output */
+body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+body .gs { font-weight: bold } /* Generic.Strong */
+body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+body .gt { color: #0040D0 } /* Generic.Traceback */
+body .kc { color: #954121 } /* Keyword.Constant */
+body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */
+body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */
+body .kp { color: #954121 } /* Keyword.Pseudo */
+body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */
+body .kt { color: #B00040 } /* Keyword.Type */
+body .m { color: #666666 } /* Literal.Number */
+body .s { color: #219161 } /* Literal.String */
+body .na { color: #7D9029 } /* Name.Attribute */
+body .nb { color: #954121 } /* Name.Builtin */
+body .nc { color: #0000FF; font-weight: bold } /* Name.Class */
+body .no { color: #880000 } /* Name.Constant */
+body .nd { color: #AA22FF } /* Name.Decorator */
+body .ni { color: #999999; font-weight: bold } /* Name.Entity */
+body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+body .nf { color: #0000FF } /* Name.Function */
+body .nl { color: #A0A000 } /* Name.Label */
+body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+body .nt { color: #954121; font-weight: bold } /* Name.Tag */
+body .nv { color: #19469D } /* Name.Variable */
+body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+body .w { color: #bbbbbb } /* Text.Whitespace */
+body .mf { color: #666666 } /* Literal.Number.Float */
+body .mh { color: #666666 } /* Literal.Number.Hex */
+body .mi { color: #666666 } /* Literal.Number.Integer */
+body .mo { color: #666666 } /* Literal.Number.Oct */
+body .sb { color: #219161 } /* Literal.String.Backtick */
+body .sc { color: #219161 } /* Literal.String.Char */
+body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */
+body .s2 { color: #219161 } /* Literal.String.Double */
+body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+body .sh { color: #219161 } /* Literal.String.Heredoc */
+body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+body .sx { color: #954121 } /* Literal.String.Other */
+body .sr { color: #BB6688 } /* Literal.String.Regex */
+body .s1 { color: #219161 } /* Literal.String.Single */
+body .ss { color: #19469D } /* Literal.String.Symbol */
+body .bp { color: #954121 } /* Name.Builtin.Pseudo */
+body .vc { color: #19469D } /* Name.Variable.Class */
+body .vg { color: #19469D } /* Name.Variable.Global */
+body .vi { color: #19469D } /* Name.Variable.Instance */
+body .il { color: #666666 } /* Literal.Number.Integer.Long */
View
333 docs/zappa.html
@@ -0,0 +1,333 @@
+<!DOCTYPE html> <html> <head> <title>zappa.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> zappa.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-1">&#182;</a> </div> <p><strong>Zappa</strong> is a <a href="http://coffeescript.org">CoffeeScript</a> DSL-ish interface for building web apps on the
+<a href="http://nodejs.org">node.js</a> runtime, integrating <a href="http://expressjs.com">express</a>, <a href="http://socket.io">socket.io</a>
+and other best-of-breed libraries.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">log = </span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span>
+<span class="nv">fs = </span><span class="nx">require</span> <span class="s1">&#39;fs&#39;</span>
+
+<span class="vi">@version = </span><span class="s1">&#39;0.2.0&#39;</span></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">&#182;</a> </div> <p>CoffeeScript-generated JavaScript may contain anyone of these; when we "rewrite"
+a function (see below) though, it loses access to its parent scope, and consequently to
+any helpers it might need. So we need to reintroduce these helpers manually inside any
+"rewritten" function.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">coffeescript_helpers = </span><span class="s2">&quot;&quot;&quot;</span>
+<span class="s2"> var __slice = Array.prototype.slice;</span>
+<span class="s2"> var __hasProp = Object.prototype.hasOwnProperty;</span>
+<span class="s2"> var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };</span>
+<span class="s2"> var __extends = function(child, parent) {</span>
+<span class="s2"> for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }</span>
+<span class="s2"> function ctor() { this.constructor = child; }</span>
+<span class="s2"> ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype;</span>
+<span class="s2"> return child; };</span>
+<span class="s2"> var __indexOf = Array.prototype.indexOf || function(item) {</span>
+<span class="s2"> for (var i = 0, l = this.length; i &lt; l; i++) {</span>
+<span class="s2"> if (this[i] === item) return i;</span>
+<span class="s2"> } return -1; };</span>
+<span class="s2">&quot;&quot;&quot;</span><span class="p">.</span><span class="nx">replace</span> <span class="sr">/\n/g</span><span class="p">,</span> <span class="s1">&#39;&#39;</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</a> </div> <p>"Rewrites" a function so that it accepts the value of @/this ("context")
+and local variables as parameters.
+The names of local variables to be "extracted" have to be provided beforehand.
+The function will lose access to its parent scope in the process.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">rewrite_function = </span><span class="nf">(func, locals_names) -&gt;</span>
+ <span class="nv">code = </span><span class="nb">String</span><span class="p">(</span><span class="nx">func</span><span class="p">)</span>
+ <span class="nv">code = </span><span class="s2">&quot;function () {#{code}}&quot;</span> <span class="nx">unless</span> <span class="nx">code</span><span class="p">.</span><span class="nx">indexOf</span> <span class="s1">&#39;function&#39;</span> <span class="o">is</span> <span class="mi">0</span>
+ <span class="nv">code = </span><span class="s2">&quot;#{coffeescript_helpers}return (#{code}).apply(context, args);&quot;</span>
+ <span class="k">for</span> <span class="nx">name</span> <span class="k">in</span> <span class="nx">locals_names</span>
+ <span class="nv">code = </span><span class="s2">&quot;var #{name} = locals.#{name};&quot;</span> <span class="o">+</span> <span class="nx">code</span>
+ <span class="k">new</span> <span class="nb">Function</span><span class="p">(</span><span class="s1">&#39;context&#39;</span><span class="p">,</span> <span class="s1">&#39;locals&#39;</span><span class="p">,</span> <span class="s1">&#39;args&#39;</span><span class="p">,</span> <span class="nx">code</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p>Takes in a function and builds express/socket.io apps based on the rules contained in it.</p> </td> <td class="code"> <div class="highlight"><pre><span class="vi">@app = </span><span class="nf">(root_function) -&gt;</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#182;</a> </div> <p>Names of local variables that we have to know beforehand, to use with <code>rewrite_function</code>.
+Helpers and defs will be known after we execute the user-provided <code>root_function</code>.
+TODO: <em>_filename and _</em>dirname won't work this way. Find another solution.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">globals = </span><span class="p">[</span><span class="s1">&#39;global&#39;</span><span class="p">,</span> <span class="s1">&#39;process&#39;</span><span class="p">,</span> <span class="s1">&#39;console&#39;</span><span class="p">,</span> <span class="s1">&#39;require&#39;</span><span class="p">,</span> <span class="s1">&#39;__filename&#39;</span><span class="p">,</span> <span class="s1">&#39;__dirname&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;module&#39;</span><span class="p">,</span> <span class="s1">&#39;setTimeout&#39;</span><span class="p">,</span> <span class="s1">&#39;clearTimeout&#39;</span><span class="p">,</span> <span class="s1">&#39;setInterval&#39;</span><span class="p">,</span> <span class="s1">&#39;clearInterval&#39;</span><span class="p">]</span> </pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">&#182;</a> </div> <p>TODO: using?, route?, postrender?, enable, disable, settings, error</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">root_locals_names = </span><span class="p">[</span><span class="s1">&#39;express&#39;</span><span class="p">,</span> <span class="s1">&#39;io&#39;</span><span class="p">,</span> <span class="s1">&#39;app&#39;</span><span class="p">,</span> <span class="s1">&#39;get&#39;</span><span class="p">,</span> <span class="s1">&#39;post&#39;</span><span class="p">,</span> <span class="s1">&#39;put&#39;</span><span class="p">,</span> <span class="s1">&#39;del&#39;</span><span class="p">,</span> <span class="s1">&#39;at&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;helper&#39;</span><span class="p">,</span> <span class="s1">&#39;def&#39;</span><span class="p">,</span> <span class="s1">&#39;view&#39;</span><span class="p">,</span> <span class="s1">&#39;set&#39;</span><span class="p">,</span> <span class="s1">&#39;use&#39;</span><span class="p">,</span> <span class="s1">&#39;configure&#39;</span><span class="p">,</span> <span class="s1">&#39;include&#39;</span><span class="p">,</span> <span class="s1">&#39;client&#39;</span><span class="p">,</span> <span class="s1">&#39;coffee&#39;</span><span class="p">,</span> <span class="s1">&#39;js&#39;</span><span class="p">,</span> <span class="s1">&#39;css&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;enable&#39;</span><span class="p">,</span> <span class="s1">&#39;disable&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">&#182;</a> </div> <p>TODO: app? (something shared with ws_handlers), app.clients?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">http_locals_names = </span><span class="p">[</span><span class="s1">&#39;response&#39;</span><span class="p">,</span> <span class="s1">&#39;request&#39;</span><span class="p">,</span> <span class="s1">&#39;next&#39;</span><span class="p">,</span> <span class="s1">&#39;params&#39;</span><span class="p">,</span> <span class="s1">&#39;send&#39;</span><span class="p">,</span> <span class="s1">&#39;render&#39;</span><span class="p">,</span> <span class="s1">&#39;redirect&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">&#182;</a> </div> <p>TODO: emit?, broadcast, render?, app? (shared between http-ws, persistent)</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ws_locals_names = </span><span class="p">[</span><span class="s1">&#39;socket&#39;</span><span class="p">,</span> <span class="s1">&#39;id&#39;</span><span class="p">,</span> <span class="s1">&#39;params&#39;</span><span class="p">,</span> <span class="s1">&#39;client&#39;</span><span class="p">]</span>
+ <span class="nv">helpers_names = </span><span class="p">[]</span>
+ <span class="nv">defs_names = </span><span class="p">[]</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">&#182;</a> </div> <p>Storage for the functions provided by the user.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">routes = </span><span class="p">[]</span>
+ <span class="nv">ws_handlers = </span><span class="p">{}</span>
+ <span class="nv">helpers = </span><span class="p">{}</span>
+ <span class="nv">defs = </span><span class="p">{}</span>
+ <span class="nv">views = </span><span class="p">{}</span>
+ </pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">&#182;</a> </div> <p>Builds the applications's root scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">express = </span><span class="nx">require</span> <span class="s1">&#39;express&#39;</span>
+ <span class="nv">socketio = </span><span class="nx">require</span> <span class="s1">&#39;socket.io&#39;</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">&#182;</a> </div> <p>Monkeypatch express to support inline templates. Such is life.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">express</span><span class="p">.</span><span class="nx">View</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">__defineGetter__</span> <span class="s1">&#39;exists&#39;</span><span class="p">,</span> <span class="o">-&gt;</span>
+ <span class="k">return</span> <span class="kc">true</span> <span class="k">if</span> <span class="nx">views</span><span class="p">[</span><span class="nx">@view</span><span class="p">]</span><span class="o">?</span>
+ <span class="k">try</span>
+ <span class="nx">fs</span><span class="p">.</span><span class="nx">statSync</span><span class="p">(</span><span class="nx">@path</span><span class="p">)</span>
+ <span class="k">return</span> <span class="kc">true</span>
+ <span class="k">catch</span> <span class="nx">err</span>
+ <span class="k">return</span> <span class="kc">false</span>
+ <span class="nx">express</span><span class="p">.</span><span class="nx">View</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">__defineGetter__</span> <span class="s1">&#39;contents&#39;</span><span class="p">,</span> <span class="o">-&gt;</span>
+ <span class="k">return</span> <span class="nx">views</span><span class="p">[</span><span class="nx">@view</span><span class="p">]</span> <span class="k">if</span> <span class="nx">views</span><span class="p">[</span><span class="nx">@view</span><span class="p">]</span><span class="o">?</span>
+ <span class="nx">fs</span><span class="p">.</span><span class="nx">readFileSync</span> <span class="nx">@path</span><span class="p">,</span> <span class="s1">&#39;utf8&#39;</span>
+
+ <span class="nv">app = </span><span class="nx">express</span><span class="p">.</span><span class="nx">createServer</span><span class="p">()</span>
+ <span class="nv">io = </span><span class="nx">socketio</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="nx">app</span><span class="p">)</span>
+ <span class="nx">io</span><span class="p">.</span><span class="nx">set</span> <span class="s1">&#39;log level&#39;</span><span class="p">,</span> <span class="mi">1</span>
+
+ <span class="nv">root_context = </span><span class="p">{}</span>
+ <span class="nv">root_locals = </span><span class="p">{</span><span class="nx">express</span><span class="p">,</span> <span class="nx">io</span><span class="p">,</span> <span class="nx">app</span><span class="p">}</span>
+ <span class="nx">root_locals</span><span class="p">[</span><span class="nx">g</span><span class="p">]</span> <span class="o">=</span> <span class="nb">eval</span><span class="p">(</span><span class="nx">g</span><span class="p">)</span> <span class="k">for</span> <span class="nx">g</span> <span class="k">in</span> <span class="nx">globals</span>
+
+ <span class="k">for</span> <span class="nx">verb</span> <span class="k">in</span> <span class="p">[</span><span class="s1">&#39;get&#39;</span><span class="p">,</span> <span class="s1">&#39;post&#39;</span><span class="p">,</span> <span class="s1">&#39;put&#39;</span><span class="p">,</span> <span class="s1">&#39;del&#39;</span><span class="p">]</span>
+ <span class="nx">do</span> <span class="nf">(verb) -&gt;</span>
+ <span class="nx">root_locals</span><span class="p">[</span><span class="nx">verb</span><span class="p">]</span> <span class="o">=</span> <span class="o">-&gt;</span>
+ <span class="k">if</span> <span class="k">typeof</span> <span class="nx">arguments</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">isnt</span> <span class="s1">&#39;object&#39;</span>
+ <span class="nx">routes</span><span class="p">.</span><span class="nx">push</span> <span class="nv">verb: </span><span class="nx">verb</span><span class="p">,</span> <span class="nv">path: </span><span class="nx">arguments</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nv">handler: </span><span class="nx">arguments</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
+ <span class="k">else</span>
+ <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">arguments</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
+ <span class="nx">routes</span><span class="p">.</span><span class="nx">push</span> <span class="nv">verb: </span><span class="nx">verb</span><span class="p">,</span> <span class="nv">path: </span><span class="nx">k</span><span class="p">,</span> <span class="nv">handler: </span><span class="nx">v</span>
+
+ <span class="nv">root_locals.client = </span><span class="nf">(obj) -&gt;</span>
+ <span class="nx">app</span><span class="p">.</span><span class="nx">enable</span> <span class="s1">&#39;zappa serve client&#39;</span>
+ <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">obj</span>
+ <span class="nv">js = </span><span class="s2">&quot;;zappa.run(#{v});&quot;</span>
+ <span class="nx">routes</span><span class="p">.</span><span class="nx">push</span> <span class="nv">verb: </span><span class="s1">&#39;get&#39;</span><span class="p">,</span> <span class="nv">path: </span><span class="nx">k</span><span class="p">,</span> <span class="nv">handler: </span><span class="nx">js</span><span class="p">,</span> <span class="nv">contentType: </span><span class="s1">&#39;js&#39;</span>
+
+ <span class="nv">root_locals.coffee = </span><span class="nf">(obj) -&gt;</span>
+ <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">obj</span>
+ <span class="nv">js = </span><span class="s2">&quot;;#{coffeescript_helpers}(#{v})();&quot;</span>
+ <span class="nx">routes</span><span class="p">.</span><span class="nx">push</span> <span class="nv">verb: </span><span class="s1">&#39;get&#39;</span><span class="p">,</span> <span class="nv">path: </span><span class="nx">k</span><span class="p">,</span> <span class="nv">handler: </span><span class="nx">js</span><span class="p">,</span> <span class="nv">contentType: </span><span class="s1">&#39;js&#39;</span>
+
+ <span class="nv">root_locals.js = </span><span class="nf">(obj) -&gt;</span>
+ <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">obj</span>
+ <span class="nv">js = </span><span class="nb">String</span><span class="p">(</span><span class="nx">v</span><span class="p">)</span>
+ <span class="nx">routes</span><span class="p">.</span><span class="nx">push</span> <span class="nv">verb: </span><span class="s1">&#39;get&#39;</span><span class="p">,</span> <span class="nv">path: </span><span class="nx">k</span><span class="p">,</span> <span class="nv">handler: </span><span class="nx">js</span><span class="p">,</span> <span class="nv">contentType: </span><span class="s1">&#39;js&#39;</span>
+
+ <span class="nv">root_locals.css = </span><span class="nf">(obj) -&gt;</span>
+ <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">obj</span>
+ <span class="nv">css = </span><span class="nb">String</span><span class="p">(</span><span class="nx">v</span><span class="p">)</span>
+ <span class="nx">routes</span><span class="p">.</span><span class="nx">push</span> <span class="nv">verb: </span><span class="s1">&#39;get&#39;</span><span class="p">,</span> <span class="nv">path: </span><span class="nx">k</span><span class="p">,</span> <span class="nv">handler: </span><span class="nx">css</span><span class="p">,</span> <span class="nv">contentType: </span><span class="s1">&#39;css&#39;</span>
+
+ <span class="nv">root_locals.helper = </span><span class="nf">(obj) -&gt;</span>
+ <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">obj</span>
+ <span class="nx">helpers_names</span><span class="p">.</span><span class="nx">push</span> <span class="nx">k</span>
+ <span class="nx">helpers</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">v</span>
+
+ <span class="nv">root_locals.def = </span><span class="nf">(obj) -&gt;</span>
+ <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">obj</span>
+ <span class="nx">defs_names</span><span class="p">.</span><span class="nx">push</span> <span class="nx">k</span>
+ <span class="nx">defs</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">v</span>
+
+ <span class="nv">root_locals.at = </span><span class="nf">(obj) -&gt;</span>
+ <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">obj</span>
+ <span class="nx">ws_handlers</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">v</span>
+
+ <span class="nv">root_locals.view = </span><span class="nf">(obj) -&gt;</span>
+ <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">obj</span>
+ <span class="nx">views</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">v</span>
+
+ <span class="nv">root_locals.set = </span><span class="nf">(obj) -&gt;</span>
+ <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">obj</span>
+ <span class="nx">app</span><span class="p">.</span><span class="nx">set</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span>
+
+ <span class="nv">root_locals.use = </span><span class="nf">(obj) -&gt;</span>
+ <span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">.</span><span class="nx">apply</span> <span class="nx">app</span><span class="p">,</span> <span class="nx">arguments</span>
+
+ <span class="nv">root_locals.configure = </span><span class="o">-&gt;</span>
+ <span class="nx">app</span><span class="p">.</span><span class="nx">configure</span><span class="p">.</span><span class="nx">apply</span> <span class="nx">app</span><span class="p">,</span> <span class="nx">arguments</span>
+
+ <span class="nv">root_locals.include = </span><span class="nf">(name) -&gt;</span>
+ <span class="nv">sub = </span><span class="nx">require</span> <span class="nx">name</span>
+ <span class="nv">rewritten_sub = </span><span class="nx">rewrite_function</span><span class="p">(</span><span class="nx">sub</span><span class="p">,</span> <span class="nx">root_locals_names</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">globals</span><span class="p">))</span>
+ <span class="nx">rewritten_sub</span><span class="p">(</span><span class="nx">root_context</span><span class="p">,</span> <span class="nx">root_locals</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">&#182;</a> </div> <p>Executes the (rewriten) end-user function and learns how the app should be structured.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">rewritten_root = </span><span class="nx">rewrite_function</span><span class="p">(</span><span class="nx">root_function</span><span class="p">,</span> <span class="nx">root_locals_names</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">globals</span><span class="p">))</span>
+ <span class="nx">rewritten_root</span><span class="p">(</span><span class="nx">root_context</span><span class="p">,</span> <span class="nx">root_locals</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">&#182;</a> </div> <p>Implements the application according to the specification.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">helpers</span>
+ <span class="nx">helpers</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">rewrite_function</span><span class="p">(</span><span class="nx">v</span><span class="p">,</span> <span class="nx">http_locals_names</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">helpers_names</span><span class="p">).</span><span class="nx">concat</span><span class="p">(</span><span class="nx">defs_names</span><span class="p">).</span><span class="nx">concat</span><span class="p">(</span><span class="nx">globals</span><span class="p">))</span>
+
+ <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">ws_handlers</span>
+ <span class="nx">ws_handlers</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">rewrite_function</span><span class="p">(</span><span class="nx">v</span><span class="p">,</span> <span class="nx">ws_locals_names</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">helpers_names</span><span class="p">).</span><span class="nx">concat</span><span class="p">(</span><span class="nx">defs_names</span><span class="p">).</span><span class="nx">concat</span><span class="p">(</span><span class="nx">globals</span><span class="p">))</span>
+
+ <span class="k">if</span> <span class="nx">app</span><span class="p">.</span><span class="nx">settings</span><span class="p">[</span><span class="s1">&#39;zappa serve client&#39;</span><span class="p">]</span>
+ <span class="nx">app</span><span class="p">.</span><span class="nx">get</span> <span class="s1">&#39;/zappa/zappa.js&#39;</span><span class="p">,</span> <span class="nf">(req, res) -&gt;</span>
+ <span class="nx">res</span><span class="p">.</span><span class="nx">contentType</span> <span class="s1">&#39;js&#39;</span>
+ <span class="nx">res</span><span class="p">.</span><span class="nx">send</span> <span class="s2">&quot;;#{coffeescript_helpers}(#{zappa_client_js})();&quot;</span>
+
+ <span class="k">if</span> <span class="nx">app</span><span class="p">.</span><span class="nx">settings</span><span class="p">[</span><span class="s1">&#39;zappa serve jquery&#39;</span><span class="p">]</span>
+ <span class="nx">app</span><span class="p">.</span><span class="nx">get</span> <span class="s1">&#39;/zappa/jquery.js&#39;</span><span class="p">,</span> <span class="nf">(req, res) -&gt;</span>
+ <span class="nx">res</span><span class="p">.</span><span class="nx">contentType</span> <span class="s1">&#39;js&#39;</span>
+ <span class="nx">fs</span><span class="p">.</span><span class="nx">readFile</span> <span class="s1">&#39;node_modules/jquery/dist/node-jquery.min.js&#39;</span><span class="p">,</span> <span class="nf">(err, data) -&gt;</span>
+ <span class="nx">res</span><span class="p">.</span><span class="nx">send</span> <span class="nx">data</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</span>
+
+ <span class="k">if</span> <span class="nx">app</span><span class="p">.</span><span class="nx">settings</span><span class="p">[</span><span class="s1">&#39;zappa serve sammy&#39;</span><span class="p">]</span>
+ <span class="nx">app</span><span class="p">.</span><span class="nx">get</span> <span class="s1">&#39;/zappa/sammy.js&#39;</span><span class="p">,</span> <span class="nf">(req, res) -&gt;</span>
+ <span class="nx">res</span><span class="p">.</span><span class="nx">contentType</span> <span class="s1">&#39;js&#39;</span>
+ <span class="nx">fs</span><span class="p">.</span><span class="nx">readFile</span> <span class="s1">&#39;sammy.min.js&#39;</span><span class="p">,</span> <span class="nf">(err, data) -&gt;</span>
+ <span class="nx">res</span><span class="p">.</span><span class="nx">send</span> <span class="nx">data</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">&#182;</a> </div> <p>Implements the http server with express.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">for</span> <span class="nx">r</span> <span class="k">in</span> <span class="nx">routes</span>
+ <span class="nx">do</span> <span class="nf">(r) -&gt;</span>
+ <span class="k">if</span> <span class="k">typeof</span> <span class="nx">r</span><span class="p">.</span><span class="nx">handler</span> <span class="o">is</span> <span class="s1">&#39;string&#39;</span>
+ <span class="nx">app</span><span class="p">[</span><span class="nx">r</span><span class="p">.</span><span class="nx">verb</span><span class="p">]</span> <span class="nx">r</span><span class="p">.</span><span class="nx">path</span><span class="p">,</span> <span class="nf">(req, res) -&gt;</span>
+ <span class="nx">res</span><span class="p">.</span><span class="nx">contentType</span> <span class="nx">r</span><span class="p">.</span><span class="nx">contentType</span> <span class="k">if</span> <span class="nx">r</span><span class="p">.</span><span class="nx">contentType</span><span class="o">?</span>
+ <span class="nx">res</span><span class="p">.</span><span class="nx">send</span> <span class="nx">r</span><span class="p">.</span><span class="nx">handler</span>
+ <span class="k">else</span>
+ <span class="nv">rewritten_handler = </span><span class="nx">rewrite_function</span><span class="p">(</span><span class="nx">r</span><span class="p">.</span><span class="nx">handler</span><span class="p">,</span>
+ <span class="nx">http_locals_names</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">helpers_names</span><span class="p">).</span><span class="nx">concat</span><span class="p">(</span><span class="nx">defs_names</span><span class="p">).</span><span class="nx">concat</span><span class="p">(</span><span class="nx">globals</span><span class="p">))</span>
+
+ <span class="nv">context = </span><span class="kc">null</span>
+ <span class="nv">locals = </span><span class="p">{}</span>
+ <span class="nx">locals</span><span class="p">[</span><span class="nx">g</span><span class="p">]</span> <span class="o">=</span> <span class="nb">eval</span><span class="p">(</span><span class="nx">g</span><span class="p">)</span> <span class="k">for</span> <span class="nx">g</span> <span class="k">in</span> <span class="nx">globals</span>
+
+ <span class="k">for</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">def</span> <span class="k">of</span> <span class="nx">defs</span>
+ <span class="nx">locals</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="nx">def</span>
+
+ <span class="k">for</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">helper</span> <span class="k">of</span> <span class="nx">helpers</span>
+ <span class="nx">locals</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="o">-&gt;</span>
+ <span class="nx">helper</span><span class="p">(</span><span class="nx">context</span><span class="p">,</span> <span class="nx">locals</span><span class="p">,</span> <span class="nx">arguments</span><span class="p">)</span>
+
+ <span class="nx">app</span><span class="p">[</span><span class="nx">r</span><span class="p">.</span><span class="nx">verb</span><span class="p">]</span> <span class="nx">r</span><span class="p">.</span><span class="nx">path</span><span class="p">,</span> <span class="nf">(req, res, next) -&gt;</span>
+ <span class="nv">context = </span><span class="p">{}</span>
+ <span class="nx">context</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">v</span> <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">req</span><span class="p">.</span><span class="nx">query</span>
+ <span class="nx">context</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">v</span> <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">req</span><span class="p">.</span><span class="nx">params</span>
+ <span class="nx">context</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">v</span> <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span>
+ <span class="nv">locals.params = </span><span class="nx">context</span>
+ <span class="nv">locals.request = </span><span class="nx">req</span>
+ <span class="nv">locals.response = </span><span class="nx">res</span>
+ <span class="nv">locals.next = </span><span class="nx">next</span>
+ <span class="nv">locals.send = </span><span class="o">-&gt;</span> <span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">.</span><span class="nx">apply</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">arguments</span>
+ <span class="nv">locals.render = </span><span class="o">-&gt;</span>
+ <span class="nv">args = </span><span class="p">[]</span>
+ <span class="nx">args</span><span class="p">.</span><span class="nx">push</span> <span class="nx">a</span> <span class="k">for</span> <span class="nx">a</span> <span class="k">in</span> <span class="nx">arguments</span>
+ <span class="nx">args</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">?=</span> <span class="p">{}</span>
+ <span class="nx">args</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">v</span> <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">context</span>
+ <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">.</span><span class="nx">apply</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">args</span>
+ <span class="nv">locals.redirect = </span><span class="o">-&gt;</span> <span class="nx">res</span><span class="p">.</span><span class="nx">redirect</span><span class="p">.</span><span class="nx">apply</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">arguments</span>
+ <span class="nv">result = </span><span class="nx">rewritten_handler</span><span class="p">(</span><span class="nx">context</span><span class="p">,</span> <span class="nx">locals</span><span class="p">)</span>
+ <span class="nx">res</span><span class="p">.</span><span class="nx">contentType</span><span class="p">(</span><span class="nx">r</span><span class="p">.</span><span class="nx">contentType</span><span class="p">)</span> <span class="k">if</span> <span class="nx">r</span><span class="p">.</span><span class="nx">contentType</span><span class="o">?</span>
+ <span class="k">if</span> <span class="k">typeof</span> <span class="nx">result</span> <span class="o">is</span> <span class="s1">&#39;string&#39;</span> <span class="k">then</span> <span class="nx">res</span><span class="p">.</span><span class="nx">send</span> <span class="nx">result</span>
+ <span class="k">else</span> <span class="k">return</span> <span class="nx">result</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">&#182;</a> </div> <p>Implements the websockets server with socket.io.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">io</span><span class="p">.</span><span class="nx">sockets</span><span class="p">.</span><span class="kc">on</span> <span class="s1">&#39;connection&#39;</span><span class="p">,</span> <span class="nf">(socket) -&gt;</span>
+ <span class="nv">context = </span><span class="p">{}</span>
+ <span class="nv">locals = </span><span class="p">{</span><span class="nx">socket</span><span class="p">,</span> <span class="nv">id: </span><span class="nx">socket</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span> <span class="nv">client: </span><span class="p">{}}</span>
+ <span class="nx">locals</span><span class="p">[</span><span class="nx">g</span><span class="p">]</span> <span class="o">=</span> <span class="nb">eval</span><span class="p">(</span><span class="nx">g</span><span class="p">)</span> <span class="k">for</span> <span class="nx">g</span> <span class="k">in</span> <span class="nx">globals</span>
+
+ <span class="k">for</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">def</span> <span class="k">of</span> <span class="nx">defs</span>
+ <span class="nx">locals</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="nx">def</span>
+
+ <span class="k">for</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">helper</span> <span class="k">of</span> <span class="nx">helpers</span>
+ <span class="nx">locals</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="o">-&gt;</span>
+ <span class="nx">helper</span><span class="p">(</span><span class="nx">context</span><span class="p">,</span> <span class="nx">locals</span><span class="p">,</span> <span class="nx">arguments</span><span class="p">)</span>
+
+ <span class="nx">ws_handlers</span><span class="p">.</span><span class="nx">connection</span><span class="p">(</span><span class="nx">context</span><span class="p">,</span> <span class="nx">locals</span><span class="p">)</span> <span class="k">if</span> <span class="nx">ws_handlers</span><span class="p">.</span><span class="nx">connection</span><span class="o">?</span>
+
+ <span class="nx">socket</span><span class="p">.</span><span class="kc">on</span> <span class="s1">&#39;disconnect&#39;</span><span class="p">,</span> <span class="o">-&gt;</span>
+ <span class="nv">context = </span><span class="p">{}</span>
+ <span class="nx">ws_handlers</span><span class="p">.</span><span class="nx">disconnect</span><span class="p">(</span><span class="nx">context</span><span class="p">,</span> <span class="nx">locals</span><span class="p">)</span> <span class="k">if</span> <span class="nx">ws_handlers</span><span class="p">.</span><span class="nx">disconnect</span><span class="o">?</span>
+
+ <span class="k">for</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">h</span> <span class="k">of</span> <span class="nx">ws_handlers</span>
+ <span class="k">if</span> <span class="nx">name</span> <span class="o">isnt</span> <span class="s1">&#39;connection&#39;</span> <span class="o">and</span> <span class="nx">name</span> <span class="o">isnt</span> <span class="s1">&#39;disconnect&#39;</span>
+ <span class="nx">socket</span><span class="p">.</span><span class="kc">on</span> <span class="nx">name</span><span class="p">,</span> <span class="nf">(data) -&gt;</span>
+ <span class="nv">context = </span><span class="p">{}</span>
+ <span class="nv">locals.params = </span><span class="nx">context</span>
+ <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">data</span>
+ <span class="nx">context</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">v</span>
+ <span class="nx">h</span><span class="p">(</span><span class="nx">context</span><span class="p">,</span> <span class="nx">locals</span><span class="p">)</span>
+
+ <span class="p">{</span><span class="nx">app</span><span class="p">,</span> <span class="nx">io</span><span class="p">}</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">&#182;</a> </div> <p>Takes a function and runs it as a zappa app. Optionally accepts a number for port,
+and/or a string for hostname (any order).
+Returns an object where <code>app</code> is the express server and <code>io</code> is the socket.io handle.
+Ex.:
+ require('zappa').run -> get '/': 'hi'
+ require('zappa').run 80, -> get '/': 'hi'
+ require('zappa').run 'domain.com', 80, -> get '/': 'hi'</p> </td> <td class="code"> <div class="highlight"><pre><span class="vi">@run = </span><span class="o">-&gt;</span>
+ <span class="nv">host = </span><span class="kc">null</span>
+ <span class="nv">port = </span><span class="mi">5678</span>
+ <span class="nv">root_function = </span><span class="kc">null</span>
+
+ <span class="k">for</span> <span class="nx">a</span> <span class="k">in</span> <span class="nx">arguments</span>
+ <span class="k">switch</span> <span class="k">typeof</span> <span class="nx">a</span>
+ <span class="k">when</span> <span class="s1">&#39;string&#39;</span> <span class="k">then</span> <span class="nv">host = </span><span class="nx">a</span>
+ <span class="k">when</span> <span class="s1">&#39;number&#39;</span> <span class="k">then</span> <span class="nv">port = </span><span class="nx">a</span>
+ <span class="k">when</span> <span class="s1">&#39;function&#39;</span> <span class="k">then</span> <span class="nv">root_function = </span><span class="nx">a</span>
+
+ <span class="nv">zapp = </span><span class="nx">@app</span><span class="p">(</span><span class="nx">root_function</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="nx">host</span><span class="o">?</span> <span class="k">then</span> <span class="nx">zapp</span><span class="p">.</span><span class="nx">app</span><span class="p">.</span><span class="nx">listen</span> <span class="nx">port</span><span class="p">,</span> <span class="nx">host</span>
+ <span class="k">else</span> <span class="nx">zapp</span><span class="p">.</span><span class="nx">app</span><span class="p">.</span><span class="nx">listen</span> <span class="nx">port</span>
+
+ <span class="nx">zapp</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">&#182;</a> </div> <p>Client-side zappa.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">zappa_client = </span><span class="o">-&gt;</span>
+ <span class="nv">zappa = </span><span class="nb">window</span><span class="p">.</span><span class="nv">zappa = </span><span class="p">{}</span>
+ <span class="nv">zappa.version = </span><span class="kc">null</span>
+
+ <span class="nv">coffeescript_helpers = </span><span class="kc">null</span>
+ <span class="nv">rewrite_function = </span><span class="kc">null</span>
+
+ <span class="nv">zappa.run = </span><span class="nf">(root_function) -&gt;</span>
+ <span class="nv">root_locals_names = </span><span class="p">[</span><span class="s1">&#39;def&#39;</span><span class="p">,</span> <span class="s1">&#39;helper&#39;</span><span class="p">,</span> <span class="s1">&#39;get&#39;</span><span class="p">,</span> <span class="s1">&#39;socket&#39;</span><span class="p">,</span> <span class="s1">&#39;connect&#39;</span><span class="p">,</span> <span class="s1">&#39;at&#39;</span><span class="p">]</span>
+ <span class="nv">sammy_locals_names = </span><span class="p">[]</span>
+ <span class="nv">ws_locals_names = </span><span class="p">[</span><span class="s1">&#39;socket&#39;</span><span class="p">,</span> <span class="s1">&#39;id&#39;</span><span class="p">,</span> <span class="s1">&#39;params&#39;</span><span class="p">,</span> <span class="s1">&#39;client&#39;</span><span class="p">]</span>
+ <span class="nv">helpers_names = </span><span class="p">[]</span>
+ <span class="nv">defs_names = </span><span class="p">[]</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-18">&#182;</a> </div> <p>Storage for the functions provided by the user.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">routes = </span><span class="p">[]</span>
+ <span class="nv">ws_handlers = </span><span class="p">{}</span>
+ <span class="nv">helpers = </span><span class="p">{}</span>
+ <span class="nv">defs = </span><span class="p">{}</span>
+
+ <span class="nv">socket = </span><span class="kc">null</span>
+ <span class="nv">app = </span><span class="nx">Sammy</span><span class="p">()</span> <span class="k">if</span> <span class="nx">Sammy</span><span class="o">?</span>
+
+ <span class="nv">root_context = </span><span class="p">{}</span>
+ <span class="nv">root_locals = </span><span class="p">{}</span>
+
+ <span class="nv">root_locals.get = </span><span class="o">-&gt;</span>
+ <span class="k">if</span> <span class="k">typeof</span> <span class="nx">arguments</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">isnt</span> <span class="s1">&#39;object&#39;</span>
+ <span class="nx">routes</span><span class="p">.</span><span class="nx">push</span><span class="p">({</span><span class="nv">path: </span><span class="nx">arguments</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nv">handler: </span><span class="nx">arguments</span><span class="p">[</span><span class="mi">1</span><span class="p">]})</span>
+ <span class="k">else</span>
+ <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">arguments</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
+ <span class="nx">routes</span><span class="p">.</span><span class="nx">push</span><span class="p">({</span><span class="nv">path: </span><span class="nx">k</span><span class="p">,</span> <span class="nv">handler: </span><span class="nx">v</span><span class="p">})</span>
+
+ <span class="nv">root_locals.helper = </span><span class="nf">(obj) -&gt;</span>
+ <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">obj</span>
+ <span class="nx">helpers_names</span><span class="p">.</span><span class="nx">push</span> <span class="nx">k</span>
+ <span class="nx">helpers</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">v</span>
+
+ <span class="nv">root_locals.def = </span><span class="nf">(obj) -&gt;</span>
+ <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">obj</span>
+ <span class="nx">defs_names</span><span class="p">.</span><span class="nx">push</span> <span class="nx">k</span>
+ <span class="nx">defs</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">v</span>
+
+ <span class="nv">root_locals.at = </span><span class="nf">(obj) -&gt;</span>
+ <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">obj</span>
+ <span class="nx">ws_handlers</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">v</span>
+
+ <span class="nv">root_locals.connect = </span><span class="o">-&gt;</span>
+ <span class="nv">socket = </span><span class="nx">io</span><span class="p">.</span><span class="nx">connect</span><span class="p">.</span><span class="nx">apply</span> <span class="nx">io</span><span class="p">,</span> <span class="nx">arguments</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-19">&#182;</a> </div> <p>Executes the (rewriten) end-user function and learns how the app should be structured.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">rewritten_root = </span><span class="nx">rewrite_function</span><span class="p">(</span><span class="nx">root_function</span><span class="p">,</span> <span class="nx">root_locals_names</span><span class="p">)</span>
+ <span class="nx">rewritten_root</span><span class="p">(</span><span class="nx">root_context</span><span class="p">,</span> <span class="nx">root_locals</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-20">&#182;</a> </div> <p>Implements the application according to the specification.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">helpers</span>
+ <span class="nx">helpers</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">rewrite_function</span><span class="p">(</span><span class="nx">v</span><span class="p">,</span> <span class="nx">http_locals_names</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">helpers_names</span><span class="p">).</span><span class="nx">concat</span><span class="p">(</span><span class="nx">defs_names</span><span class="p">))</span>
+
+ <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">ws_handlers</span>
+ <span class="nx">ws_handlers</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">rewrite_function</span><span class="p">(</span><span class="nx">v</span><span class="p">,</span> <span class="nx">ws_locals_names</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">helpers_names</span><span class="p">).</span><span class="nx">concat</span><span class="p">(</span><span class="nx">defs_names</span><span class="p">))</span>
+
+ <span class="k">for</span> <span class="nx">r</span> <span class="k">in</span> <span class="nx">routes</span>
+ <span class="nx">do</span> <span class="nf">(r) -&gt;</span>
+ <span class="nv">rewritten_handler = </span><span class="nx">rewrite_function</span><span class="p">(</span><span class="nx">r</span><span class="p">.</span><span class="nx">handler</span><span class="p">,</span>
+ <span class="nx">sammy_locals_names</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">helpers_names</span><span class="p">).</span><span class="nx">concat</span><span class="p">(</span><span class="nx">defs_names</span><span class="p">))</span>
+
+ <span class="nv">context = </span><span class="kc">null</span>
+ <span class="nv">locals = </span><span class="p">{}</span>
+
+ <span class="k">for</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">def</span> <span class="k">of</span> <span class="nx">defs</span>
+ <span class="nx">locals</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="nx">def</span>
+
+ <span class="k">for</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">helper</span> <span class="k">of</span> <span class="nx">helpers</span>
+ <span class="nx">locals</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="o">-&gt;</span>
+ <span class="nx">helper</span><span class="p">(</span><span class="nx">context</span><span class="p">,</span> <span class="nx">locals</span><span class="p">,</span> <span class="nx">arguments</span><span class="p">)</span>
+
+ <span class="nx">app</span><span class="p">.</span><span class="nx">get</span> <span class="nx">r</span><span class="p">.</span><span class="nx">path</span><span class="p">,</span> <span class="o">-&gt;</span>
+ <span class="nv">context = </span><span class="p">{}</span>
+ <span class="nv">locals.params = </span><span class="nx">context</span>
+ <span class="nx">rewritten_handler</span><span class="p">(</span><span class="nx">context</span><span class="p">,</span> <span class="nx">locals</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-21">&#182;</a> </div> <p>Implements the websockets client with socket.io.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">socket</span><span class="o">?</span>
+ <span class="nv">context = </span><span class="p">{}</span>
+ <span class="nv">locals = </span><span class="p">{</span><span class="nx">socket</span><span class="p">}</span>
+
+ <span class="k">for</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">def</span> <span class="k">of</span> <span class="nx">defs</span>
+ <span class="nx">locals</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="nx">def</span>
+
+ <span class="k">for</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">helper</span> <span class="k">of</span> <span class="nx">helpers</span>
+ <span class="nx">locals</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="o">-&gt;</span>
+ <span class="nx">helper</span><span class="p">(</span><span class="nx">context</span><span class="p">,</span> <span class="nx">locals</span><span class="p">,</span> <span class="nx">arguments</span><span class="p">)</span>
+
+ <span class="k">for</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">h</span> <span class="k">of</span> <span class="nx">ws_handlers</span>
+ <span class="nx">socket</span><span class="p">.</span><span class="kc">on</span> <span class="nx">name</span><span class="p">,</span> <span class="nf">(data) -&gt;</span>
+ <span class="nv">context = </span><span class="p">{}</span>
+ <span class="nv">locals.params = </span><span class="nx">context</span>
+ <span class="k">for</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">data</span>
+ <span class="nx">context</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">v</span>
+ <span class="nx">h</span><span class="p">(</span><span class="nx">context</span><span class="p">,</span> <span class="nx">locals</span><span class="p">)</span>
+
+ <span class="nx">$</span><span class="p">(</span><span class="o">-&gt;</span> <span class="nx">app</span><span class="p">.</span><span class="nx">run</span> <span class="s1">&#39;#/&#39;</span><span class="p">)</span>
+
+<span class="nv">zappa_client_js = </span><span class="nb">String</span><span class="p">(</span><span class="nx">zappa_client</span><span class="p">)</span>
+ <span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="s1">&#39;version = null;&#39;</span><span class="p">,</span> <span class="s2">&quot;version = &#39;#{@version}&#39;;&quot;</span><span class="p">)</span>
+ <span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="s1">&#39;coffeescript_helpers = null;&#39;</span><span class="p">,</span> <span class="s2">&quot;var coffeescript_helpers = &#39;#{coffeescript_helpers}&#39;;&quot;</span><span class="p">)</span>
+ <span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="s1">&#39;rewrite_function = null;&#39;</span><span class="p">,</span> <span class="s2">&quot;var rewrite_function = #{rewrite_function};&quot;</span><span class="p">)</span>
+ <span class="p">.</span><span class="nx">replace</span> <span class="sr">/(\n)/g</span><span class="p">,</span> <span class="s1">&#39;&#39;</span>
+
+</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
View
15 package.json
@@ -1,7 +1,7 @@
{
"name": "zappa",
- "description": "Web development, cut-the-crap style.",
- "version": "0.1.5",
+ "description": "CoffeeScript DSL-ish interface to node development.",
+ "version": "0.2.0",
"author": "Maurice Machado <maurice@bitbending.com>",
"contributors": [
{"name": "Maurice Machado", "email": "maurice@bitbending.com"},
@@ -12,14 +12,11 @@
],
"repository": {"type": "git", "url": "http://github.com/mauricemach/zappa.git"},
"dependencies": {
- "express": ">= 2.3.0",
- "coffeekup": ">= 0.2.3",
- "coffee-script": ">= 1.0.1",
- "socket.io": ">= 0.6.3",
- "jquery": ">= 1.5.1"
+ "express": ">= 2.4.2",
+ "coffee-script": ">= 1.1.1",
+ "socket.io": ">= 0.7.6"
},
"keywords": ["framework", "websockets", "coffeescript"],
- "bin": "./bin/zappa",
"main": "./lib/zappa",
- "engines": { "node": ">= 0.4.1" }
+ "engines": { "node": ">= 0.4.9" }
}
View
790 src/zappa.coffee
@@ -1,393 +1,17 @@
-zappa = exports
-express = require 'express'
-fs = require 'fs'
-puts = console.log
-{inspect} = require 'sys'
-coffee = null
-jquery = null
-io = null
-coffeekup = null
-
-class Zappa
- constructor: ->
- @context = {}
- @apps = {}
- @current_app = null
-
- @locals =
- app: (name) => @app name
- include: (path) => @include path
- require: require
- global: global
- process: process
- module: module
-
- for name in 'get|post|put|del|route|at|msg|client|using|def|helper|postrender|layout|view|style'.split '|'
- do (name) =>
- @locals[name] = =>
- @ensure_app 'default' unless @current_app?
- @current_app[name].apply @current_app, arguments
-
- app: (name) ->
- @ensure_app name
- @current_app = @apps[name]
-
- include: (file) ->
- @define_with @read_and_compile(file)
- puts "Included file \"#{file}\""
+# **Zappa** is a [CoffeeScript](http://coffeescript.org) DSL-ish interface for building web apps on the
+# [node.js](http://nodejs.org) runtime, integrating [express](http://expressjs.com), [socket.io](http://socket.io)
+# and other best-of-breed libraries.
- define_with: (code) ->
- scoped(code)(@context, @locals)
+log = console.log
+fs = require 'fs'
- ensure_app: (name) ->
- @apps[name] = new App(name) unless @apps[name]?
- @current_app = @apps[name] unless @current_app?
+@version = '0.2.0'
- read_and_compile: (file) ->
- coffee = require 'coffee-script'
- code = @read file
- coffee.compile code
-
- read: (file) -> fs.readFileSync file, 'utf8'
-
- run_file: (file, options) ->
- @locals.__filename = require('path').join(process.cwd(), file)
- @locals.__dirname = process.cwd()
- @locals.module.filename = @locals.__filename
- code = if file.match /\.coffee$/ then @read_and_compile file else @read file
- @run code, options
-
- run: (code, options) ->
- options ?= {}
-
- @define_with code
-
- i = 0
- for k, a of @apps
- opts = {}
- if options.port
- opts.port = if options.port[i]? then options.port[i] else a.port + i
- else if i isnt 0
- opts.port = a.port + i
-
- opts.hostname = options.hostname if options.hostname
-
- a.start opts
- i++
-
-class App
- constructor: (@name) ->
- @name ?= 'default'
- @port = 5678
-
- @http_server = express.createServer()
- if coffeekup?
- @http_server.register '.coffee', coffeekup
- @http_server.set 'view engine', 'coffee'
- @http_server.configure =>
- @http_server.use express.static("#{process.cwd()}/public")
- @http_server.use express.bodyParser()
- @http_server.use express.cookieParser()
- # TODO: Make the secret configurable.
- @http_server.use express.session(secret: 'hackme')
-
- # App-level vars, exposed to handlers as [app]."
- @vars = {}
-
- @defs = {}
- @helpers = {}
- @postrenders = {}
- @socket_handlers = {}
- @msg_handlers = {}
-
- @views = {}
- @layouts = {}
- @layouts.default = ->
- doctype 5
- html ->
- head ->
- title @title if @title
- if @scripts
- for s in @scripts
- script src: s + '.js'
- script(src: @script + '.js') if @script
- if @stylesheets
- for s in @stylesheets
- link rel: 'stylesheet', href: s + '.css'
- link(rel: 'stylesheet', href: @stylesheet + '.css') if @stylesheet
- style @style if @style
- body @content
-
- start: (options) ->
- options ?= {}
- @port = options.port if options.port
- @hostname = options.hostname if options.hostname
-
- if io?
- @ws_server = io.listen @http_server, {log: ->}
- @ws_server.on 'connection', (client) =>
- @socket_handlers.connection?.execute client
- client.on 'disconnect', => @socket_handlers.disconnection?.execute client
- client.on 'message', (raw_msg) =>
- msg = parse_msg raw_msg
- @msg_handlers[msg.title]?.execute client, msg.params
-
- if @hostname? then @http_server.listen @port, @hostname
- else @http_server.listen @port
-
- puts "App \"#{@name}\" listening on #{if @hostname? then @hostname + ':' else '*:'}#{@port}..."
- @http_server
-
- get: -> @route 'get', arguments
- post: -> @route 'post', arguments
- put: -> @route 'put', arguments
- del: -> @route 'del', arguments
- route: (verb, args) ->
- if typeof args[0] isnt 'object'
- @register_route verb, args[0], args[1]
- else
- for k, v of args[0]
- @register_route verb, k, v
-
- register_route: (verb, path, response) ->
- if typeof response isnt 'function'
- @http_server[verb] path, (req, res) -> res.send String(response)
- else
- handler = new RequestHandler(response, @defs, @helpers, @postrenders, @views, @layouts, @vars)
- @http_server[verb] path, (req, res, next) ->
- handler.execute(req, res, next)
-
- using: ->
- pairs = {}
- for a in arguments
- pairs[a] = require(a)
- @def pairs
-
- def: (pairs) ->
- for k, v of pairs
- @defs[k] = v
-
- helper: (pairs) ->
- for k, v of pairs
- @helpers[k] = scoped(v)
-
- postrender: (pairs) ->
- jquery = require 'jquery'
- for k, v of pairs
- @postrenders[k] = scoped(v)
-
- at: (pairs) ->
- io = require 'socket.io'
- for k, v of pairs
- @socket_handlers[k] = new MessageHandler(v, @)
-
- msg: (pairs) ->
- io = require 'socket.io'
- for k, v of pairs
- @msg_handlers[k] = new MessageHandler(v, @)
-
- layout: (arg) ->
- pairs = if typeof arg is 'object' then arg else {default: arg}
- coffeekup = require 'coffeekup'
- for k, v of pairs
- @layouts[k] = v
-
- view: (arg) ->
- pairs = if typeof arg is 'object' then arg else {default: arg}
- coffeekup = require 'coffeekup'
- for k, v of pairs
- @views[k] = v
-
- client: (arg) ->
- pairs = if typeof arg is 'object' then arg else {default: arg}
- for k, v of pairs
- do (k, v) =>
- code = ";(#{v})();"
- @http_server.get "/#{k}.js", (req, res) ->
- res.contentType 'bla.js'
- res.send code
-
- style: (arg) ->
- pairs = if typeof arg is 'object' then arg else {default: arg}
- for k, v of pairs
- do (k, v) =>
- @http_server.get "/#{k}.css", (req, res) ->
- res.contentType 'bla.css'
- res.send v
-
-class RequestHandler
- constructor: (handler, @defs, @helpers, @postrenders, @views, @layouts, @vars) ->
- @handler = scoped(handler)
- @locals = null
-
- init_locals: ->
- @locals = {}
- @locals.app = @vars
- @locals.render = @render
- @locals.partial = @partial
- @locals.redirect = @redirect
- @locals.send = @send
- @locals.puts = puts
-
- for k, v of @defs
- @locals[k] = v
-
- for k, v of @helpers
- do (k, v) =>
- @locals[k] = ->
- v(@context, @, arguments)
-
- @locals.defs = @defs
- @locals.postrenders = @postrenders
- @locals.views = @views
- @locals.layouts = @layouts
-
- execute: (request, response, next) ->
- @init_locals() unless @locals?
-
- @locals.context = {}
- @locals.params = @locals.context
-
- @locals.request = request
- @locals.response = response
- @locals.next = next
-
- @locals.session = request.session
- @locals.cookies = request.cookies
-
- for k, v of request.query
- @locals.context[k] = v
- for k, v of request.params
- @locals.context[k] = v
- for k, v of request.body
- @locals.context[k] = v
-
- result = @handler(@locals.context, @locals)
-
- if typeof result is 'string'
- response.send result
- else
- result
-
- redirect: -> @response.redirect.apply @response, arguments
- send: -> @response.send.apply @response, arguments
-
- render: (template, options) ->
- options ?= {}
- options.layout ?= 'default'
-
- opts = options.options or {} # Options for the templating engine.
- opts.context ?= @context
- opts.context.zappa = partial: @partial
- opts.locals ?= {}
- opts.locals.partial = (template, context) ->
- text ck_options.context.zappa.partial template, context
-
- template = @views[template] if typeof template is 'string'
-
- result = coffeekup.render template, opts
-
- if typeof options.apply is 'string'
- postrender = @postrenders[options.apply]
- body = jquery('body')
- body.empty().html(result)
- postrender opts.context, jquery.extend(@defs, {$: jquery})
- result = body.html()
-
- if options.layout
- layout = @layouts[options.layout]
- opts.context.content = result
- result = coffeekup.render layout, opts
-
- @response.send result
-
- null
-
- partial: (template, context) =>
- template = @views[template]
- coffeekup.render(template, context: context)
-
-class MessageHandler
- constructor: (handler, @app) ->
- @handler = scoped(handler)
- @locals = null
-
- init_locals: ->
- @locals = {}
- @locals.app = @app.vars
- @locals.render = @render
- @locals.partial = @partial
- @locals.puts = puts
-
- for k, v of @app.defs
- @locals[k] = v
-
- for k, v of @app.helpers
- do (k, v) =>
- @locals[k] = ->
- v(@context, @, arguments)
-
- @locals.defs = @app.defs
- @locals.postrenders = @app.postrenders
- @locals.views = @app.views
- @locals.layouts = @app.layouts
-
- execute: (client, params) ->
- @init_locals() unless @locals?
-
- @locals.context = {}
- @locals.params = @locals.context
- @locals.client = client
- # TODO: Move this to context.
- @locals.id = client.sessionId
- @locals.send = (title, data) => client.send build_msg(title, data)
- @locals.broadcast = (title, data, except) =>
- except ?= []
- if except not instanceof Array then except = [except]
- except.push @locals.id
- @app.ws_server.broadcast build_msg(title, data), except
-
- for k, v of params
- @locals.context[k] = v
-
- @handler(@locals.context, @locals)
-
- render: (template, options) ->
- options ?= {}
- options.layout ?= 'default'
-
- opts = options.options or {} # Options for the templating engine.
- opts.context ?= @context
- opts.context.zappa = partial: @partial
- opts.locals ?= {}
- opts.locals.partial = (template, context) ->
- text ck_options.context.zappa.partial template, context
-
- template = @app.views[template] if typeof template is 'string'
-
- result = coffeekup.render template, opts
-
- if typeof options.apply is 'string'
- postrender = @postrenders[options.apply]
- body = jquery('body')
- body.empty().html(result)
- postrender opts.context, jquery.extend(@defs, {$: jquery})
- result = body.html()
-
- if options.layout
- layout = @layouts[options.layout]
- opts.context.content = result
- result = coffeekup.render layout, opts
-
- @send 'render', value: result
-
- null
-
- partial: (template, context) =>
- template = @app.views[template]
- coffeekup.render(template, context: context)
-
-coffeescript_support = """
+# CoffeeScript-generated JavaScript may contain anyone of these; when we "rewrite"
+# a function (see below) though, it loses access to its parent scope, and consequently to
+# any helpers it might need. So we need to reintroduce these helpers manually inside any
+# "rewritten" function.
+coffeescript_helpers = """
var __slice = Array.prototype.slice;
var __hasProp = Object.prototype.hasOwnProperty;
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
@@ -395,42 +19,372 @@ coffeescript_support = """
for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype;
- return child;
- };
+ return child; };
var __indexOf = Array.prototype.indexOf || function(item) {
for (var i = 0, l = this.length; i < l; i++) {
if (this[i] === item) return i;
- }
- return -1;
- };
-"""
-
-build_msg = (title, data) ->
- obj = {}
- obj[title] = data
- JSON.stringify(obj)
-
-parse_msg = (raw_msg) ->
- obj = JSON.parse(raw_msg)
- for k, v of obj
- return {title: k, params: v}
-
-scoped = (code) ->
- code = String(code)
- code = "function () {#{code}}" unless code.indexOf('function') is 0
- code = "#{coffeescript_support} with(locals) {return (#{code}).apply(context, args);}"
+ } return -1; };
+""".replace /\n/g, ''
+
+# "Rewrites" a function so that it accepts the value of @/this ("context")
+# and local variables as parameters.
+# The names of local variables to be "extracted" have to be provided beforehand.
+# The function will lose access to its parent scope in the process.
+rewrite_function = (func, locals_names) ->
+ code = String(func)
+ code = "function () {#{code}}" unless code.indexOf 'function' is 0
+ code = "#{coffeescript_helpers}return (#{code}).apply(context, args);"
+ for name in locals_names
+ code = "var #{name} = locals.#{name};" + code
new Function('context', 'locals', 'args', code)
-publish_api = (from, to, methods) ->
- for name in methods.split '|'
- do (name) ->
- if typeof from[name] is 'function'
- to[name] = -> from[name].apply from, arguments
+# Takes in a function and builds express/socket.io apps based on the rules contained in it.
+@app = (root_function) ->
+ # Names of local variables that we have to know beforehand, to use with `rewrite_function`.
+ # Helpers and defs will be known after we execute the user-provided `root_function`.
+ # TODO: __filename and __dirname won't work this way. Find another solution.
+ globals = ['global', 'process', 'console', 'require', '__filename', '__dirname',
+ 'module', 'setTimeout', 'clearTimeout', 'setInterval', 'clearInterval']
+ # TODO: using?, route?, postrender?, enable, disable, settings, error
+ root_locals_names = ['express', 'io', 'app', 'get', 'post', 'put', 'del', 'at',
+ 'helper', 'def', 'view', 'set', 'use', 'configure', 'include', 'client', 'coffee', 'js', 'css',
+ 'enable', 'disable']
+ # TODO: app? (something shared with ws_handlers), app.clients?
+ http_locals_names = ['response', 'request', 'next', 'params', 'send', 'render', 'redirect']
+ # TODO: emit?, broadcast, render?, app? (shared between http-ws, persistent)
+ ws_locals_names = ['socket', 'id', 'params', 'client']
+ helpers_names = []
+ defs_names = []
+
+ # Storage for the functions provided by the user.
+ routes = []
+ ws_handlers = {}
+ helpers = {}
+ defs = {}
+ views = {}
+
+ # Builds the applications's root scope.
+ express = require 'express'
+ socketio = require 'socket.io'
+
+ # Monkeypatch express to support inline templates. Such is life.
+ express.View.prototype.__defineGetter__ 'exists', ->
+ return true if views[@view]?
+ try
+ fs.statSync(@path)
+ return true
+ catch err
+ return false
+ express.View.prototype.__defineGetter__ 'contents', ->
+ return views[@view] if views[@view]?
+ fs.readFileSync @path, 'utf8'
+
+ app = express.createServer()
+ io = socketio.listen(app)
+ io.set 'log level', 1
+
+ root_context = {}
+ root_locals = {express, io, app}
+ root_locals[g] = eval(g) for g in globals
+
+ for verb in ['get', 'post', 'put', 'del']
+ do (verb) ->
+ root_locals[verb] = ->
+ if typeof arguments[0] isnt 'object'
+ routes.push verb: verb, path: arguments[0], handler: arguments[1]
+ else
+ for k, v of arguments[0]
+ routes.push verb: verb, path: k, handler: v
+
+ root_locals.client = (obj) ->
+ app.enable 'zappa serve client'
+ for k, v of obj
+ js = ";zappa.run(#{v});"
+ routes.push verb: 'get', path: k, handler: js, contentType: 'js'
+
+ root_locals.coffee = (obj) ->
+ for k, v of obj
+ js = ";#{coffeescript_helpers}(#{v})();"
+ routes.push verb: 'get', path: k, handler: js, contentType: 'js'
+
+ root_locals.js = (obj) ->
+ for k, v of obj
+ js = String(v)
+ routes.push verb: 'get', path: k, handler: js, contentType: 'js'
+
+ root_locals.css = (obj) ->
+ for k, v of obj
+ css = String(v)
+ routes.push verb: 'get', path: k, handler: css, contentType: 'css'
+
+ root_locals.helper = (obj) ->
+ for k, v of obj
+ helpers_names.push k
+ helpers[k] = v
+
+ root_locals.def = (obj) ->
+ for k, v of obj
+ defs_names.push k
+ defs[k] = v
+
+ root_locals.at = (obj) ->
+ for k, v of obj
+ ws_handlers[k] = v
+
+ root_locals.view = (obj) ->
+ for k, v of obj
+ views[k] = v
+
+ root_locals.set = (obj) ->
+ for k, v of obj
+ app.set k, v
+
+ root_locals.use = (obj) ->
+ app.use.apply app, arguments
+
+ root_locals.configure = ->
+ app.configure.apply app, arguments
+
+ root_locals.include = (name) ->
+ sub = require name
+ rewritten_sub = rewrite_function(sub, root_locals_names.concat(globals))
+ rewritten_sub(root_context, root_locals)
+
+ # Executes the (rewriten) end-user function and learns how the app should be structured.
+ rewritten_root = rewrite_function(root_function, root_locals_names.concat(globals))
+ rewritten_root(root_context, root_locals)
+
+ # Implements the application according to the specification.
+
+ for k, v of helpers
+ helpers[k] = rewrite_function(v, http_locals_names.concat(helpers_names).concat(defs_names).concat(globals))
+
+ for k, v of ws_handlers
+ ws_handlers[k] = rewrite_function(v, ws_locals_names.concat(helpers_names).concat(defs_names).concat(globals))
+
+ if app.settings['zappa serve client']
+ app.get '/zappa/zappa.js', (req, res) ->
+ res.contentType 'js'
+ res.send ";#{coffeescript_helpers}(#{zappa_client_js})();"
+
+ if app.settings['zappa serve jquery']
+ app.get '/zappa/jquery.js', (req, res) ->
+ res.contentType 'js'
+ fs.readFile 'node_modules/jquery/dist/node-jquery.min.js', (err, data) ->
+ res.send data.toString()
+
+ if app.settings['zappa serve sammy']
+ app.get '/zappa/sammy.js', (req, res) ->
+ res.contentType 'js'
+ fs.readFile 'sammy.min.js', (err, data) ->
+ res.send data.toString()
+
+ # Implements the http server with express.
+ for r in routes
+ do (r) ->
+ if typeof r.handler is 'string'
+ app[r.verb] r.path, (req, res) ->
+ res.contentType r.contentType if r.contentType?
+ res.send r.handler
+ else
+ rewritten_handler = rewrite_function(r.handler,
+ http_locals_names.concat(helpers_names).concat(defs_names).concat(globals))
+
+ context = null
+ locals = {}
+ locals[g] = eval(g) for g in globals
+
+ for name, def of defs
+ locals[name] = def
+
+ for name, helper of helpers
+ locals[name] = ->
+ helper(context, locals, arguments)
+
+ app[r.verb] r.path, (req, res, next) ->
+ context = {}
+ context[k] = v for k, v of req.query
+ context[k] = v for k, v of req.params
+ context[k] = v for k, v of req.body
+ locals.params = context
+ locals.request = req
+ locals.response = res
+ locals.next = next
+ locals.send = -> res.send.apply res, arguments
+ locals.render = ->
+ args = []
+ args.push a for a in arguments
+ args[1] ?= {}
+ args[1][k] = v for k, v of context
+ res.render.apply res, args
+ locals.redirect = -> res.redirect.apply res, arguments
+ result = rewritten_handler(context, locals)
+ res.contentType(r.contentType) if r.contentType?
+ if typeof result is 'string' then res.send result
+ else return result
+
+ # Implements the websockets server with socket.io.
+ io.sockets.on 'connection', (socket) ->
+ context = {}
+ locals = {socket, id: socket.id, client: {}}
+ locals[g] = eval(g) for g in globals
+
+ for name, def of defs
+ locals[name] = def
+
+ for name, helper of helpers
+ locals[name] = ->
+ helper(context, locals, arguments)
+
+ ws_handlers.connection(context, locals) if ws_handlers.connection?
+
+ socket.on 'disconnect', ->
+ context = {}
+ ws_handlers.disconnect(context, locals) if ws_handlers.disconnect?
+
+ for name, h of ws_handlers
+ if name isnt 'connection' and name isnt 'disconnect'
+ socket.on name, (data) ->
+ context = {}
+ locals.params = context
+ for k, v of data
+ context[k] = v
+ h(context, locals)
+
+ {app, io}
+
+# Takes a function and runs it as a zappa app. Optionally accepts a number for port,
+# and/or a string for hostname (any order).
+# Returns an object where `app` is the express server and `io` is the socket.io handle.
+# Ex.:
+# require('zappa').run -> get '/': 'hi'
+# require('zappa').run 80, -> get '/': 'hi'
+# require('zappa').run 'domain.com', 80, -> get '/': 'hi'
+@run = ->
+ host = null
+ port = 5678
+ root_function = null
+
+ for a in arguments
+ switch typeof a
+ when 'string' then host = a
+ when 'number' then port = a
+ when 'function' then root_function = a
+
+ zapp = @app(root_function)
+
+ if host? then zapp.app.listen port, host
+ else zapp.app.listen port
+
+ zapp
+
+# Client-side zappa.
+zappa_client = ->
+ zappa = window.zappa = {}
+ zappa.version = null
+
+ coffeescript_helpers = null
+ rewrite_function = null
+
+ zappa.run = (root_function) ->
+ root_locals_names = ['def', 'helper', 'get', 'socket', 'connect', 'at']
+ sammy_locals_names = []
+ ws_locals_names = ['socket', 'id', 'params', 'client']
+ helpers_names = []
+ defs_names = []
+
+ # Storage for the functions provided by the user.
+ routes = []
+ ws_handlers = {}
+ helpers = {}
+ defs = {}
+
+ socket = null
+ app = Sammy() if Sammy?
+
+ root_context = {}
+ root_locals = {}
+
+ root_locals.get = ->
+ if typeof arguments[0] isnt 'object'
+ routes.push({path: arguments[0], handler: arguments[1]})
else
- to[name] = from[name]
+ for k, v of arguments[0]
+ routes.push({path: k, handler: v})
+
+ root_locals.helper = (obj) ->
+ for k, v of obj
+ helpers_names.push k
+ helpers[k] = v
+
+ root_locals.def = (obj) ->
+ for k, v of obj
+ defs_names.push k
+ defs[k] = v
+
+ root_locals.at = (obj) ->
+ for k, v of obj
+ ws_handlers[k] = v
+
+ root_locals.connect = ->
+ socket = io.connect.apply io, arguments
+
+ # Executes the (rewriten) end-user function and learns how the app should be structured.
+ rewritten_root = rewrite_function(root_function, root_locals_names)
+ rewritten_root(root_context, root_locals)
+
+ # Implements the application according to the specification.
+
+ for k, v of helpers
+ helpers[k] = rewrite_function(v, http_locals_names.concat(helpers_names).concat(defs_names))
+
+ for k, v of ws_handlers
+ ws_handlers[k] = rewrite_function(v, ws_locals_names.concat(helpers_names).concat(defs_names))
+
+ for r in routes
+ do (r) ->
+ rewritten_handler = rewrite_function(r.handler,
+ sammy_locals_names.concat(helpers_names).concat(defs_names))
+
+ context = null
+ locals = {}
+
+ for name, def of defs
+ locals[name] = def
+
+ for name, helper of helpers
+ locals[name] = ->
+ helper(context, locals, arguments)
+
+ app.get r.path, ->
+ context = {}
+ locals.params = context
+ rewritten_handler(context, locals)
+
+ # Implements the websockets client with socket.io.
+ if socket?
+ context = {}
+ locals = {socket}
+
+ for name, def of defs
+ locals[name] = def
+
+ for name, helper of helpers
+ locals[name] = ->
+ helper(context, locals, arguments)
+
+ for name, h of ws_handlers
+ socket.on name, (data) ->
+ context = {}
+ locals.params = context
+ for k, v of data
+ context[k] = v
+ h(context, locals)
-z = new Zappa()
+ $(-> app.run '#/')
-zappa.version = '0.1.5'
-zappa.run = -> z.run.apply z, arguments
-zappa.run_file = -> z.run_file.apply z, arguments
+zappa_client_js = String(zappa_client)
+ .replace('version = null;', "version = '#{@version}';")
+ .replace('coffeescript_helpers = null;', "var coffeescript_helpers = '#{coffeescript_helpers}';")
+ .replace('rewrite_function = null;', "var rewrite_function = #{rewrite_function};")
+ .replace /(\n)/g, ''
Please sign in to comment.
Something went wrong with that request. Please try again.