Text generation Part One

Prerequisites: You should have a basic working knowledge of JavaScript and HTML and have read about getting started.

ISHML's text generation API facilitates the creation of complex text generation objects using a templating system based on JavaScript's template literal notation. Specifically, ishml.Template is a tag function that may be called with either template literal notation or standard function call notation. Instead of returning text, however, ishml.Template returns an instance of ishml.Phrase. The template defines the phrase; the phrase generates the text.

This tutorial will start by defining simple phrases and then advance to nested, recursive, conditional, and looping text generation. You will get the most out of this tutorial if you experiment with the examples. Just click the link in the code listings to edit them in JSFiddle.

Hello, World

Listing 1 below shows the Hello World web page for ISHML's text generation API. If you click on the results tab, you will see a greeting. Clicking the results tab again or clicking on the Click here link updates the greeting.

Listing 1

Switch to the HTML tab. The ishml.js script provides access to the API. The second script, en-us.js, is an optional library of modern American English templates and phrase suffixes. Both scripts are often used together for English language text generation.

Switch to the JavaScript tab and study the code. First, we assign ishml.Template to a variable represented by an underscore. This is simply for convenience so that we don't have to type out ishml.Template over and over. The underscore was chose because it reflects the "fill in the blanks" nature of text generation. Next we assign a phrase to the myPhrase variable. This phrase happens to be a nested phrase. The outer phrase definition, Hello, _____, has an expression, denoted by ${...}, which defines an inner phrase. The inner phrase fills in the blank of the outer phrase with a random planet each time the text is generated. The last line of the script does the actual work of generating the text and places it inside the h1 element.

Defining Phrases

The syntax for defining phrases contains minimal punctuation. It is designed to get out of your way and give you a sense of the text to be generated just by glancing at the code. Listing 2 below demonstrates many styles of phrase definition. As you become more familiar with phrases, you will develop your own style. Sometimes template literal notation is preferred; sometimes standard function call notation is easier. Sometimes a deeply nested inline structure is the most straightforward, sometimes it is less confusing to predefine the inner phrases separately and then reference them in the outer phrase.

Listing 2

Example 1 defines a phrase by using template literal notation. (If you are unfamiliar with template literals and tagged templates, please be sure to read up on them before continuing this tutorial.) Unlike standard template literals, ishml.Template returns an instance of ishml.Phrase, not a simple string. The actual string, Hello, world, in example1 is hidden away in an array attached to the phrase.

Examples 2, 3, and 5 show phrase definition using standard function call notation. The a variation of the examples show each data value passed as a separate argument. The b variation passes in a single array of values. Both variations produce identical results. While it is common for the data to be a series of strings, you may also pass in complex data objects, other phrases, numbers, or even functions that return phrases, strings, or numbers. You may mix any of these types freely.

Examples 4a and 4b are nested phrases, which mix both notation styles. The outer phrase is defined using template literal notation. The expression inside the template, denoted by ${...}, is a phrase definition. Acceptable expressions are expression that evaluate to phrases, strings, numbers, or functions that when called during evaluation return phrases, strings, or numbers.

Examples 6a and 6b define empty phrases. Leaving the data out of nested phrases can sometimes make the code easier to read. Data may always be added or replaced after the initial definition a phrase.

Populating Phrases

Phrase data may be updated anytime by calling the phrases .populate method. Listing 3 shows some examples of populating phrases with data.

Listing 3

Three alternatives are shown for populating the planets phrase, a simple list of string arguments, complex data as a list of arguments, and complex data in an array. In each case, the incoming data will completely replace the phrase's internal array of data.

Often, we want to be more selective when populating a phrase and send data to specific sub-phrases. This is done by tagging the sub-phrases when the phrase is defined. Study the definition of myPhrase. The phrase uses template literal notations and contains two expressions, which are phrases. The definitions of the sub-phrases have the .tag() method appended to them. This method assigns an ID tag to each of the phrases, planet and remark. Tagged phrases provide a means for referencing specific sub-phrases within a phrase. In this example .populate is called with an Object as an argument. The property keys of the Object are matched against the ID tags of the sub-phrases and the data contained in each matching property of the Object is sent to populate the corresponding sub-phrase.

Saying Something

Now that we know a little about defining and populating phrases, let's generate some text.

Listing 4

Examine the JavaScript in listing 4 above. Phrases are evaluated by calling the phrase's say() method. This method updates the phrase's text property then returns the phrase. The first console.log() demonstrates accessing the generated text. The second demonstrates generating and accessing the text in one statement.

Phrases also provide methods for updating web pages. The replace() method takes a CSS selector string as its argument. It replaces the contents of all elements in the HTML document that match the selector with the contents of the .text property. append() and prepend() work in a similar manner except that they append and prepend the selected elements' contents. Click on the result tab above to see a live demonstration.

Continue to part two to learn how to alter the behavior of phrases with prefixes and suffixes.