5. Artistic programming
And so we reach the third and final level of our journey. The other two levels are pretty much complete in explaining them and how to use them. What follows for the rest of this tome is all about the third level.
The third level is the shedding of constraints. We take those snippets of code from the second level and we run them through code transformations. This enables us to do just about anything. Even more, we can call out to external programs, feeding the snippets in as standard input and receiving the output as the next form of the snippet.
This is the level of complete artistry. We can write little mini-languages to make efficient input. We can use a wide variety of text transformations of one language to the next all smoothly in the code. We can weave in user-end documentation, tests, sanity checks, compile contexts, and whatever else we can dream of, to make the job of coding, and all of its ancillary tasks, efficient and enjoyable.
The basic command syntax uses pipe syntax. Instead of just a reference,
such as _"name", we can pipe the incoming text into a command, or series of
commands, such as _"name | cat awesome, _"dude" | sub A, b". This would
take the text in the reference name and send it through the command cat which
concatenates stuff together. In particular it would join the incoming text
with awesome and the stuff in the dude section. Then that resulting text
goes through the sub command and all instances of A get replaced with b.
Note that section names can be referenced in the command arguments.
Sub
To start with, let’s say we want to create functions for the arithmetic
operators. That is, we want to be able to write add(4, 5) instead of 4+5.
In JavaScript, we could do
var add = function (a, b) {
return a + b;
}
And that would be fine. We could then do that for subtraction, multiplication, and division. But that is a bit repetitive. So instead we can do
# Operators
We want to convert the operators to functions.
We start with a basic form using addition
var OP = function (a, b) {
return a ?? b;
}
When done we will save it in [ops.js](#math-ops "save:")
## Math ops
Let's create the operators
_"operators| sub OP, add, ??, +"
_"operators| sub OP, mul, ??, *"
_"operators| sub OP, div, ??, /"
_"operators| sub OP, sub, ??, -"
And that generates the following in a file called ops.js.
var add = function (a, b) {
return a + b;
}
var mul = function (a, b) {
return a * b;
}
var div = function (a, b) {
return a / b;
}
var sub = function (a, b) {
return a - b;
}
This is not that exciting of an example. And there are a number of ways we could have approached this with a simple copy and paste being one of them. Indeed, the four lines of litpro code is copy and pasted (it is also possible to run some custom code to do this more elegantly, but this is a simple introduction).
But you may wonder what is the advantage? The creative effort is about the same level, but now all four are dependent on each other. This may be good, it may not be good. It is good if you later decide to modify this. For example, you may want to check that the operators are numbers. Or you may want to round the result or cast it into some other form. By modifying the originating function, we get all of them modified at once. That is, the benefit is in the maintenance.
The downside is that they are coupled. So, for example if we want to inject a test for division by zero, we need to add something to facilitate that. One solution is to put in a comment line that gets replaced with what you need.
# Operators
We want to convert the operators to functions.
The ?? will be replaced with operator symbols. We check for something to be a
number and then do the computation. This is not really necessary nor perhaps
the best to do it, but there you have it.
var OP = function (a, b) {
if (Number.isNumber(a) && Number.isNumber(b) ) {
//rep
return a ?? b;
} else {
return NaN;
}
}
When done we will save it in [ops2.js](#math-ops "save:")
## Math ops
Let's create the operators
_"operators| sub OP, add, ??, +"
_"operators| sub OP, mul, ??, *"
_"operators| sub OP, div, ??, /, //rep, _"division by zero" "
_"operators| sub OP, sub, ??, -"
## Division by zero
The division by zero is so bad so let's deal it. Let's be bad mathematical
people and give some values of oo, -oo, and 1
if (b === 0) {
if (a > 0) {
return Infinity;
} else if (a < 0) {
return -Infinity;
} else {
return 1;
}
}
Turning into:
var add = function (a, b) {
if (Number.isNumber(a) && Number.isNumber(b) ) {
//rep
return a + b;
} else {
return NaN;
}
}
var mul = function (a, b) {
if (Number.isNumber(a) && Number.isNumber(b) ) {
//rep
return a * b;
} else {
return NaN;
}
}
var div = function (a, b) {
if (Number.isNumber(a) && Number.isNumber(b) ) {
if (b === 0) {
if (a > 0) {
return Infinity;
} else if (a < 0) {
return -Infinity;
} else {
return 1;
}
}
return a / b;
} else {
return NaN;
}
}
var sub = function (a, b) {
if (Number.isNumber(a) && Number.isNumber(b) ) {
//rep
return a - b;
} else {
return NaN;
}
}
This could easily become cumbersome. As is generally true with this style of programming, it is a matter of artistic choice as to which is the most useful and clear in any given situation. It is likely to evolve over time just as repeating similar code often evolves into pulling it out to functions. This is just one of the stops along the way.
5.1 Web
As another example, let’s say we are creating a web page. We want to have the
content written in markdown, but we want to create the structure in pug (formerly the jade language).
Let’s presume that the commands to convert them are md and pug,
respectively.
# Webpage
We are going to make a web page.
[web.html](#structure "save:|log | jade | compile structure ")
## Structure
We use the HTML5 elements of nav, article and aside in their appropriate
roles. The nav is very lame.
nav
.left Click
.right Clack
article \_":content |md "
aside \_"announcements |md "
script \_"js stuff | jshint "
[content]()
Here we have some great body content
# Best Webs Ever
We have the best webs **ever**.
## Silk
Yeah, we got spider silk. [Kevlar strength](kevlar.html). Real cool.
### Announcements
Whatever we want to say
_Open Now!_
## js Stuff
Just some random javascript. The jshint will check it for errors and such.
var a, b;
if (a = b) {
a = 2;
} else {
// never reached;
}
Jshint just loves it when one uses assignment instead of equality testing in a
boolean expression.
Note that jshint still allows it to be built. It will just give a warning on
the command line.
This yields
<nav>
<div class="left">Click</div>
<div class="right">Clack</div>
</nav>
<article><h1>Best Webs Ever</h1>
<p>We have the best webs <strong>ever</strong>.</p>
<h2>Silk</h2>
<p>Yeah, we got spider silk. <a href="kevlar.html">Kevlar strength</a>. Real coo\
l.</p>
</article>
<aside><p><em>Open Now!</em></p>
</aside>
<script>var a, b;
if (a = b) {
a = 2;
} else {
// never reached;
}</script>
The easiest way to run this is with literate-programming which has both markdown and pug included.
But to run this with litpro, one needs to use the lprc.js file that defines these commands.
There are other methods that we’ll discuss later, but this is perhaps the most useful method.
The lprc.js file requires the modules markdown-it and pug. We also include jshint which was done to check the script that we snuck in there.
module.exports = function (Folder, args) {
if (args.file.length === 0) {
args.file = ["web.md"];
}
if (!Folder.prototype.local) {
Folder.prototype.local = {};
}
require('litpro-jshint')(Folder, args);
var jade = require('pug');
Folder.sync("pug" , function (code, args) {
options = args.join(",").trim();
if (options) {
options = JSON.parse(options);
} else {
options = {'pretty':true};
}
return jade.render(code, options);
});
var md = require('markdown-it')({
html:true,
linkify:true
});
Folder.prototype.local.md = md;
Folder.sync( "md", function (code, args) {
return md.render(code);
});
};
We will discuss a lot of what is going on in this example as time goes on. But notice how we can cut up our assembly of the material, run them through commands, and get a nice compiled output.
The backslashes are escaping the substitution in the first round as mixing pug with compiled HTML content does not lead to good results. So we compile the pug and then when that is ready, we call the compile command to run that through our standard compiler. In this example, we need to include the structure named section as the overarching section.