Interchange Guides: Official Programming Style

Mike Heins

Jeff Barr

Eric Zarko

Jon Jensen

Sonny Cook

This documentation is free; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

Abstract

The purpose of this document is to present the officially encouraged Interchange programming style.


Table of Contents

General Programming Style
Interchange-specific additions
Writing usertags
XMLDOCS notes

General Programming Style

Interchange programming style is perlstyle, with few additions. Most of the following was decided in a meeting held on November 14, 2000.

We agreed that it is good to have a programming style, and that the existing style of code should be preserved. We agreed that making global changes to impose a consistent style is not worth doing. Instead, we will make revisions as we rewrite code. We will generally follow the published Perl style guidelines.

Interchange-specific additions

  • if / else - we accept, but do not encourage the use of cuddled else constructs (those with } else { on the same line). Use:

      }
      else {
    

  • Lexical Issues - white space is free, and white space around operators increases readability. Lining up equal signs (=) in a series of assignments can be used to emphasize the parallel structure.



        reset_calc() unless $Vend::Calc_reset;
        $CGI_array  = \%CGI::values_array;
        $CGI        = \%CGI::values;
        $Carts      = $::Carts;
        $Items      = $Vend::Items;


  • Naming - package globals should start with a capital letter. In other situations, avoid StudlyCaps where names begin with a capital letter. Items in the main package should be referenced as $::Foo, not $main::Foo.

    ## Allow no substitution of downloads
    return if $::Pragma->{download};
    

  • Filehandles - Use lexical variables (added in 2008):

    # BAD
    open SRC, $assertfile
    
    # GOOD
    open my $src, $assertfile
    

  • Return from subroutines - Use explicit return statements.

  • Globals - global variables and subs should be used very sparingly. Occasionally it is necessary to use global variables as implicit arguments to certain subs for efficiency purposes. We should not add more globals, and we should consider removing existing ones. An important exception are certain subs such as logGlobal, logDebug, errmsg, and logError.

  • CVS - CVS comments should be meaningful. As a matter of good programming practice, we encourage a careful review of all diffs before committing changes to CVS. When committing a large number of files (possibly containing changes and fixes to multiple areas) it is best to create file-specific comments addressing individual fixes. Using blank comments is not encouraged.

  • Loops - we prefer to declare loop control variables immediately prior to the beginning of the loop:

      my $var;
      foreach $var () {
      	...
      }
    

  • HTML - in late 2004, it was agreed to make the HTML code as XHTML-compliant as possible, but without using XHTML constructs that could cause problems for older browsers. (This subset of support should also be common to HTML).

    In essence, all HTML tag and argument names should be lowercased, and all argument values should be quoted, using double quotes if not particularly unsuitable. Perl gives us the nice qq{} operator that eliminates the problem of quotes clashing with Perl syntax:

    my $buf = qq{<a href="http://www.av.com/">Visit AltaVista!</a>};
    

    XHTML also mandates that all tags are treated as containers. This is easy to follow for container tags such as <p> — simply remember not to omit the closing tag. With non-container tags, such as <input>, <br> or <hr>, closing > needs to be replaced with />, but not unconditionally (Interchange must be able to output both the usual > and and XHTML variant />). In such constructs, you can use $Vend::Xtrailer that's automatically set to / if XHTML is enabled, and eventually you could replace your "raw" calls to tags such as <input> with calls to Interchange tags formel or display that will honor $Vend::Xtrailer.

    <form action="[process]">
      <input type="text"   name="city" value="[value city]" />
      <input type="submit"             value=" Submit "     />
    </form>
    

Writing usertags

See usertag and ITL glossary entries and the UserTag configuration directive for technical information.

If you use addAttr option, then name the hash-receiving variable "$opt":

UserTag test Order one two three
UserTag test addAttr
UserTag test Routine <<EOR
sub {
	my ($one, $two, $three, $opt) = @_;

	....
}
EOR

XMLDOCS notes

As you might know, XMLDOCS documentation system contains bin/stattree script which parses complete Interchange source tree. Even though it really tries to recognize code regardless of formatting (much like Perl interpreter does), there are still some little suggestions on the programming style to make it easier for XMLDOCS.

  • Do not use the hash character # in weird contexts. Use it only for comments (putting a space between eventual code and inline comment) or simple substitution such as s#A#B#g. (Impact: cosmetic)

    # Line comment
    my $test = 12; # Only used for test
    

  • Do not break word sub and subroutine name to separate lines. sub test.... is OK, sub \n test is NOT. It's best to use the cleanest variant that matches regular expression ^sub \w+ {$. (Impact: might confuse function tracking code)

    sub test1 {
    

  • Do not break obviously "solid" blocks of code to multiple lines. To give you an idea of what I am talking about, let's say you should not break typical xmldocs regexps, such as /\$::Pragma->{(\w+?)}/ or /\$Vend::Cfg->{Pragma}{(\w+?)}/. (Impact: important. Might prevent the bin/stattree script from detecting symbols)

    return if $::Pragma->{download};
    
    if (
      $Vend::Cfg->{Pragma}{download}
      ) {
    

  • Do not break blocks of code that obviously follow a lexical pattern. For example, do not introduce double quotes or structural changes to the below:



      ['FormAction',    'action',           ''],
      ['MaxServers',    'integer',          10],
      ['GlobalSub',     'subroutine',       ''],
      ['Database',      'database',         ''],
      ['FullUrl',       'yesno',            'No'],
      ['Locale',        'locale',           ''],
      ['HitCount',      'yesno',            'No'],
      ['IpHead',        'yesno',            'No'],
      ['IpQuad',        'integer',          '1'],
      ['TagDir',        'root_dir_array',   'code'],


DocBook!Interchange!