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

NAME

P - Safer, friendlier printf/print/sprintf + say

VERSION

Version "1.1.10"

SYNOPSIS

  P FILEHANDLE, FORMAT, LIST
  P FORMAT, LIST
  P @ARRAY
  $s=P @ARRAY; P $s;          # same output as "P @ARRAY" 
  Pe                          # same as P, but output to  STDERR

P is a combined printf, sprintf & say in 1 routine. It was designed to save on typing and undef checking when printing strings. It saves on in that you don't have constantly insert or move newlines (\n). If you change a string into a formatted string, insert P, as in:

  die "Wrong number of params";
             # to
  die P "Expecting 2 params, got %s", scalar @ARGV;

When printed as strings ("%s"), undefs are automatically caught and "∄", (U+2204 - meaning "There does not exist") is printed in place of "Use of uninitialized value $x in xxx at -e line z."

By default P, prints the content of references (instead HASH (or ARRAY)=(0x12345678), three levels deep. Deeper nesting is replaced by the unicode ellipsis character (U+2026).

DESCRIPTION

While designed for development use, it is useful in many more situations, as tries to "do the right thing" based on context. It can usually be used as a drop-in replacement the perl functions print, printf, sprintf, and, say.

P tries to smartly handle newlines at the end of the line -- adding them or subtracting them based on if they are going to a file handle or to another variable.

The newline handling at the end of a line can be supressed by adding the Unicode control char "Don't break here" (0x83) at the end of a string or by assigning the return value and having a file handle as the first argument. Ex: my $fmt = P STDOUT, "no LF added= ";>.

Blessed objects, by default, are printed with the Class name in front of the reference. Note that these substitutions are performed only with references printed through a string ("%s") format -- features designed to give useful output in development or debug situations.

One minor difference between P and sprintf': P takes the same list format as printf. P does not implement the sprintf's design flaw in forcing an array argument into scalar context, which is described in the perl documentation as something that is almost never useful.

NOTE: A side effect of P being a contextual replacement for sprintf, is if it is used as the last line of a subroutine. By default, this won't print it's arguments to STDOUT, but acts as sprintf in returning the formatted string to the caller.

Experimental Features

While P is normally called procedurally, and not as an object, there are some rare cases where you would really like it to print "just 1 level deeper". To do that, you need to get a pointer to P's options.

To get that pointer, call P::->ops({key=>value}) to set P's options and save the return value. Use that as a class-pointer to call P. See following example.

Example

Suppose you had an array of objects, and you wanted to see the contents of the objects in the array. Normally P would only print the first two levels:

  my %complex_probs = (                                
      questions =E<gt> [ "sqrt(-4)",  "(1-i)**2"     ],
      answers   =E<gt> [ {real => 0, i =>2 }, 
                     {real => 0, i => -2 } ] );
        my $prob_ref = \%complex_problems;
  P "my probs = %s", [$prob_ref];

Would normally produce:

  my probs = [{answers=>[{…}, {…}], questions=>["sqrt(-4)", "(1-i)**2"]}]

When you might want to see those hashes as they are short anyway. To do that you'd use the object and print with that, like this:

  my %complex_probs = (                                     
      questions => [ "sqrt(-4)",          "(1-i)**2"     ],
      answers   => [ {real => 0, i =>2 }, { real => 0, i => -2 } ] );
  my $p=P::->ops({depth=>4});                                
  $p->P("my array = %s", \%complex_probs);

Which produces:

  my probs = [{answers=>[{i=>2, real=>0}, {i=>-2, real=>0}],  # extra "\n" 
                     questions=>["sqrt(-4)", "(1-i)**2"]}]

Note: Don't confuse P with a Pretty Printer or Data::Dumper. Especially, when printing references, it was designed as a debug aid.

Summary of possible OO args to "ops"

    depth=>3; Allows setting depth of nested structure printing. NOTE: regardless of depth, recursive structures in the same call to P, will not expand but be displayed in some abbreviated form (in flux).

    implicit_io=>0; in printing references, references to globs and i/O handles do not have their contents printed. If this is wanted, one would call ops with this set to true.

    noquote=>1; in printing items in hashes or arrays, data that are read only or do not need quoting don't have quoting (contrast to Data::Dumper, where it can be turned off or on, but not turned on, only when needed).

    maxstring=>undef; Allows specifying a maximum length of any single datum when expanded from an indirection expansion.

Example 2: Not worrying about "undefs"

Looking at some old code of mine, I found this:

  print sprintf STDERR,
    "Error: in parsing (%s), proto=%s, host=%s, page=%s\n",
    $_[0] // "null", $proto // "null", $host // "null",
    $path // "null";
  die "Exiting due to error."

Too many words and effort in upgrading a die message! Now it looks like:

  die P "Error: in parsing (%s), proto=%s, host=%s, page=%s",
          $_[0], $proto, $host, $path;

It's not just about formatting or replacing sprintf -- but automatically giving you sanity in places like error messages and debug output when the variables you are printing may be 'undef' -- which would abort the output entirely!

MORE EXAMPLES

  P "Hello %s", "World";            # auto NL when to a FH
  P "Hello \x83"; P "World";        # \x83: suppress auto-NL to FH's 
  $s = P "%s", "Hello %s";          # not needed if printing to string 
  P $s, "World";                    # still prints "Hello World" 

  @a = ("Hello %s", "World");       # using array, fmt as 1st arg 
  P @a;                             # print "Hello World"
  P 0 + @a;                         # prints #items in '@a': 2

  P "a=%s", \@a;                    # prints contents of 'a': [1,2,3...]

  P STDERR @a                       # use @a as args to a specific FH
                                    # Uses indirect method calls when invoked
                                    # like "print FH ARGS"
                                    #
  Pe  "Output to STDERR"            # 'Shortcut' for P to STDERR

  # P Hash bucket usage + contents with hashes:
  %H=(one=>1, two=>2, u=>undef);

  P "%H hash usage: %s", "".%H;     # Shows used/total Hash bucket usage
  P "%H=%s", \%H;                   # Show contents of hash:
    %H={u=>(undef), one=>1, two=>2}

  bless my $h=\%H, 'Hclass';        # Blessed objs... 
  P "Obj-h = %s", $h;               #   & content:
    Obj-h = Hclass{u=>(undef), one=>1, two=>2}

NOTES

Values given as args with a format statement, are checked for undef and have "∄" substituted for undefined values. If you print vars as in decimal or floating point, they'll likely show up as 0, which doesn't stand out as well.

Sometimes the perl parser gets confused about what args belong to P and which do not. Using parens (i.e. P("Hello World")) can help in those cases.

Usable in any code, P was was designed to save typing, time and work of undef checking, newline handling, peeking at data structures in small spaces during development. It tries to do the "right thing" with the given input. It may not be suitable where speed is paramount.