CoffeeKup optimization (v3)

Revision 3 of this benchmark created by Omar Khan on


Description

Experimental optimization of CoffeeKup templates using UglifyJS for static analysis.

This test runs the following template, from the coffeekup benchmark script:

doctype 5
html lang: 'en', ->
  head ->
    meta charset: 'utf-8'
    title @title
    style '''
      body {font-family: "sans-serif"}
      section, header {display: block}
    '
''
  body ->
    section ->
      header ->
        h1 @title
      if @inspired
        p 'Create a witty example'
      else
        p 'Go meta'
      ul ->
        for user in @users
          li user.name
          li -> a href: "mailto:\#{user.email}", -> user.email

The template is rendered using the following data:

data =
  title: 'test'
  inspired: no
  users: [
    {email: 'house@gmail.com', name: 'house'}
    {email: 'cuddy@gmail.com', name: 'cuddy'}
    {email: 'wilson@gmail.com', name: 'wilson'}
  ]

Preparation HTML

<script>
var template = function anonymous(data) {
var a,b,body,em,h1,head,header,html,i,ins,li,p,s,section,style,th,title,u,ul,font,tt,hr,meta;a = function(){return __ck.tag('a', arguments);};b = function(){return __ck.tag('b', arguments);};body = function(){return __ck.tag('body', arguments);};em = function(){return __ck.tag('em', arguments);};h1 = function(){return __ck.tag('h1', arguments);};head = function(){return __ck.tag('head', arguments);};header = function(){return __ck.tag('header', arguments);};html = function(){return __ck.tag('html', arguments);};i = function(){return __ck.tag('i', arguments);};ins = function(){return __ck.tag('ins', arguments);};li = function(){return __ck.tag('li', arguments);};p = function(){return __ck.tag('p', arguments);};s = function(){return __ck.tag('s', arguments);};section = function(){return __ck.tag('section', arguments);};style = function(){return __ck.tag('style', arguments);};th = function(){return __ck.tag('th', arguments);};title = function(){return __ck.tag('title', arguments);};u = function(){return __ck.tag('u', arguments);};ul = function(){return __ck.tag('ul', arguments);};font = function(){return __ck.tag('font', arguments);};tt = function(){return __ck.tag('tt', arguments);};hr = function(){return __ck.tag('hr', arguments);};meta = function(){return __ck.tag('meta', arguments);};var __slice = Array.prototype.slice;var __hasProp = Object.prototype.hasOwnProperty;var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };var __extends = function(child, parent) {  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; };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; };
    var coffeescript, comment, doctype, h, ie, tag, text, yield, __ck, _ref, _ref2;
    if (data == null) {
      data = {};
    }
    if ((_ref = data.format) == null) {
      data.format = false;
    }
    if ((_ref2 = data.autoescape) == null) {
      data.autoescape = false;
    }
    __ck = {
      buffer: [],
      esc: function(txt) {
        if (data.autoescape) {
          return h(txt);
        } else {
          return String(txt);
        }
      },
      tabs: 0,
      repeat: function(string, count) {
        return Array(count + 1).join(string);
      },
      indent: function() {
        if (data.format) {
          return text(this.repeat('  ', this.tabs));
        }
      },
      tag: function(name, args) {
        var combo, i, _i, _len;
        combo = [name];
        for (_i = 0, _len = args.length; _i < _len; _i++) {
          i = args[_i];
          combo.push(i);
        }
        return tag.apply(data, combo);
      },
      render_idclass: function(str) {
        var c, classes, i, id, _i, _j, _len, _len2, _ref3;
        classes = [];
        _ref3 = str.split('.');
        for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
          i = _ref3[_i];
          if (__indexOf.call(i, '#') >= 0) {
            id = i.replace('#', '');
          } else {
            if (i !== '') {
              classes.push(i);
            }
          }
        }
        if (id) {
          text(" id=\"" + id + "\"");
        }
        if (classes.length > 0) {
          text(" class=\"");
          for (_j = 0, _len2 = classes.length; _j < _len2; _j++) {
            c = classes[_j];
            if (c !== classes[0]) {
              text(' ');
            }
            text(c);
          }
          return text('"');
        }
      },
      render_attrs: function(obj, prefix) {
        var k, v, _results;
        if (prefix == null) {
          prefix = '';
        }
        _results = [];
        for (k in obj) {
          v = obj[k];
          if (typeof v === 'boolean' && v) {
            v = k;
          }
          if (typeof v === 'function') {
            v = "(" + v + ").call(this);";
          }
          _results.push(typeof v === 'object' && !(v instanceof Array) ? this.render_attrs(v, prefix + k + '-') : v ? text(" " + (prefix + k) + "=\"" + (this.esc(v)) + "\"") : void 0);
        }
        return _results;
      },
      render_contents: function(contents) {
        var result;
        switch (typeof contents) {
          case 'string':
          case 'number':
          case 'boolean':
            return text(this.esc(contents));
          case 'function':
            if (data.format) {
              text('\n');
            }
            this.tabs++;
            result = contents.call(data);
            if (typeof result === 'string') {
              this.indent();
              text(this.esc(result));
              if (data.format) {
                text('\n');
              }
            }
            this.tabs--;
            return this.indent();
        }
      },
      render_tag: function(name, idclass, attrs, contents) {
        this.indent();
        text("<" + name);
        if (idclass) {
          this.render_idclass(idclass);
        }
        if (attrs) {
          this.render_attrs(attrs);
        }
        if (__indexOf.call(this.self_closing, name) >= 0) {
          text(' />');
          if (data.format) {
            text('\n');
          }
        } else {
          text('>');
          this.render_contents(contents);
          text("</" + name + ">");
          if (data.format) {
            text('\n');
          }
        }
        return null;
      }
    };
    tag = function() {
      var a, args, attrs, contents, idclass, name, _i, _len;
      name = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
      for (_i = 0, _len = args.length; _i < _len; _i++) {
        a = args[_i];
        switch (typeof a) {
          case 'function':
            contents = a;
            break;
          case 'object':
            attrs = a;
            break;
          case 'number':
          case 'boolean':
            contents = a;
            break;
          case 'string':
            if (args.length === 1) {
              contents = a;
            } else {
              if (a === args[0]) {
                idclass = a;
              } else {
                contents = a;
              }
            }
        }
      }
      return __ck.render_tag(name, idclass, attrs, contents);
    };
    yield = function(f) {
      var old_buffer, temp_buffer;
      temp_buffer = [];
      old_buffer = __ck.buffer;
      __ck.buffer = temp_buffer;
      f();
      __ck.buffer = old_buffer;
      return temp_buffer.join('');
    };
    h = function(txt) {
      return String(txt).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
    };
    doctype = function(type) {
      if (type == null) {
        type = 'default';
      }
      text(__ck.doctypes[type]);
      if (data.format) {
        return text('\n');
      }
    };
    text = function(txt) {
      __ck.buffer.push(String(txt));
      return null;
    };
    comment = function(cmt) {
      text("<!--" + cmt + "-->");
      if (data.format) {
        return text('\n');
      }
    };
    coffeescript = function(param) {
      switch (typeof param) {
        case 'function':
          return script("" + __ck.coffeescript_helpers + "(" + param + ").call(this);");
        case 'string':
          return script({
            type: 'text/coffeescript'
          }, function() {
            return param;
          });
        case 'object':
          param.type = 'text/coffeescript';
          return script(param);
      }
    };
    ie = function(condition, contents) {
      __ck.indent();
      text("<!--[if " + condition + "]>");
      __ck.render_contents(contents);
      text("<![endif]-->");
      if (data.format) {
        return text('\n');
      }
    };
    __ck.doctypes = {"5":"<!DOCTYPE html>","default":"<!DOCTYPE html>","xml":"<?xml version=\"1.0\" encoding=\"utf-8\" ?>","transitional":"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">","strict":"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">","frameset":"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">","1.1":"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">","basic":"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML Basic 1.1//EN\" \"http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd\">","mobile":"<!DOCTYPE html PUBLIC \"-//WAPFORUM//DTD XHTML Mobile 1.2//EN\" \"http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd\">","ce":"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"ce-html-1.0-transitional.dtd\">"};__ck.coffeescript_helpers = "var __slice = Array.prototype.slice;var __hasProp = Object.prototype.hasOwnProperty;var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };var __extends = function(child, parent) {  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; };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; };";__ck.self_closing = ["area","base","br","col","command","embed","hr","img","input","keygen","link","meta","param","source","track","wbr","basefont","frame"];(function(){doctype(5);
html({
  lang: 'en'
}, function() {
  head(function() {
    meta({
      charset: 'utf-8'
    });
    title(this.title);
    return style('body {font-family: "sans-serif"}\nsection, header {display: block}');
  });
  return body(function() {
    return section(function() {
      header(function() {
        return h1(this.title);
      });
      if (this.inspired) {
        p('Create a witty example');
      } else {
        p('Go meta');
      }
      return ul(function() {
        var user, _i, _len, _ref, _results;
        _ref = this.users;
        _results = [];
        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
          user = _ref[_i];
          li(user.name);
          _results.push(li(function() {
            return a({
              href: "mailto:" + user.email
            }, function() {
              return user.email;
            });
          }));
        }
        return _results;
      });
    });
  });
});}).call(data);return __ck.buffer.join('');
};

var optimized = function anonymous(data) {
__ck = {
  buffer: ''
};
text = function(txt) {
  if (typeof txt === 'string' || txt instanceof String) {
    __ck.buffer += txt;
  } else if (typeof txt === 'number' || txt instanceof Number) {
    __ck.buffer += String(txt);
  }
};
h = function(txt) {
  var escaped;
  if (typeof txt === 'string' || txt instanceof String) {
    escaped = txt.replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;');
  } else {
    escaped = txt;
  }
  return escaped;
};
yield = function(f) {
  var temp_buffer = '';
  var old_buffer = __ck.buffer;
  __ck.buffer = temp_buffer;
  f();
  temp_buffer = __ck.buffer;
  __ck.buffer = old_buffer;
  return temp_buffer;
};
((function() {
  text("<!DOCTYPE html>");
  text('<html lang="en">');
  text(function() {
    text("<head>");
    text(function() {
      text('<meta charset="utf-8" />');
      text("<title>");
      text(this.title);
      text("</title>");
      return function() {
        text("<style>");
        text('body {font-family: "sans-serif"}\nsection, header {display: block}');
        text("</style>");
      }.call(data);
    }.call(data));
    text("</head>");
    return function() {
      text("<body>");
      text(function() {
        return function() {
          text("<section>");
          text(function() {
            text("<header>");
            text(function() {
              return function() {
                text("<h1>");
                text(this.title);
                text("</h1>");
              }.call(data);
            }.call(data));
            text("</header>");
            if (this.inspired) {
              text("<p>");
              text("Create a witty example");
              text("</p>");
            } else {
              text("<p>");
              text("Go meta");
              text("</p>");
            }
            return function() {
              text("<ul>");
              text(function() {
                var user, _i, _len, _ref, _results;
                _ref = this.users;
                _results = [];
                for (_i = 0, _len = _ref.length; _i < _len; _i++) {
                  user = _ref[_i];
                  text("<li>");
                  text(user.name);
                  text("</li>");
                  _results.push(function() {
                    text("<li>");
                    text(function() {
                      return function() {
                        text('<a href="');
                        text("mailto:" + user.email);
                        text('">');
                        text(function() {
                          return user.email;
                        }.call(data));
                        text("</a>");
                      }.call(data);
                    }.call(data));
                    text("</li>");
                  }.call(data));
                }
                return _results;
              }.call(data));
              text("</ul>");
            }.call(data);
          }.call(data));
          text("</section>");
        }.call(data);
      }.call(data));
      text("</body>");
    }.call(data);
  }.call(data));
  text("</html>");
})).call(data);return __ck.buffer;
};

var eco_template = function (__obj) {
  if (!__obj) __obj = {};
  var __out = [], __capture = function(callback) {
    var out = __out, result;
    __out = [];
    callback.call(this);
    result = __out.join('');
    __out = out;
    return __safe(result);
  }, __sanitize = function(value) {
    if (value && value.ecoSafe) {
      return value;
    } else if (typeof value !== 'undefined' && value != null) {
      return __escape(value);
    } else {
      return '';
    }
  }, __safe, __objSafe = __obj.safe, __escape = __obj.escape;
  __safe = __obj.safe = function(value) {
    if (value && value.ecoSafe) {
      return value;
    } else {
      if (!(typeof value !== 'undefined' && value != null)) value = '';
      var result = new String(value);
      result.ecoSafe = true;
      return result;
    }
  };
  if (!__escape) {
    __escape = __obj.escape = function(value) {
      return ('' + value)
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;');
    };
  }
  (function() {
    (function() {
      var user, _i, _len, _ref;
      __out.push('<!DOCTYPE html>\n<html lang="en">\n  <head>\n    <meta charset="utf-8">\n    <title>');
      __out.push(__sanitize(this.title));
      __out.push('</title>\n    <style>\n      body {font-family: "sans-serif"}\n      section, header {display: block}\n    </style>\n  </head>\n  <body>\n    <section>\n      <header>\n        <h1>');
      __out.push(__sanitize(this.title));
      __out.push('</h1>\n      </header>\n      ');
      if (this.inspired) {
        __out.push('\n        <p>Create a witty example</p>\n      ');
      } else {
        __out.push('\n        <p>Go meta</p>\n      ');
      }
      __out.push('\n      <ul>\n        ');
      _ref = this.users;
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        user = _ref[_i];
        __out.push('\n          <li>');
        __out.push(__sanitize(user.name));
        __out.push('</li>\n          <li><a href="mailto:');
        __out.push(__sanitize(user.email));
        __out.push('">');
        __out.push(__sanitize(user.email));
        __out.push('</a></li>\n        ');
      }
      __out.push('\n      </ul>\n    </section>\n  </body>\n</html>');
    }).call(this);
    
  }).call(__obj);
  __obj.safe = __objSafe, __obj.escape = __escape;
  return __out.join('');
};

var data = {
  title: 'test',
  inspired: false,
  users: [
    {
      email: 'house@gmail.com',
      name: 'house'
    }, {
      email: 'cuddy@gmail.com',
      name: 'cuddy'
    }, {
      email: 'wilson@gmail.com',
      name: 'wilson'
    }
  ]
};
</script>

Test runner

Ready to run.

Testing in
TestOps/sec
Compiled template
template(data);
ready
Optimized template
optimized(data);
ready
Eco template
eco_template(data);
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.