NAME
P - Safer, friendlier printf/print/sprintf + say
VERSION
Version "1.1.33"
SYNOPSIS
use P qw[:depth=5 :undef=(undef)];
P FILEHANDLE FORMAT, LIST
P FILEHANDLE LIST
P FORMAT, (LIST)
P (LIST)
P @ARRAY # can contain FH, FMT+ARGS & return string
$s = P @ARRAY; P $s; # can be same output as "P @ARRAY"
Pe # same as P STDERR,...
$s = P FILEHANDLE ... # sends same output to $s and FILEHANDLE
DESCRIPTION
P
is a combined print, printf, sprintf & say in 1 routine. It saves tremendously on development time. It's not just the 1 char verb, but has these time saving and powerful features:
Too often I've either changed a string to a format statement, or just forgot the 'f'. With P
it doesn't matter -- either will work.
Example:
# Let's start with a "die" statement.
1) die "Wrong number of params";
# Then wants to add how many params one got:
2) die P "Expecting 2 params, got %s", scalar @ARGV;
# Then you want to see what was passed. No loop needed:
3) die P "Expecting 2 params, got %s (ARGV=%s), 0+@ARGV, \@ARGV;
In the send die
, P
is replacing sprintf
-- however, instead of something like "ARRAY(0x12345678)
", P
would try to display the actual contents of the array, showing ["arg1", "arg2".
When it comes to newline
's, or "\n" at the end of line, P
behaves like say
when printing to output or a file handle and will auto append a line feed when needed.
Since P
can be used to print to strings, when doing so, it will auto-suppress up to one included "\n
" at the end of a format statement AND automatically add one if it is printing to a device (if it is doing both at he same time -- it favors suppression).
How often have you printed diagnostic output only to get nothing because one of the variables being printed was undef
. P
handles it.
By default, it prints a symbol for "does not exist" in place of where the string would have displayed (%s fmt, only) and prints the rest of the string normally.
P
doesn't have as many arbitrary restrictions on it's arguments.
It handles cases that the equivalent perl statement won't.
VERB -> P print printf sprintf say
V --FEATURE-- V --- ----- ------ ------- ---
to a FH Yes Yes Yes No Yes
to $fh Yes Yes Yes No No
to a string Yes No No Yes No
add EOL-NL to FH? Yes No No No Yes
sub EOL-NL w/"-l" Yes No No No Yes
sub EOL-NL in string Yes No No No No
FMT Yes No Yes Yes No
@[FMT,ARGS] Yes No Yes No No
undef to "%s" Yes No No No No
@[$fh,FMT,ARGS] (7) Yes No No No No
like "tee" (8) Yes No No No No
7 - File Handle in 1st member of ARRAY used for output.
8 - When P is being used as a string formatter like sprintf,
it can still have a "$fh" as the first argument that will
print the formatted string to the file handle as well as
returning it's value (note: this will force the string
to be printed w/o a trailing newline).
Undefs
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 package 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 an abbreviated form. implicit_io => 0
-
When printing references, GLOBS and IO refs do not have their contents printed (since printing contents of such refs may do I/O that changes the object's state). If this is wanted, one would call
ops
withimplicit_io
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
%H=(one=>1, two=>2, u=>undef); # P Hash bucket usage + contents:
P "%H hash usage: %s", "".%H; # Shows used/total Hash bucket usage
P "%H=%s", \%H; # print contents of hash:
%H={u=>(undef), one=>1, two=>2}
bless my $h=\%H, 'Hclass'; # Blessed objects...
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.