#!/usr/bin/perl -w { package P; BEGIN{ $::INC{__PACKAGE__.".pm"} = __FILE__."#__LINE__"}; use 5.10.0; use strict; our $VERSION='1.0.7'; # RCS $Revision: 1.15 $ - $Date: 2012-12-31 16:56:07-08 $ # 1.0.7 - (2013-1-9) add support for printing blessed objects # - pod corrections # - strip added LF from 'rev' example with tr (looks wrong) # 1.0.6 - add manual check for LF at end (chomp doesn't always work) # 1.0.5 - if don't recognize ref type, print var # 1.0.4 - added support for printing contents of arrays and hashes. # (tnx 2 MidLifeXis@prlmnks 4 brain reset) # 1.0.3 - add Pea # 1.0.2 - found 0x83 = "no break here" -- use that for NL suppress # - added support for easy inclusion in other files # (not just as lib); # - add ISA and EXPORT to 'mem' so they are available @ BEGIN time # # 1.0.1 - add 0xa0 (non breaking space) to suppress NL our (@ISA, @EXPORT); BEGIN {@EXPORT=qw(P Pa Pe Pea), @ISA=qw(Exporter) }; use parent 'Exporter'; sub P(@) { # 'safen' to string or FH or STDOUT my $_; do{ print '(@)'; @_=@$_[0] } if ref $_[0] eq 'ARRAY'; my ($fh, $f); my $explicit_out; if (ref $_[0] eq 'GLOB') { $fh = shift; $explicit_out=1; } else { $fh =\*STDOUT; } $f=shift; no warnings; my $res = sprintf $f, map {my $_ = &{ sub { return "undef" unless defined $_; my ($v, $ref_, $pkg) = ($_, ref $_, ''); if (0<=(index $v,'=') && m{(\w+)=(\w+)}) { $pkg=$1.":", $ref_=$2 } return <$_> if ($ref_) =~ /GLOB/; return $_ unless $ref_; given ($ref_) { when (/^GLOB$/) { <*$v> } when (/^IO$/) { <$$v>} when (/^SCALAR$/) { return $pkg.'\\' .$$v } when (/^ARRAY$/) { return $pkg."[" . ( join ",", @{ [ map { $_//"(undef)" } @$v ] } ) . "]" } when (/^HASH$/) { $pkg."{" . (join ", ", @{[ map {'"'.$_.'"=>"'.($v->{$_}//"(undef)").'"'} keys %$v ]})."}" } default {return $v} } } } } @_ ; chomp $res; #(index $res,-1,1) eq "\012" and $res=substr $res,0,length($res)-1; my $ctx = defined wantarray; ; #0x83=128+3=131 = non-breaking space -- if at end, trim it & don't CR; {use bytes; #pretend we know what we are doing... ;-) if ((ord substr $res,-1) eq 131) { #"NO_BREAK_HERE" my $w=0; $w=1 if (ord substr $res, -2,1) eq 194; #UTF-8 encoded? $res=substr $res,0,-($w+1)+length $res ; $ctx=1; }}; if (!$fh && !$ctx) { #internal consistancy check $fh = \*STDERR and P $fh "Invalid File Handle presented for output, using STDERR:"; $explicit_out=1; } else { return $res if (!$explicit_out and $ctx) } $fh->print ($res . (!$ctx ? "\n" : "") ); }; sub Pa(@) {goto &P}; sub Pe($;@) { return unless @_; unshift @_, \*STDERR; goto &P }; sub Pea(@) {goto &Pe}; sub Pae(@) {goto &Pe}; 1;} { package main; use utf8; (caller 0)[0] || do { $/=undef; $$_=; close main::DATA; eval "$$_"; 1; }; 1; } ############################################################################ #{{{1 # use P; =head1 NAME P, Pe, Pa, (& TBD: Pea/Pae) Safer, General Format + Print sub =head1 VERSION Version "$Version" =head1 SYNOPSIS P Pa @ARRAY Pe (same forms as P, but to STDERR) Pae (same form as Pa but to STDERR) =head1 DESCRIPTION P, while designed with development in mind, isn't limited to such. It combines features of printf, sprintf, and say: printing to strings if its output is assign to something, adding newlines when output is not to a string, ignoring a single extra newlines if added, allowing suppression of the auto-newline using the Unicode-control char "\0x83" "Don't break here". With few special cases to remember. Any items printed as strings that are undef -- will print 'undef'. =head1 EXAMPLES: =over 4 =item S<> =item S

=item S<> =item S

=item S<> =item S<$s = P "%s", "Hello %s"; # not needed if printing to string > =item S

=item S<@a = ("%s", "my string"); # using array, fmt as 1st arg > =item S =item S

=item S<@a = ("Hello %s", "World"); # format in array[0]> =item S =item S

=item S

=item S<> =item S

=item S< # NOTE: "," after FH L> =item S =item S< # P Hash bucket usage + contents > =item S< # with hashes> =item S<%H = (one =>ES< 1, two =>ES< 2, u =>ES< undef);> =item S

=item S

ES =back =head1 NOTES Note, values given as args to a formatted print statement, are checked for undef and substitute "(undef)" for undefined values. If you print vars as numbers, this has the side effect of causing runtime format errors, so best to print as strings to see 'undef'. While usable in any code, it's use was designed to save typing, time and work of undef checking, newline handling, and doing the right thing with given input. It may not be suitable where speed is important. Hidden (but documented) feature: inserting the 'NO BREAK HERE' control- char (\x83 or UTF-8 string \xc283) as the last char of a string will suppress a 'break' (newline) where it normally would be added. =cut #}}}1 __DATA__ # line ' .__LINE__ . ' "' ' __FILE__ . "\"\n" . ' foreach (qw{STDERR STDOUT}) {select *$_; $|=1}; use strict; use warnings; use Carp::Always; use P; { my $i; my $incr = sub { ++$i}; sub iter(){"Hello Perl ${\(0+&$incr)}"} } my $format="#%-2d %-25s: "; our $case=0; sub case ($) { $_=P (\*STDOUT, $format, ++$case, "(".$_[0].")"); ""; } case "ret from func"; P &iter; # case 1: return from func case "w/string"; P "${\(+iter())}"; # case 2 w/string case "passed array"; my @msg = ("%s", &iter ); Pa @msg; # case 3 (hack around perlbug) case "w/fmt+string"; P "%s",iter; # case 4 case "to STDERR"; P \*STDERR, iter; # case 5 #needs redirection to see case "to strng embedded in #7"; # case 6 to string; prints in case 7 my $str = P "%s",iter; P ""; case "prev string"; # case 7 - print embedded P output P "prev str=\"%s\" (no LF) && ${\(+iter())}", $str; case "p thru '/.../rev' fr/FH "; # case 8 - P 'pipe' my $fh; open $fh, "echo -n \"(echo) ${\(+iter)}\" |rev |tr -d \"\n\" |" or die p(\*STDERR, "Problem opening 'rev' util ($!),". " got PATH?(skipping)\n\n", 1); P \*STDOUT, "%s", $fh; case "P && array ref"; my @ar=qw(one two three 4 5 6); P "%s",\@ar; # case 9 - array expansion case "P HASH ref"; # case 10 - hash expansion my %hash=(a=>'apple', b=>'bread', c=>'cherry'); P "%s", \%hash; case "P PKG ref"; # case 11 - blessed object { my $hp; bless $hp={a=>1, b=>2}, 'PKG'; P "%s", $hp; } #case "as IO::HANDLE handler"; # case 1x - T.B.D. #P STDERR "Does this goto STDERR?"; #print STDERR ""; #case "as Glob handler?"; # case 1x - T.B.D. #Pg STDERR "Globing out?" # vim: ts=2 sw=2