NAME
Text::Forge Style Guide
SYNOPSIS
<%
# This is a code block.
do_something_interesting(
$with_some,
\@very_very,
\%interesting_arguments,
);
%>
<%
if ($something) {
if ($dangerous) {
# This is something dangerous
%>
<em>Danger! Danger!</em>
<%
} else {
# This is something that is not dangerous
%>
I see something, but it doesn't seem to be dangerous.
<%
} else {
# There is nothing here
%>
Nope, there's nothing there.
<%
}
%>
I told $who to get <%$ $inside?"out":"back in" %>!!!
DESCRIPTION
Text::Forge shares one important trait with perl: it can be as readable or as unreadable as you like.
Good code is easy to read and maintain; poor code is difficult to learn and to modify. This leads us to believe that anything that tends to make code easier to read or modify makes it better, while anything that detracts from these two things makes it worse.
Let's examine some best practices in writing Text::Forge documents that are legible and maintainable.
Large Code Blocks
Large code blocks are usually found before any output is generated. It is best to keep code -- even unrelated code that is still adjacent -- together in one block. The block should only be separated if you want to put some text in between.
Normally, you want to start and end a block with a '<%
' and '%>
' on a line by itself. Keep at least one blank line after the beginning and before the end to make sure it is clearly visible.
However, some people like to save vertical screen space and join the line with the <%
and %>
with the code. Some prefer to indent the opening <%
. This is especially true when you have a very small code block. Whatever you decide to do, it is probably best to standardize it among your team.
Also, be sure to indent the code, like you would indent code in curly braces ({
, }
) or parentheses ((
, )
).
Here are three examples of common ways to format some code blocks. You should decide which one works for you and stick with it.
<%
while (shift @options) {
%>
Another option is $_->{name}.
<%
if ($_->{benefits}) {
%>
The benefits of this option are: <%$ join ", ", @{$_->{benefits}} %>.
<%
}
}
%>
<% while (shift @options) { %>
Another option is $_->{name}.
<% if ($_->{benefits}) { %>
The benefits of this option are: <%$ join ", ", @{$_->{benefits}} %>.
<% }
} %>
<% while (shift @options) { %>
Another option is $_->{name}.
<% if ($_->{benefits}) { %>
The benefits of this option are: <%$ join ", ", @{$_->{benefits}} %>.
<% } %>
<% } %>
It's also considered good practice to avoid putting large blocks of code into Text::Forge templates. Templates are designed to be simple and readable - a harmony of perl and plain text. Consider abstracting large code blocks into appropriately named packages.
<%
use Time::Duration;
%>
This page has been "running" for <%$ Time::Duration->runtime() %>.
Text Intertwined With Code
It is extremely easy to get confused when you are mixing perl code with regular text. This is most common when you have text that is dependent on multiple conditions or nested loops.
The best way to handle this is to think of each piece of code as a separate block. The code may grow in the future as well, so this tends to increase maintainability.
For HTML, you need to be strategic with your placement of the markers so that whitespace isn't introduced in the wrong places. Note that a closing marker followed directly by a newline does not translate to a newline. The next line of text is treated as if it directly followed the closing tag.
A good text editor will be able to distinguish between the HTML code and the perl code. The highlighting cues will be more than enough to see how the code is structured, as well as how the HTML is structured. Text::Forge highlighting is available for ViM and Emacs.
<%
foreach my $q (@questions) {
# Show the question text
%>
<table>
<tr>
<td>$q->{text}</td>
</tr>
<tr>
<td>
<%
# Show the options
if ($q->{type} eq 'checkbox' or $q->{type} eq 'radio') {
# We are doing checkboxes or radio buttions.
foreach my $a ($q->{answers}) {
# Working through each answer one by one
%>
<input type="$q->{type}" name="$q->{id}" value="$a->{id}"
<%$ $q->{selected}?"checked":"" %> />$a->{text}<br />
<%
}
} else {
# We are doing a dropdown
%>
<select name="$q->{id}">
<%
foreach my $a ($q->{answers}) {
# Working through each answer one by one
%>
<option value="$a->{id}"
<%$ $q->{selected}?"selected":"" %>>$a->{text}</option>
<%
}
%>
</select>
<%
}
%>
</td>
</tr>
</table>
<%
}
%>
Code Snippets
Oftentimes, it is more readable to use small snippets of code that directly translate into real text than to store the text in a variable and use it later. In this case, try to keep the code flowing with the text. Here are some examples.
You can choose one of these options: <%$ join ", ", @options %>
Your contract expires <%$ $days_left>30?"in a while":"very soon" %>.
And since templates are always part of the text, it may be wise to include them in a single line by themselves everytime they are used. This makes them much more identifiable.
<% $forge->include("my_template", @with_my_args) %>
Direct Substitutions
Using direct substitutions in text tend to increase readability and maintainability.
Hello $first_name, I'm glad to see you this $weekday morning!
Be sure you know what is in the variable before doing this. You usually want to encode input from the user or from another source to be sure that it won't harm the formatting of your text, or do much worse like embedding Javascript in an HTML page.
We'll deliver "<%= $book_title %>" immediately to your house!
Remember that pre-encoding the variable is wise if it is going to be used more than once.
<%
$name = $forge->encode_entities($name);
%>
Hello, $name!
...
As a member of our website, $name, you are entitled to certain benefits.
Coding with HTML People
It is common to split the jobs between a web programmer and a web designer. The programmer is responsible for making the text conditional and putting in business logic. The web designer is responsible for making the HTML work on a variety of browsers and keeping track of the tables.
As a web programmer, it is risky to play with the HTML code of the web designer. They know how to make the HTML work with a variety of browsers and one small change can affect certain browers in big ways. As a web designer, it is difficult to read perl code, and so it is hard to identify where to modify the HTML code.
The web programmer should be responsible for making the perl code explicit, especially as the code is near or intermixed with HTML. Using comments is extremely useful. The web designer should become familiar with how for
, while
, and other loops work. They should also understand what if
, elsif
, and else
mean, and how that affects what is shown. The web programmer should try to keep these statements explicit, using simple logic or well-named variables. In short, perl is an expressive language, and the web programmer should try to express perl in something close to English.
Here is some sample code to show how the web programmer can make the web designer's job a little easier.
<%
if ($is_member) {
if ($must_renew_soon) {
# Is a member, but must renew soon.
%>
You are a member, but you must renew soon.
<%
} else {
# Is a member, but doesn't have to renew soon.
%>
You are a member.
<%
}
} else {
# Not a member
%>
You are not a member yet. Sign up now!
<%
}
%>
Be sure to keep the two people in each position talking with each other. When the web programmer doesn't understand why HTML is structured a certain way, they should ask the web designer. When the web designer doesn't know how to modify the page, they should ask the web programmer.
SEE ALSO
Text::Forge Tutorial
Text::Forge
AUTHOR
Jonathan Gardner <jgardn@alumni.washington.edu>
Contributions and suggestions made by Adam Monsen and Maurice Aubrey.
COPYRIGHT
Copyright © 2002, Jonathan Gardner
This document is licensed under the GNU Free Documentation License.