<%= post.title %>

In the begining there was C

So anyway, back when the world wide web was young and mostly tax-free, you had a thing called a web server which served up poorly formatted but mostly academic content which were stored in HTML files.

HTML had the ability to include form fields inside the text using things like <INPUT> tags, which captured information from the reader via white rectangles that look like this: . Your web browser then sent those values back to the web server, which forwarded that information to a separate process using a thing called the Common Gateway Interface. This was a standard way of piping the data into a separate process, using stdin and some environment variables, and to pipe the output generated by stdout back to the user.

Back in the day, these things would be written in C, or perl, or bash, and mostly consisted of a bit of code to decode the form fields, a few if/then/else constructs to work out what the user intended, maybe hit a database or two, followed by a ridiculous number of printf()s to generate the output.

A bit like this:

/* remeber cgic ? of course you do. */
#include <stdlib.h>
#include <string.h>
#include <cgic.h>

int cgiMain() {
  char name[241];
  cgiFormString("name", name, 241);
  if (strncmp(name, "", 241)==0) { strncpy(name, "World", 241); }

  cgiHeaderContentType("text/html");
  fprintf(cgiOut, "<HTML><HEAD>\n");
  fprintf(cgiOut, "<TITLE>countingtoseven.com</TITLE></HEAD>\n");
  fprintf(cgiOut, "<BODY><H1>countingtoseven.com</H1>\n");
  fprintf(cgiOut, "<P>Hello, %s\n", name);
  fprintf(cgiOut, "<P>Welcome to countingtoseven.com, the worldwide premier ");
  fprintf(cgiOut, "destination for counting to seven.\n");
  fprintf(cgiOut, "<HR/>\n");
  fprintf(cgiOut, "<BLINK>Frequently Asked Question</BLINK>\n");
  fprintf(cgiOut, "<BR/>Q) How do I count to seven ?\n");
  fprintf(cgiOut, "<BR/>A) Like this:\n");
  for (int i=1; i<=7; i++) {
    fprintf(cgiOut, "<BR/>%d\n", i);
  }
  fprintf(cgiOut, "<BR/>Q) Hang about. My name isn't %s.\n", name);
  fprintf(cgiOut, "<BR/>A) Well, what is it, then ?\n");
  fprintf(cgiOut, "<BR/>Q) That's a question, not an answer.\n");
  fprintf(cgiOut, "<BR/>A) And that's not a question.\n");
  fprintf(cgiOut, "<BR/>Q) Whatever. My name is <INPUT TYPE=\"text\" NAME=\"name\"/>\n");
  fprintf(cgiOut, "<BR/>A) <INPUT TYPE=\"submit\" NAME=\"submit\" VALUE=\"Pleased to meet you\">\n");
  fprintf(cgiOut, "</BODY></HTML>\n");
  exit(0);
}

(these days, of course, you’d replace the BLINK tag with your multi-megabyte responsive javascript web framework of choice).

Mindless repetition

Most sane people dumped the unchanging parts of those fprintf statements into a separate file, and used some kind of tokenising system for replacing bits of text into other bits of text. So instead of fprintf(cgiOut, "%s",xx), people would use ${xx} syntax or [[xx]] syntax or <%=xx%> syntax or {{xx}} syntax for the dynamic bits, making the template look like this instead:

<HTML><HEAD>
<TITLE>countingtoseven.com</TITLE></HEAD>
<BODY><H1>countingtoseven.com</H1>
<P>Hello, <%= name %>
<P>Welcome to countingtoseven.com, the worldwide premiere
destination for counting to seven.
<HR/>
<H1>Frequently Asked Question</H1>
<BR/>Q) How do I count to seven ? 
<BR/>A) Like this:
<% for (int i=1; i<= 7; i++ { fprintf(cgiOut "<BR/>%d\n", i);
} %>
<BR/>Q) Hang about. My name isn't <%= name %>
<BR/>A) Well, what is it, then ?
<BR/>Q) That's a question, not an answer.
<BR/>A) And that's not a question.
<BR/>Q) Whatever. My name is <INPUT TYPE="text" NAME="name"/>
<BR/>A) <INPUT TYPE="submit" NAME="submit" VALUE="Pleased to meet you">
</BODY></HTML>

which had the advantage of being viewable in a actual web browser, or in FrontPage, HotDog “Professional” or Dreamweaver, if you remember those.

So you’d either call a C function to read the file, perform the substitutions, and generate the output, or run it through some kind of preprocessor to add the boilerplate C code and wrap everything in fprintf statements, then compile and run that, which gave you the advantage of being able to stick C code into your template.

!@#^%ing delimiters

Then Microsoft came along with this thing called Active Server Pages (or ASP) which they included in their newfangled IIS server, which used <% ... %> syntax to denote code, and <%= ... %> syntax to denote the relatively common case of generating dynamic content.

Sun then came up with Java Server Pages (or JSP), which used similar syntax; and then PHP invented their own way of doing that, and became inexplicably popular. This was about the same time that ColdFusion came into existence and was then consigned into the dustbin of history.

So anyway, every year or two since then, the new language on the block invents the new templating language on the block, which allows you to “powerfully” loop over an array or something using some idiosyncratic syntax they’ve pulled out of their arse.

I imagine this is the sort of thing that SAP developers do.

So if you’re inventing a new templating language, then (a) don’t, and (b) use that syntax.

TL;DR

So anyway, here’s a new templating language. It’s called Jessop.

It runs on top of the Java Scripting API, which provides a standard interface to running non-Java languages on the JVM.

It uses the ASP/JSP conventions of using <% ... %> syntax to denote code, and <%= ... %> syntax to denote the common case of generating dynamic content.

It also uses the JSP convention of using <%@ ... %> to denote declarations, which are used to tell the parser how to interpret the rest of the file.

Using the scripting API means that the language used within those <% ... %> and <%= ... %> blocks can be any language which is supported by the Java Scripting API, including:

Why should I use that ?

Because you don’t want to learn yet another language so that you can get your Enterprise-Ready Distributed Modular Rules Engine to count to seven, or invent another DSL so that users can add fields to a report.

It’s also BSD-licensed, which you’ll probably prefer to the alternatives.

How should I use that ?

Here’s a contrived example:

package com.randomnoun.contrived.jessop;

import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;
import javax.script.ScriptException;

import java.util.Scanner

public class JessopTest {
  public void main(String args[]) throws ScriptException {
    String script = new Scanner(new File(args[1])).useDelimiter("\\Z").next();
    ScriptEngine engine = new ScriptEngineManager().getEngineByName("jessop");
    if (engine==null) { throw new IllegalStateException("Missing engine 'jessop'"); }
    engine.eval(script);
  }
}

then feed it something like this:

<%@ jessop language="javascript" engine="rhino" %>
just some text
<% for (var i=1; i<10; i++) { %>
<%= i %>
<% } %>

or this

<%@ jessop language="java" engine="beanshell" %>
just some text
<% for (int i=0; i<10; i++) { %>
<%= i %>
<% } %>

or this

<%@ jessop language="ruby" engine="jruby" %>
just some text
<% (1..10).each do |i| %>
<%= i %>
<% end %>

or this

<%@ jessop language="python" engine="jython" %>
just some text
<% for i in range(1, 10): %>
<%= i %>

or this

<%@ jessop language="lua" engine="luaj" %>
just some text
<% for i=1,10 do %>
<%= i %>
<% end %>

or this

<%@ jessop language="lisp" engine="ABCL" %>
just some text
<% (loop for i from 1 to 10 do %>
<%= i %>
<% ) %>

You’ll need to put the jessop JAR onto your classpath, as well as whatever scripting engine you’re intending to use.

If you’re using maven, it’s got the artifactId:groupId of com.randomnoun.common:jessop.

Here’s a link to it.

There should be some more detailed information if you hit the big brown button above.

I should probably see what node.js does before unleashing this quality software product into the world. No, it looks like they’ve sharted out even more incompatible nonsense. There’s more of these than goddamn wiki markup languages, I tell you.


[1]: if you felt like getting pwned
[2]: which I still loathe with a passion, but that’s what the cool kids are using these days


Updates

2016-08-08: jessop 1.0.5 released: addded ruby language support (via jruby)
2016-12-28: jessop 1.0.8 released: added lisp language support (via abcl)

Add a Comment

Your email address will not be published. Required fields are marked *