Added :tidy, stream DDumper output through Perl::Tidy
[Data-Peek.git] / Peek.pm
blobe3b155054ec0e7187c8d2c4e0a20f73d7a675fe6
1 package Data::Peek;
3 use strict;
4 use warnings;
6 use DynaLoader ();
8 use vars qw( $VERSION @ISA @EXPORT @EXPORT_OK );
9 $VERSION = "0.32";
10 @ISA = qw( DynaLoader Exporter );
11 @EXPORT = qw( DDumper DDsort DPeek DDisplay DDump DHexDump DDual DGrow );
12 @EXPORT_OK = qw( triplevar :tidy );
13 push @EXPORT, "DDump_IO";
15 bootstrap Data::Peek $VERSION;
17 ### ############# DDumper () ##################################################
19 use Data::Dumper;
21 my %sk = (
22 undef => 0,
23 "" => 0,
24 0 => 0,
25 1 => 1,
27 V => sub { # Sort by value
28 my $r = shift;
29 [ sort { $r->{$a} cmp $r->{$b} } keys %$r ];
31 VN => sub { # Sort by value numeric
32 my $r = shift;
33 [ sort { $r->{$a} <=> $r->{$b} } keys %$r ];
35 VNR => sub { # Sort by value numeric reverse
36 my $r = shift;
37 [ sort { $r->{$b} <=> $r->{$a} } keys %$r ];
39 VR => sub { # Sort by value reverse
40 my $r = shift;
41 [ sort { $r->{$b} cmp $r->{$a} } keys %$r ];
43 R => sub { # Sort reverse
44 my $r = shift;
45 [ reverse sort keys %$r ];
48 my $_sortkeys = 1;
49 my $_perltidy;
51 sub DDsort
53 @_ or return;
55 $_sortkeys = exists $sk{$_[0]} ? $sk{$_[0]} : $_[0];
56 } # DDsort
58 sub import
60 my @exp = @_;
61 my @etl;
62 foreach my $p (@exp) {
63 exists $sk{$p} and DDsort ($p), next;
65 if ($p eq ":tidy") {
66 $_perltidy = eval q{use Perl::Tidy; $Perl::Tidy::VERSION };
67 next;
70 push @etl, $p;
72 __PACKAGE__->export_to_level (1, @etl);
73 } # import
75 sub DDumper
77 local $Data::Dumper::Sortkeys = $_sortkeys;
78 local $Data::Dumper::Indent = 1;
79 local $Data::Dumper::Quotekeys = 0;
80 local $Data::Dumper::Deparse = 1;
81 local $Data::Dumper::Terse = 1;
82 local $Data::Dumper::Useqq = 0; # I want unicode visible
84 my $s = Data::Dumper::Dumper @_;
85 if ($_perltidy) {
86 Perl::Tidy::perltidy (source => \$s, destination => \my $t);
87 $s = $t;
89 else {
90 $s =~ s/^(\s*)(.*?)\s*=>/sprintf "%s%-16s =>", $1, $2/gme; # Align =>
91 $s =~ s/\bbless\s*\(\s*/bless (/gm and $s =~ s/\s+\)([;,])$/)$1/gm;
92 $s =~ s/^(?= *[]}](?:[;,]|$))/ /gm;
93 $s =~ s/^(\s*[{[]) *\n *(?=\S)(?![{[])/$1 /gm;
94 $s =~ s/^(\s+)/$1$1/gm;
97 defined wantarray or warn $s;
98 return $s;
99 } # DDumper
101 ### ############# DDump () ####################################################
103 our $has_perlio;
105 BEGIN {
106 use Config;
107 $has_perlio = ($Config{useperlio} || "undef") eq "define";
110 sub _DDump_ref
112 my (undef, $down) = (@_, 0);
114 my $ref = ref $_[0];
115 if ($ref eq "SCALAR" || $ref eq "REF") {
116 my %hash = DDump (${$_[0]}, $down);
117 return { %hash };
119 if ($ref eq "ARRAY") {
120 my @list;
121 foreach my $list (@{$_[0]}) {
122 my %hash = DDump ($list, $down);
123 push @list, { %hash };
125 return [ @list ];
127 if ($ref eq "HASH") {
128 my %hash;
129 foreach my $key (sort keys %{$_[0]}) {
130 $hash{DPeek ($key)} = { DDump ($_[0]->{$key}, $down) };
132 return { %hash };
134 undef;
135 } # _DDump_ref
137 sub _DDump
139 my (undef, $down, $dump, $fh) = (@_, "");
141 if ($has_perlio and open $fh, ">", \$dump) {
142 #print STDERR "Using DDump_IO\n";
143 DDump_IO ($fh, $_[0], $down);
144 close $fh;
146 else {
147 #print STDERR "Using DDump_XS\n";
148 $dump = DDump_XS ($_[0]);
151 return $dump;
152 } # _DDump
154 sub DDump ($;$)
156 my (undef, $down) = (@_, 0);
157 my @dump = split m/[\r\n]+/, _DDump ($_[0], wantarray || $down) or return;
159 if (wantarray) {
160 my %hash;
161 ($hash{sv} = $dump[0]) =~ s/^SV\s*=\s*//;
162 m/^\s+(\w+)\s*=\s*(.*)/ and $hash{$1} = $2 for @dump;
164 if (exists $hash{FLAGS}) {
165 $hash{FLAGS} =~ tr/()//d;
166 $hash{FLAGS} = { map { $_ => 1 } split m/,/ => $hash{FLAGS} };
169 $down && ref $_[0] and
170 $hash{RV} = _DDump_ref ($_[0], $down - 1) || $_[0];
171 return %hash;
174 my $dump = join "\n", @dump, "";
176 defined wantarray and return $dump;
178 warn $dump;
179 } # DDump
181 sub DHexDump
183 use bytes;
184 my $off = 0;
185 my @out;
186 my $var = @_ ? $_[0] : $_;
187 defined $var or return;
188 my $str = "$var"; # force stringification
189 for (unpack "(A32)*", unpack "H*", $str) {
190 my @b = unpack "(A2)*", $_;
191 my $out = sprintf "%04x ", $off;
192 $out .= " ".($b[$_]||" ") for 0 .. 7;
193 $out .= " ";
194 $out .= " ".($b[$_]||" ") for 8 .. 15;
195 $out .= " ";
196 $out .= ($_ < 0x20 || $_ >= 0x7f ? "." : chr $_) for map { hex $_ } @b;
197 push @out, $out."\n";
198 $off += 16;
201 wantarray and return @out;
203 defined wantarray and return join "", @out;
205 warn join "", @out;
206 } # DHexDump
208 "Indent";
210 __END__
212 =head1 NAME
214 Data::Peek - A collection of low-level debug facilities
216 =head1 SYNOPSIS
218 use Data::Peek;
220 print DDumper \%hash; # Same syntax as Data::Dumper
222 print DPeek \$var;
223 my ($pv, $iv, $nv, $rv, $magic) = DDual ($var [, 1]);
224 print DPeek for DDual ($!, 1);
225 print DDisplay ("ab\nc\x{20ac}\rdef\n");
226 print DHexDump ("ab\nc\x{20ac}\rdef\n");
228 my $dump = DDump $var;
229 my %hash = DDump \@list;
230 DDump \%hash;
232 my %hash = DDump (\%hash, 5); # dig 5 levels deep
234 my $dump;
235 open my $fh, ">", \$dump;
236 DDump_IO ($fh, \%hash, 6);
237 close $fh;
238 print $dump;
240 use Data::Peek qw( DGrow triplevar );
241 my $x = ""; DGrow ($x, 10000);
242 my $tv = triplevar ("\N{GREEK SMALL LETTER PI}", 3, "3.1415");
244 =head1 DESCRIPTION
246 Data::Peek started off as C<DDumper> being a wrapper module over
247 L<Data::Dumper>, but grew out to be a set of low-level data
248 introspection utilities that no other module provided yet, using the
249 lowest level of the perl internals API as possible.
251 =head2 DDumper ($var, ...)
253 Not liking the default output of Data::Dumper, and always feeling the need
254 to set C<$Data::Dumper::Sortkeys = 1;>, and not liking any of the default
255 layouts, this function is just a wrapper around Data::Dumper::Dumper with
256 everything set as I like it.
258 $Data::Dumper::Sortkeys = 1;
259 $Data::Dumper::Indent = 1;
261 And the result is further beautified to meet my needs:
263 * quotation of hash keys has been removed (with the disadvantage
264 that the output might not be parseable again).
265 * arrows for hashes are aligned at 16 (longer keys don't align)
266 * closing braces and brackets are now correctly aligned
268 In void context, C<DDumper ()> warn ()'s.
270 Example
272 $ perl -MDP \
273 -e'DDumper { ape => 1, foo => "egg", bar => [ 2, "baz", undef ]};'
275 { ape => 1,
276 bar => [
278 'baz',
279 undef
281 foo => 'egg'
284 If C<Data::Peek> is C<use>d with import argument C<:tidy>, the output
285 of C<DDumper> is formatted using C<Perl::Tidy> (if available) according
286 to your C<.perltidyrc>, maybe somewhat like (YMMV):
288 $ perl -MDP=:tidy \
289 -we'DDumper { ape => 1, foo => "egg", bar => [ 2, "baz", undef ]};'
290 { ape => 1,
291 bar => [2, 'baz', undef],
292 foo => 'egg'
295 =head2 DDsort ( 0 | 1 | R | V | VR | VN | VNR )
297 Set the hash sort algorithm for DDumper. The default is to sort by key value.
299 0 - Do not sort
300 1 - Sort by key
301 R - Reverse sort by key
302 V - Sort by value
303 VR - Reverse sort by value
304 VN - Sort by value numerical
305 VNR - Reverse sort by value numerical
307 These can also be passed to import:
309 $ perl -MDP=VNR \
310 -we'DDumper { foo => 1, bar => 2, zap => 3, gum => 13 }'
311 { gum => 13,
312 zap => 3,
313 bar => 2,
314 foo => 1
316 $ perl -MDP=V \
317 -we'DDumper { foo => 1, bar => 2, zap => 3, gum => 13 }'
318 { foo => 1,
319 gum => 13,
320 bar => 2,
321 zap => 3
324 =head2 DPeek
326 =head2 DPeek ($var)
328 Playing with C<sv_dump ()>, I found C<Perl_sv_peek ()>, and it might be
329 very useful for simple checks. If C<$var> is omitted, uses $_.
331 Example
333 print DPeek "abc\x{0a}de\x{20ac}fg";
335 PV("abc\nde\342\202\254fg"\0) [UTF8 "abc\nde\x{20ac}fg"]
337 In void context, C<DPeek ()> prints to C<STDERR> plus a newline.
339 =head2 DDisplay
341 =head2 DDisplay ($var)
343 Show the PV content of a scalar the way perl debugging would have done.
344 UTF-8 detection is on, so this is effectively the same as returning the
345 first part the C<DPeek ()> returns for non-UTF8 PV's or the second part
346 for UTF-8 PV's. C<DDisplay ()> returns the empty string for scalars that
347 no have a valid PV.
349 Example
351 print DDisplay "abc\x{0a}de\x{20ac}fg";
353 "abc\nde\x{20ac}fg"
355 =head2 DHexDump
357 =head2 DHexDump ($var)
359 Show the (stringified) content of a scalar as a hex-dump. If C<$var>
360 is omitted, C<$_> is dumped. Returns C<undef> or an empty list if
361 C<$var> (or C<$_>) is undefined.
363 In void context, the dump is done to STDERR. In scalar context, the
364 complete dump is returned as a single string. In list context, the dump
365 is returned as lines.
367 Example
369 print DHexDump "abc\x{0a}de\x{20ac}fg";
371 0000 61 62 63 0a 64 65 e2 82 ac 66 67 abc.de...fg
373 =head2 my ($pv, $iv, $nv, $rv, $hm) = DDual ($var [, $getmagic])
375 DDual will return the basic elements in a variable, guaranteeing that no
376 conversion takes place. This is very useful for dual-var variables, or
377 when checking is a variable has defined entries for a certain type of
378 scalar. For each String (PV), Integer (IV), Double (NV), and Reference (RV),
379 the current value of C<$var> is returned or undef if it is not set (yet).
380 The 5th element is an indicator if C<$var> has magic, which is B<not> invoked
381 in the returned values, unless explicitly asked for with a true optional
382 second argument.
384 Example
386 print DPeek for DDual ($!, 1);
388 In void context, DDual does the equivalent of
390 { my @d = DDual ($!, 1);
391 print STDERR
392 DPeek ($!), "\n",
393 " PV: ", DPeek ($d[0]), "\n",
394 " IV: ", DPeek ($d[1]), "\n",
395 " NV: ", DPeek ($d[2]), "\n",
396 " RV: ", DPeek ($d[3]), "\n";
399 =head2 my $len = DGrow ($pv, $size)
401 Fastest way to preallocate space for a PV scalar. Returns the allocated
402 length. If $size is smaller than the already allocated space, it will
403 not shrink.
405 cmpthese (-2, {
406 pack => q{my $x = ""; $x = pack "x20000"; $x = "";},
407 op_x => q{my $x = ""; $x = "x" x 20000; $x = "";},
408 grow => q{my $x = ""; DGrow ($x, 20000); $x = "";},
411 Rate op_x pack grow
412 op_x 62127/s -- -59% -96%
413 pack 152046/s 145% -- -91%
414 grow 1622943/s 2512% 967% --
417 =head2 my $tp = triplevar ($pv, $iv, $nv)
419 When making C<DDual ()> I wondered if it were possible to create triple-val
420 scalar variables. L<Scalar::Util> already gives us C<dualvar ()>, that creates
421 you a scalar with different numeric and string values that return different
422 values in different context. Not that C<triplevar ()> would be very useful,
423 compared to C<dualvar ()>, but at least this shows that it is possible.
425 C<triplevar ()> is not exported by default.
427 Example:
429 print DPeek for DDual
430 Data::Peek::triplevar ("\N{GREEK SMALL LETTER PI}", 3, 3.1415);
432 PV("\317\200"\0) [UTF8 "\x{3c0}"]
433 IV(3)
434 NV(3.1415)
435 SV_UNDEF
436 IV(0)
438 =head2 DDump ($var [, $dig_level])
440 A very useful module when debugging is C<Devel::Peek>, but is has one big
441 disadvantage: it only prints to STDERR, which is not very handy when your
442 code wants to inspect variables at a low level.
444 Perl itself has C<sv_dump ()>, which does something similar, but still
445 prints to STDERR, and only one level deep.
447 C<DDump ()> is an attempt to make the innards available to the script level
448 with a reasonable level of compatibility. C<DDump ()> is context sensitive.
450 In void context, it behaves exactly like C<Perl_sv_dump ()>.
452 In scalar context, it returns what C<Perl_sv_dump ()> would have printed.
454 In list context, it returns a hash of the variable's properties. In this mode
455 you can pass an optional second argument that determines the depth of digging.
457 Example
459 print scalar DDump "abc\x{0a}de\x{20ac}fg"
461 SV = PV(0x723250) at 0x8432b0
462 REFCNT = 1
463 FLAGS = (PADBUSY,PADMY,POK,pPOK,UTF8)
464 PV = 0x731ac0 "abc\nde\342\202\254fg"\0 [UTF8 "abc\nde\x{20ac}fg"]
465 CUR = 11
466 LEN = 16
468 my %h = DDump "abc\x{0a}de\x{20ac}fg";
469 print DDumper \%h;
471 { CUR => '11',
472 FLAGS => {
473 PADBUSY => 1,
474 PADMY => 1,
475 POK => 1,
476 UTF8 => 1,
477 pPOK => 1
479 LEN => '16',
480 PV => '0x731ac0 "abc\\nde\\342\\202\\254fg"\\0 [UTF8 "abc\\nde\\x{20ac}fg"]',
481 REFCNT => '1',
482 sv => 'PV(0x723250) at 0x8432c0'
485 my %h = DDump {
486 ape => 1,
487 foo => "egg",
488 bar => [ 2, "baz", undef ],
489 }, 1;
490 print DDumper \%h;
492 { FLAGS => {
493 PADBUSY => 1,
494 PADMY => 1,
495 ROK => 1
497 REFCNT => '1',
498 RV => {
499 PVIV("ape") => {
500 FLAGS => {
501 IOK => 1,
502 PADBUSY => 1,
503 PADMY => 1,
504 pIOK => 1
506 IV => '1',
507 REFCNT => '1',
508 sv => 'IV(0x747020) at 0x843a10'
510 PVIV("bar") => {
511 CUR => '0',
512 FLAGS => {
513 PADBUSY => 1,
514 PADMY => 1,
515 ROK => 1
517 IV => '1',
518 LEN => '0',
519 PV => '0x720210 ""',
520 REFCNT => '1',
521 RV => '0x720210',
522 sv => 'PVIV(0x7223e0) at 0x843a10'
524 PVIV("foo") => {
525 CUR => '3',
526 FLAGS => {
527 PADBUSY => 1,
528 PADMY => 1,
529 POK => 1,
530 pPOK => 1
532 IV => '1',
533 LEN => '8',
534 PV => '0x7496c0 "egg"\\0',
535 REFCNT => '1',
536 sv => 'PVIV(0x7223e0) at 0x843a10'
539 sv => 'RV(0x79d058) at 0x843310'
542 =head2 DDump_IO ($io, $var [, $dig_level])
544 A wrapper function around perl's internal C<Perl_do_sv_dump ()>, which
545 makes C<Devel::Peek> completely superfluous.
547 Example
549 my $dump;
550 open my $eh, ">", \$dump;
551 DDump_IO ($eh, { 3 => 4, ape => [5..8]}, 6);
552 close $eh;
553 print $dump;
555 SV = RV(0x79d9e0) at 0x843f00
556 REFCNT = 1
557 FLAGS = (TEMP,ROK)
558 RV = 0x741090
559 SV = PVHV(0x79c948) at 0x741090
560 REFCNT = 1
561 FLAGS = (SHAREKEYS)
562 IV = 2
563 NV = 0
564 ARRAY = 0x748ff0 (0:7, 2:1)
565 hash quality = 62.5%
566 KEYS = 2
567 FILL = 1
568 MAX = 7
569 RITER = -1
570 EITER = 0x0
571 Elt "ape" HASH = 0x97623e03
572 SV = RV(0x79d9d8) at 0x8440e0
573 REFCNT = 1
574 FLAGS = (ROK)
575 RV = 0x741470
576 SV = PVAV(0x7264b0) at 0x741470
577 REFCNT = 2
578 FLAGS = ()
579 IV = 0
580 NV = 0
581 ARRAY = 0x822f70
582 FILL = 3
583 MAX = 3
584 ARYLEN = 0x0
585 FLAGS = (REAL)
586 Elt No. 0
587 SV = IV(0x7467c8) at 0x7c1aa0
588 REFCNT = 1
589 FLAGS = (IOK,pIOK)
590 IV = 5
591 Elt No. 1
592 SV = IV(0x7467b0) at 0x8440f0
593 REFCNT = 1
594 FLAGS = (IOK,pIOK)
595 IV = 6
596 Elt No. 2
597 SV = IV(0x746810) at 0x75be00
598 REFCNT = 1
599 FLAGS = (IOK,pIOK)
600 IV = 7
601 Elt No. 3
602 SV = IV(0x746d38) at 0x7799d0
603 REFCNT = 1
604 FLAGS = (IOK,pIOK)
605 IV = 8
606 Elt "3" HASH = 0xa400c7f3
607 SV = IV(0x746fd0) at 0x7200e0
608 REFCNT = 1
609 FLAGS = (IOK,pIOK)
610 IV = 4
612 =head1 INTERNALS
614 C<DDump ()> uses an XS wrapper around C<Perl_sv_dump ()> where the
615 STDERR is temporarily caught to a pipe. The internal XS helper functions
616 are not meant for user space
618 =head2 DDump_XS (SV *sv)
620 Base interface to internals for C<DDump ()>.
622 =head1 BUGS
624 Windows and AIX might be using a build where not all symbols that were
625 supposed to be exported in the public API are not. Perl_pv_peek () is
626 one of them.
628 Not all types of references are supported.
630 No idea how far back this goes in perl support, but Devel::PPPort has
631 proven to be a big help.
633 =head1 SEE ALSO
635 L<Devel::Peek>, L<Data::Dumper>, L<Data::Dump>, L<Devel::Dumpvar>,
636 L<Data::Dump::Streamer>
638 =head1 AUTHOR
640 H.Merijn Brand <h.m.brand@xs4all.nl>
642 =head1 COPYRIGHT AND LICENSE
644 Copyright (C) 2008-2010 H.Merijn Brand
646 This library is free software; you can redistribute it and/or modify
647 it under the same terms as Perl itself.
649 =cut