<%= 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 the code that embeds dynamic 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:
- Javascript (via rhino or nashorn), or graalvm
- Java (via beanshell),
- Python (via Jython),
- ruby (via jruby),
- lua (via luaj),
- lisp (via armed bear common lisp),
- or something more esoteric.
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" %> GOOD EVENING. <% for (var i=1; i<10; i++) { %> <%= i %> <% } %> AH HA HA. I LOVE TO COUNT THINGS
or this
<%@ jessop language="java" engine="beanshell" %> GOOD EVENING. <% for (int i=0; i<10; i++) { %> <%= i %> <% } %> AH HA HA. I LOVE TO COUNT THINGS
or this
<%@ jessop language="ruby" engine="jruby" %> GOOD EVENING. <% (1..10).each do |i| %> <%= i %> <% end %> AH HA HA. I LOVE TO COUNT THINGS
or this
<%@ jessop language="python" engine="jython" %> GOOD EVENING. <% for i in range(1, 10): %> <%= i %> AH HA HA. I LOVE TO COUNT THINGS
or this
<%@ jessop language="lua" engine="luaj" %> GOOD EVENING. <% for i=1,10 do %> <%= i %> <% end %> AH HA HA. I LOVE TO COUNT THINGS
or this
<%@ jessop language="lisp" engine="ABCL" %> GOOD EVENING. <% (loop for i from 1 to 10 do %> <%= i %> <% ) %> AH HA HA. I LOVE TO COUNT THINGS
These aren’t particularly good examples, they just show that the templating language is the language specified in that <%@ jessop %>
declaration in the first line. Which makes the template readabale by anyone who knows that language without having to learn or use some pretend template language that has half the features and uses the word “powerful” and “extensible” in their advertising copy.
You’ll need to put the jessop JAR onto your classpath, as well as whatever scripting engine you’re intending to use.
It’s up on github, and if you’re using maven it’s got the artifactId:groupId of com.randomnoun.common:jessop.
Here’s some links 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)
2019-12-23: jessop 1.0.15 released: added javascript support again (this time using graal’s javascript)
2020-01-09: added a link to github
Reminds me of https://imgs.xkcd.com/comics/standards.png