NAME
P - Safer, friendlier printf/print/sprintf + say
VERSION
Version "1.1.22"
SYNOPSIS
P FILEHANDLE FORMAT, LIST
P FILEHANDLE LIST
P FORMAT, (LIST)
P (LIST)
P @ARRAY
$s = P @ARRAY; P $s; # same output as "P @ARRAY"
Pe # similar to P w/FILEHANDLE default = STDERR
$s = P FILEHANDLE ... # sends same output to $s and FILEHANDLE
DESCRIPTION
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 newline
s (\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).
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 here-->"
.
Bless
ed objects, by default, are printed with the Class or package 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
can take an array with the format in the 0th element, and parameters following. Sprintf
will cause an error to be raised, if you try passing an array to it, as it will force the array into scalar context -- which as the manpage says "is almost never useful". Rather than follow in the design flaws of its predecessors, P tries to do the right thing.
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 unless you explicity specify the filehandle, as it will think it is supposed to return the result -- not print it.
Special Use Features
While P
is normally called procedurally, and not as an object, there are some rare cases where one 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 pointer to call P. See following example.
EXAMPLE: (changing P's defaults)
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];
The above would normally produce:
my probs = [{answers=>[{…}, {…}], questions=>["sqrt(-4)", "(1-i)**2"]}]
Instead of the contents of the hashes, P shows the ellipses (a 1 char-width wide character) for the interior of the hashes. If you wanted the interior to print, you'd need to raise the default data expansion depth for P
as we do here:
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);
The above allows 1 extra level of depth to be printed, so the elements in the hash are displayed producing:
my probs = [{answers=>[{i=>2, real=>0}, {i=>-2, real=>0}], # extra "\n"
questions=>["sqrt(-4)", "(1-i)**2"]}]
NOTE: when referring to the <Bpackage> P
, a double colon is usually needed to tell perl you are not talking about the function name.
Please don't expect data printed by P to be "pretty" or parseable. It's not meant to be a Perl::Tidy or Data::Dumper. Especially, when printing references, it was designed as a development aid.
Summary of possible OO args to "ops" (and defaults)
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 (1). noquote => 1
-
In printing items in hashes or arrays, data that are Read-Only or do not need quoting won'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 parentheses (ex. 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.