The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.


STYLE GUIDE

Subroutine Naming (from PBP)

routine  -> imperative_verb   [ _adjective]? _ noun _ preposition
         |   imperative_verb  [ _adjective]? _ noun _ participle
         |   imperative_verb  [ _adjective]? _ noun 



FATAL BY DESIGN

Subroutines should succeed or die trying.

Except when the caller exclicity provides permission by passing an optional named parameter for fatal.

  $util->get_url('http://www.tnpi.nt/index.html');    # <- fatal (invalid domain)
  $util->get_url('http://www.tnpi.nt/index.html',fatal=>0);  # not fatal, err result
  $util->get_url('http://www.tnpi.net/index.html');   # success!

In the example above, the first example won't return anything unless the caller traps the exception. In the second example, a false value is returned. In the final example, a true value is returned.



STATUS AND ERROR MESSAGES

Don't use print or warn.

Instead, make calls to a Mail::Toaster object, which is present in each module as $log. Status messages and anything that should return a successful result should call $log->audit. Errors should instead call $log->error. The primary difference is that audit messages return a successful result code and errors return a failure code.

 $util->is_readable( '/tmp' )
    or return $log->error( "can't read /tmp" );
 $log->audit( "yay, I can read from /tmp" );

To save a status message:

  $log->audit("test status message");        <- prints nothing to the screen
  $log->audit("save and print it",debug=>1)  <- saves the message and prints it

To save an error message:

  $log->error("I've fallen and can't reach by beer");  <- fatal error
  $log->error("I can still reach my beer",fatal=>0);   <- non-fatal error

Authors are encouraged to use $log->audit extensively. By default, audit calls do not print. This allows the authors to be verbose by liberally using audit messages, as if they were commenting their code in english. 

When an error condition is encountered, the audit and error logs are printed to the screen, allowing the author and/or user to see, in great detail, what the error encountered was, as well as the context leading up to it. 


STANDARD ARGUMENTS

There are three 'standard' arguments that all classes (modules) and most methods (subroutines) support and/or use: debug, fatal, and test_ok. Their default values are (shown).

  debug:   display runtime status messages.             (true)
  fatal:   cease execution when errors are encountered. (true)
  test_ok: if defined, try to run the method (making only ephemeral
           changes) and return the defined result. (undefined)

All three 'standard' arguments are included in the globally available hash, %std_opts. Each method needs only to include %std_opts in its parameter validation to get all three.

  sub do_something {
    my $self = shift;
    my %p = validate(@_, { %std_opts } );
  };

When using the std args individually, it's best to dereference them from the hash:

  my $debug = $p{debug};
  print "doing something" if $debug;

When calling other methods, it's often desirable to pass along all of the standard arguments. This can often be accomplished by just passing along %p. However, if there are other named arguments in %p which the callee doesn't recognize, parameter validation will fail (and for good reason, this catches all manner of unexpected results). A better solution is passing %p through get_std_args. The resulting hash can safely be passed along when calling other methods: 

  sub do_something {
    my $self = shift;
    my %p = validate(@_, { %std_opts } );
    my %args = $log->get_std_args( %p );
    
    # do a bunch of stuff
    $self->do_something_else( %args );
    return $something;
  };


STANDARD ARGUMENTS, SHARING AND INHERITANCE

The %std_opts hash is globally defined in each class and contains the values that were set when the class object was instantiated. Examples:

 my $util = Mail::Toaster::Utility->new;

Since no values were specified, all subsequent calls to $util->do_something will have the default values for debug, fatal, and test_ok. Since the default for debug is true, to disable debugging for all methods in $util, explicity set debug when instantiating the object: 

 my $util = Mail::Toaster::Utility->new(debug=>0);

Of course, individual calls to $util methods can always explicitely override the values when they make the call:

 $util->do_something( debug => 0 );  # shhhh