NAME

Debug::Statements provides an easy way to insert and enable debug statements.

SYNOPSIS

use Debug::Statements qw(d);
my $d = 1;
my $myvar = 'some value';
my @list = ( 'zero', 1, 'two', "3" );
my %hash = ( 'one' => 2, 'three' => 4 );
d "Hello world";
d '$myvar';
d '@list %hash';

PROBLEM STATEMENT

Advantages of traditional "print" debug statements:
    Familiar to all programmers.
    When strategically placed, show the values of key variables as well as the flow of control.																													          
    May be left in the code to facilitate debugging, when the code next needs to be enhanced.
    May be turned on to help remotely debug and find solutions around problems.
    Printing names of subroutines executing can be particularly useful when debugging
      large programs produced by multiple developers over the span of many years.	
    Can be used in conjuction with a debugger, which is needed to change variables on-the-fly,
      step into libraries, or skip/repeat sections of code
    If the results are saved to a file, file comparisons can be useful during regression testing.
Disadvantages:
    Tedious, require too many keystrokes to type
    Reduces readability of the source code.
    Print statements clutter the standard output
    Need to be removed or commented out
    If some statements are mistakenly left in, the output can cause problems or confusion
    The next time the code needs to be enhanced, any removed print statements need to be re-inserted or uncommented

Traditional debug statement example:
    my $d = 1;
    if ($d) { print "DEBUG sub xyz:  \$myvar is $myvar\n" }
    if ($d) { print "\nDEBUG: Dumping \%myhash:\n"; Dumpvalue->new->dumpValue(\%myhash) }

Traditional debug statement example using Log4perl:
    use Log::Log4perl qw(:easy);
    my $verbose = 1;
    Log::Log4perl->easy_init($verbose ? $INFO : $WARN);
    INFO "\$myvar is $myvar";

Debug::Statements provides a quick and easy way to insert debug statements.
It prints the name of the variable AND its value
It has been optimized to save programmer keystrokes

EXAMPLE

use Debug::Statements qw(d);
my $d = 1;
my $myvar = 'some value';
d '$myvar';

output of example:
    DEBUG sub mysub:  $myvar = 'some value'

This is all you need to know to get started.

FEATURES

Arrays, hashes and refs are supported:
    d '@list';
    d '$list[2]';
    d '$list[$i]';
    d '%hash';
    d '$nestedhash{key}';
    d '$nestedhash{$key1}{$key2}';
    d '$listref';
    d '$arrayref';
    d '$arrayref->[2]';
    d '$hashref->{key}';
    d '$hashref->{$key}';

Plain text is supported:
    d 'Processing file';

Multiple debug levels are supported:
    my $d = 1;
    d '$myvar';    # prints
    d2 '$myvar';   # does not print since $d < 2
    $d = 2;
    d '$myvar';    # prints
    d2 '$myvar';   # prints
    
    D '$myvar';    # always prints, even if $d is 0 or undef
                      this is useful for short term debugging of existing code

    d0 '$myvar';   # same as d0

Supports newlines or other characters before and/or after the print statement
    d '\n $myvar';
    d '\n$myvar\n\n';
    d '\n-------\n@list\n--------\n';

Multiple variables can be printed easily:
    d '$myvar $myvar2 $myvar3';
    d '$myvar,$myvar2,$myvar3';
    d '$myvar, $myvar2, $myvar3';
    d '($myvar, $myvar2, $myvar3)';
    Each of these prints 3 separate lines

Plain text can be entered as a comment:
    d 'Here is a comment';
    d "This comment prints the value of a variable: $myvar";

Alternate syntax:
    d('$myvar');

ls() is also provided, but not exported by default
    use Debug::Statements qw(d d0 d1 d2 d3 D ls);
    ls($myfilename);
    when $d==1, this prints an ls -l listing of $myfilename
    Note that '' is not used

REQUIREMENTS PadWalker must be installed (CPAN) The test suites require Test::Fatal, Test::More, and Test::Output

  $d variable    
      Your code must have a variable '$d' defined to enable the debug statements
      $d was chosen because it is easy to type and intuitive
      If your code already uses '$d' for something else, this can be changed with Debug::Statements::setFlag()

      Consider enabling $d through the command line of your script:
	  use Getopt::Long;
	  my $d = 0;
	  GetOptions( \%opt, 'd' => sub{$d=1}, 'dd' => sub{$d=2}, ... );

  Your code must not contain a local subroutine called 'd()', since this function is imported

  Calls to d() should use 'single quotes' instead of "double quotes"
  Exception:
      To produce custom output, call d() with double-quotes.
      As is always the case with double-quotes in Perl, variables will be interpolated into values before reaching the d() subroutine.

      Example #1:
	  d "Found pattern: $mynum in file $filename";
      Produces output:
	  DEBUG sub abc:  Found pattern asdf in file foo.txt

      Example #2:
	  d "Found $key and replaced with $subtable_ref->{$key} on:  $line"
      Produces output:
	  DEBUG sub abc:  Found foo and replaced with bar on:  foobar

  Remember that when you use escaped \$ \@ \% within "double quotes",
   this is equivalent to using $ @ % within 'single quotes',
   meaning that d() will try to print the names and values of those variables.
	

OPTIONS Options may be specifed with an optional 2nd argment to d() Valid options are: b print suBroutine name (default) c Chomp newline before printing, useful when printing $line of a parsed input file e print # of Elements contained in top level of the array or hash n print line Number $. of the input file q treat the string as text, do not try to evaluate it. This is useful if you are parsing another Perl script, and the text contains sigil characters $@% r tRuncate output (default is 5 lines) s Sort contents of arrays (hashes are always sorted) t print Timestamp using localtime() and Time::HiRes::gettimeofday() x die when code reaches this line z compress array and hash dumps to save screen space For example to print $line chomped and with line number and timestamp d('$line', 'cnt'); For example to print %hash in a compressed format d('%hash', 'z');

  Options are only valid for the current debug statement
  To negate an option, capitialize it (use 'B' instead of 'b')

  Global:
      To make the current options global (peristant), append a *
      For example, to set timestamp globally:
	  d('$var', 't*');
      For example, to unset timestamp globally:
	  d('$var', 'T*');

  The module includes functions which affect global operation:
      Debug::Statements::enable();             # enable operation (default)
      Debug::Statements::disable();            # disable operation, even if $d >= 1
      Debug::Statements::setFlag('$yourvar');  # default is '$d'
      Debug::Statements::setPrintDebug("");    # default is "DEBUG:  "
      Debug::Statements::setTruncate(10);      # default is 10 lines

LIMITATIONS Does not support: array slices such as $listvar[1:3] some special variables such as $1 $_ @_ ...but any of these IS supported when using "double quotes", since this will cause Perl itself to evaluate the expression before calling d() for example: d "@_" The evaluation is of variables does not support the full range of Perl syntax. Most cases work, for example: d '$hash{$key}' However hashes uses as hash keys will not work, for example: d '$hash{$hash2{$key}}' As a workaround, use "double quotes": d "\$hash{$hash2{$key}}" instead. The rule is similar for arrays

ADVANCED

Perl versions:
    This module has been tested on 5.8.6, 5.8.8, 5.12, 5.14, and 5.20
    It may even work on 5.006
    
How it works:
    PadWalker::peek_my() gets the value of $d and the contents of your variable (from outside its scope!)
    This is stored in the internal hash reference $h
    caller()[3] gets the name of subroutine which encloses your code
    Data::Dumper pretty-prints the contents of your variable

Performance:
    For performance-critical applications, the calls to PadWalker::peek_my() and caller() may be problematic

    Solutions:
        Globally disable all functionality by calling Debug::Statements::disable();
        The PadWalker and caller functions will not be called.  No DEBUG statements will be printed.

        A second technique is to comment out some of your calls to d() within performance-critical loops

        A third technique to completely disable this code is to define you own empty d() subroutines.
        #use Debug::Statements qw(d d2);
        d{};d2{};

Debugging this module:
    To turn on internal debug, set $d to be negative.

AUTHOR

Chris Koknat 2014 chris.koknat@gmail.com