PML Language Reference
Introduction
What's the Problem
Here's the problem. You develop this really cool CGI script, you spent
months making the HTML that it generates look good. Then someone tells
you "Let's make a few changes to the interface". Well, now you have
to dig through your perl code and change all that HTML that you are
generating.
Wouldn't it be nice if you could put all your HTML in seperate files!
Then you would only have to change those files to update the interface,
and no one whould have to chnage any code. That brings a whole new problem
though, because there is some HTML that you generate on the fly and there
is no way to make it static and put it in a file. In comes PML.
PML can help
PML allows you to take all your HTML from within your script and put
it into files. Those files are mostly HTML, but also contain a little
of the PML Markup Language to do things like variabels and flow control.
Now your CGI script can have PML read a file, send it some variables
and send the results to the browser. PML is simple enough so that
you can have your HTML team edit the files, giving you more time
to code.
Example
The best way to describe PML is to take a quick look at some.
<html>
<head>
<title>${title}</title>
</head>
<body>
@if (${i_am_frank})
{
<h1>Cool, you are Frank!</h1>
}
@else
{
<h1>You must not be Frank.</h1>
}
</body>
</html>
The first thing you see is ${title}. That is a PML variable. When PML
is executing your PML file, it will replace the ${title} string with
the actual value of that variable. That value can be set from the command
line, from within your perl script, from within the PML text and also from
within PML itself.
Next you will see "@if (${i_am_frank})". This should look very
familiar to a programmer. When PML is executing your PML file, is will decide
if the variable ${i_am_frank} is true. If it is, PML will output the
text that is in the "if block". Otherwise it will output the text in the "else
block".
PML offers a lot more then what we have seen so far. You can also
extend PML from within your perl application or by writing a PML Module
in perl.
General Syntax
Text and Whitespace
All text and whitespace is preserved. The way that you alter the
output text is using PML functions and variables. PML functions
begin with an '@' symbol. PML variables begin with a
'$' sign. If you want to use a '@' or '$'
in your text, you will need to place a backslash '\\' in
front of it. This also makes it so if you need to put a backslash
in your text, you will need to put in two.
Arguments
Most PML functions take arguments. The PML set function
needs to know which variable to set and what value to set. Arguments
are given inbetween parathensis. Each argument is seperated by a
comma. There is no need to put quotations around text, unless it
contains a comma. You may use variable, and even other PML functions
inside the argument list. The argument list can also be empty for
some PML functions.
Here are some examples of arguments, using the PML set function:
# lines that START with a sharp/pound/hash are skipped
# how about one argument
@set(ThisIsTheNameOfOneVariable)
# And now two arguments
@set(myvariable, Set myvariable to this string)
# or three
@set(x, this is two, this is three)
# An argument that is a variable
@set(x, )
# An argument that is a PML function
@set(x, @perl{1})
Blocks
Some of the PML functions need blocks of text to work with. One
example is the PML if function. The if function takes
one argument and a block. It will output the block of text if
the argument is true.
Inside of the block, you can use anything that you can use inside of a block.
These include, plain text, variables and functions. A block is the text
inbetween braces { and }.
Here is an example using the PML if function:
@if( this is true) {
Then this text will get output
}
Because the parser uses the braces as delimiters, you must use caution
that you don't use a brace unless you place a backslash before it.
Here is a block inside another block:
@if( this is true) {
here comes another
@if( this one too) {
this is block two
}
back to block one
}
Comments
Comments is text that is skipped by the parser. It is a great way
to document what your text is doing, or to temparily to remove text.
PML comments are started by a #, as long as it is the first
non-whitespace charater on the line. They last until the end of the
line. To use a # you should put a backslash before it.
# This is a comment
This # is not
\\# This is not either
Variables
What's a variable?
Just like in most programming languages, PML supports variables. Variables
are a way to label some data, they are like containers with names. When
you use a variable in PML it is replaced with what ever data it contains.
Let's look at an example:
@set('cookiejar', 'peanutbutter')
The cookiejar has ${cookiejar} cookies
Let me explain what just happedned. The first line put the data
peanutbutter into the variable (container) cookiejar.
From this point on, when ever your make mention of cookiejar
PML will replace it with peanutbutter. In order to keep PML
from replacing the word cookiejar when you really wanted the
word cookiejar it requires you to inclose your variable name
in ${} like on line two above. When ever PML sees something
like this: ${word} it will look up the word and replace that
text with the data in that variable.
And in case you were wondering, when you run that PML code from above
this is what gets returned from PML:
The cookiejar has peanutbutter cookies
Variable Names
All variable names must begin with either an underscore '_' or
a letter. It can only contain letters, numbers and underscores.
Data
Variables can contain more then one value at a time. It is like a Perl
array (internaly it is a Perl Array Reference). You can access the different
'elements' of your variable using a subscript like this:
@set('cookiejar', 'peanutbutter', 'oatmeal', 'sugar')
Cookie one is ${cookiejar[0]}
Cookie two is ${cookiejar[1]}
Cookie three is ${cookiejar[2]}
This prints
Cookie one is peanutbutter
Cookie two is oatmeal
Cookie three is sugar
For a better way to do the above see @foreach. There are other
@set functions too, like @append so
see those sections for more information.
set
The set function sets a variable. It takes
as it's arguments, a variable to set and the value(s)
to set it to.
@set(name, Peter)
#name is now set to Peter
${name}
If you give more then on value, the variable will
be set as an array. You can then access the
individual values by number, starting at 0.
@set(cookies, peanutbuttter, peanutbutter chip, oatmeal)
${cookies[0]}
${cookies[1]}
${cookies[2]}
setif
The setif function is the same as the
set function except that the setif
function will not set the variable if it already
holds a value.
Append
The append function appends a string to a variable. Before the append,
the data in the variable will have spaces removed from the end of it. Then
all the spaces will be removed from the front of the string. Finally
the sting is append to the variable with one space between.
If the variable is an array, append will add another element to the end of the array.
@set(myvar, Test One)
@append(myvar, and Two)
# myvar is now "Test One and Two"
@set(test, 1, 2, 3)
@append(test, 4)
# test is now (1, 2, 3, 4) (array)
prepend
prepend is just like append except that the
string is added to the front of the variable, with a space
between the string and the variable. If the variable is an
array, the list is unshifted on to the array.
Concat
The concat function just like the append function except
concat does not add that one space.
The if function
How to make a descesion
You can use the @if function to tell PML what text to output
based on some other data. Let's take a look:
@if(1)
{
This text is printed if the condition is true
}
@else
{
This text is printed if the condition is false
}
The @if function requires that you give it a condition.
If that condition is true then it will process the text in the
block flowing the @if. If the condition is false and
you supply an @else then PML will process the text in the
block following the @else. The @else function
is optional, but if you use it, it must follow an @if function.
True and false
What is true and false is the same as what Perl considers true or false.
The very simple answer is: Blank conditions and 0 are false, everything
else is true.
Cool stuff in the condition
Just like all other PML functions that take arguments, the @if
function can take variables. Let's look at another example:
@set('condition', 1)
@if (${condition}) {
This text will get printed
}
@set('condition', 0)
@if (${condition}) {
This text will NOT get printed
}
elsif
Just like Perl, PML has a @elsif function. This function must follow
a @if function, and like @if, it must be given a condition.
If the condition to @if is false, then the condition to the next
@elsif function is checked. You can have as many @elsif
functions that you want. Here is an example:
@set('c1', 0)
@set('c2', 0)
@set('c3', 1)
@if (${c1})
{
This text will be printed if c1 is true
}
@elsif (${c2})
{
This text will be printed if c2 is true
}
@elsif (${c3})
{
This text will be printed if c3 is true
(which it is in this example)
}
@else
{
This text will be printed if nothing above
was true.
}
unless
Another function that came from Perl is the unless function.
unless is just like if except that the code in the
unless block is executed when the condition is false not
true. unless supports elsif and else just like
if.
@set( condition, 0 )
@unless ( ${condition} ) {
This text will get output because
the condition is false
} @else {
This text would get output if the
condition was true
}
The foreach function
How to loop
The foreach function is used to loop over a set of
values. Let's look at an example.
@foreach ( 1, 2, 3, 4, 5, 6 ) {
This is loop number ${.}\n
}
The output of the above code is:
This is loop number 1
This is loop number 2
This is loop number 3
This is loop number 4
This is loop number 5
This is loop number 6
Each time through the loop, the special variable ${.} will get
set to the current argument. That special \n insterts a new line.
This is necessary to get the next loop to be on a new line. This makes
it possible to loop and keep the loop text on the same line.
Looping over variables
You can also loop over an array you have set.
@set( cookiejar, peanutbutter, oatmeal, sugar )
@foreach ( ${cookiejar} ) {
I like ${.} cookies\n
}
That code would output:
I like peanutbutter cookies
I like oatmeal cookies
I like sugar cookies
The include function
The PML include function is used to include another
file in the place of the include function. It takes
an argument list of files to include.
To place file 'b' inside file 'a' at runtime use the following
code:
# This is file a
Blah Blah Blah
@include(b)
The include function is special in that it is a parse time
function. This means that the file you are including must exist
during the parsing of the original file, and you can not use
variables or other functions in the argument list of the
include. One exception to this rule is if the variable
was defined outside the file, such as in a Perl script.
PML Macros
What is a macro?
A macro is a way to repeat text over and over again without having
to type it over and over again. It lets you group some text together
and give it a name. Then to use that text you just call it by name.
Defining a macro
Use the PML macro function to define a macro. The macro
function takes arguments and a block. The first argument is the name
to call the macro and the block is the actual text. Example:
@macro( mymacro ) {
This text is called mymacro
}
Using the macro
To insert the text from above macro use call it by it's name:
Some text before the call to the macro
@mymacro()
Some text after the call to the macro
After that text is processed, it will look like:
Some text before the call to the macro
This text is called mymacro
Some text after the call to the macro
Macro arguments
PML macros can take arguments. Here is an example:
@macro( mymacro, myvariable ) {
The variable you passed was ${myvariable}
}
Then to call that macro you just:
@mymacro(test)
The ARGV Variable
If your macro was given more arguments then you declared
in your macro definition, they will be avaliable in the
${ARGV} varible which is an array.
Need
The need function is used to load in a external PML Module.
It takes a list of PML Modules to load:
@need(CGI)
@need(LWP)
Note: these are PML modules, not Perl Modules
The perl Function
The perl function is used to eval perl code. This function does not take
any arguments, just a block. The code to eval should be in the block.
You can access the PML variables inside the evaled perl by the hash %v.
@set(x, 1)
@perl{ $v{x}++; undef}
The reason that you need the undef is because the output from the
eval is injected into the output stream. Your Perl code will always
be evaled in list context.
@perl{ scalar localtime }
# puts the localtime into the output stream
Replace If Blank (rib)
This PML function is very useful for HTML tables.
It is like a reversed if function. It takes
both an argument and a block. If the block turns out
to be empty, then the function will return the string
that was passed in the argument list. Here is an example
used inside HTML:
<td>
@rib( ) {
@if (condition) {
text
}
}
</td>
If the if function from above does not
return any text, the rib function will
place a in the output stream.
warning
The warning function controls weather or
not PML will produce warning messages. By default,
warnings are turned off. Setting the warning flag
to a true value will turn them on.
@warning(1)
${new}
# this will produce a warning because
# new did not have a value
@perl{ldkj';;}
# warning above because the perl statement
# had syntax errors
The while function
while loops
The while function lets you repeat some text
over and over while some condition is true.
@set(condition, 1)
@set(i, 1)
@while(${condition}) {
Loop number
}
That code produces:
Loop number 1
Loop number 2
Loop number 3
until loops
You can use until instead of while.
The only difference is that until only
loops while the condition is false.
The wrap Function
wrap will take some options as it's arguments
and alter the text inside it's block. Here are the
arguments to give to wrap
- Number of columns to wrap to (Defaults to 80)
- Charater to use before wrap (Defaults to blank)
- Charater to used to start wraped lines (Defaults to blank)