Tests require Test::More-0.88 or up (RT#70538)
[Data-Peek.git] / Peek.pm
blobbdd380376c5d578ab48764c5b283cfb2d1c4d8c3
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.34";
10 @ISA = qw( DynaLoader Exporter );
11 @EXPORT = qw( DDumper DTidy DDsort DPeek DDisplay DDump DHexDump
12 DDual DGrow );
13 @EXPORT_OK = qw( triplevar :tidy );
14 push @EXPORT, "DDump_IO";
16 bootstrap Data::Peek $VERSION;
18 our $has_perlio;
19 our $has_perltidy;
21 BEGIN {
22 use Config;
23 $has_perlio = ($Config{useperlio} || "undef") eq "define";
24 $has_perltidy = eval q{use Perl::Tidy; $Perl::Tidy::VERSION};
27 ### ############# DDumper () ##################################################
29 use Data::Dumper;
31 my %sk = (
32 undef => 0,
33 "" => 0,
34 0 => 0,
35 1 => 1,
37 V => sub { # Sort by value
38 my $r = shift;
39 [ sort { $r->{$a} cmp $r->{$b} } keys %$r ];
41 VN => sub { # Sort by value numeric
42 my $r = shift;
43 [ sort { $r->{$a} <=> $r->{$b} } keys %$r ];
45 VNR => sub { # Sort by value numeric reverse
46 my $r = shift;
47 [ sort { $r->{$b} <=> $r->{$a} } keys %$r ];
49 VR => sub { # Sort by value reverse
50 my $r = shift;
51 [ sort { $r->{$b} cmp $r->{$a} } keys %$r ];
53 R => sub { # Sort reverse
54 my $r = shift;
55 [ reverse sort keys %$r ];
58 my $_sortkeys = 1;
59 our $_perltidy = 0;
61 sub DDsort
63 @_ or return;
65 $_sortkeys = exists $sk{$_[0]} ? $sk{$_[0]} : $_[0];
66 } # DDsort
68 sub import
70 my @exp = @_;
71 my @etl;
72 foreach my $p (@exp) {
73 exists $sk{$p} and DDsort ($p), next;
75 if ($p eq ":tidy") {
76 $_perltidy = $has_perltidy;
77 next;
80 push @etl, $p;
82 __PACKAGE__->export_to_level (1, @etl);
83 } # import
85 sub DDumper
87 $_perltidy and goto \&DTidy;
89 local $Data::Dumper::Sortkeys = $_sortkeys;
90 local $Data::Dumper::Indent = 1;
91 local $Data::Dumper::Quotekeys = 0;
92 local $Data::Dumper::Deparse = 1;
93 local $Data::Dumper::Terse = 1;
94 local $Data::Dumper::Useqq = 0; # I want unicode visible
96 my $s = Data::Dumper::Dumper @_;
97 $s =~ s/^(\s*)(.*?)\s*=>/sprintf "%s%-16s =>", $1, $2/gme; # Align =>
98 $s =~ s/\bbless\s*\(\s*/bless (/gm and $s =~ s/\s+\)([;,])$/)$1/gm;
99 $s =~ s/^(?= *[]}](?:[;,]|$))/ /gm;
100 $s =~ s/^(\s*[{[]) *\n *(?=\S)(?![{[])/$1 /gm;
101 $s =~ s/^(\s+)/$1$1/gm;
103 defined wantarray or warn $s;
104 return $s;
105 } # DDumper
107 sub DTidy
109 $has_perltidy or goto \&DDumper;
111 local $Data::Dumper::Sortkeys = $_sortkeys;
112 local $Data::Dumper::Indent = 1;
113 local $Data::Dumper::Quotekeys = 1;
114 local $Data::Dumper::Deparse = 1;
115 local $Data::Dumper::Terse = 1;
116 local $Data::Dumper::Useqq = 0;
118 my $s = Data::Dumper::Dumper @_;
119 Perl::Tidy::perltidy (source => \$s, destination => \my $t);
120 $s = $t;
122 defined wantarray or warn $s;
123 return $s;
124 } # DTidy
126 ### ############# DDump () ####################################################
128 sub _DDump_ref
130 my (undef, $down) = (@_, 0);
132 my $ref = ref $_[0];
133 if ($ref eq "SCALAR" || $ref eq "REF") {
134 my %hash = DDump (${$_[0]}, $down);
135 return { %hash };
137 if ($ref eq "ARRAY") {
138 my @list;
139 foreach my $list (@{$_[0]}) {
140 my %hash = DDump ($list, $down);
141 push @list, { %hash };
143 return [ @list ];
145 if ($ref eq "HASH") {
146 my %hash;
147 foreach my $key (sort keys %{$_[0]}) {
148 $hash{DPeek ($key)} = { DDump ($_[0]->{$key}, $down) };
150 return { %hash };
152 undef;
153 } # _DDump_ref
155 sub _DDump
157 my (undef, $down, $dump, $fh) = (@_, "");
159 if ($has_perlio and open $fh, ">", \$dump) {
160 #print STDERR "Using DDump_IO\n";
161 DDump_IO ($fh, $_[0], $down);
162 close $fh;
164 else {
165 #print STDERR "Using DDump_XS\n";
166 $dump = DDump_XS ($_[0]);
169 return $dump;
170 } # _DDump
172 sub DDump ($;$)
174 my (undef, $down) = (@_, 0);
175 my @dump = split m/[\r\n]+/, _DDump ($_[0], wantarray || $down) or return;
177 if (wantarray) {
178 my %hash;
179 ($hash{sv} = $dump[0]) =~ s/^SV\s*=\s*//;
180 m/^\s+(\w+)\s*=\s*(.*)/ and $hash{$1} = $2 for @dump;
182 if (exists $hash{FLAGS}) {
183 $hash{FLAGS} =~ tr/()//d;
184 $hash{FLAGS} = { map { $_ => 1 } split m/,/ => $hash{FLAGS} };
187 $down && ref $_[0] and
188 $hash{RV} = _DDump_ref ($_[0], $down - 1) || $_[0];
189 return %hash;
192 my $dump = join "\n", @dump, "";
194 defined wantarray and return $dump;
196 warn $dump;
197 } # DDump
199 sub DHexDump
201 use bytes;
202 my $off = 0;
203 my @out;
204 my $var = @_ ? $_[0] : $_;
205 defined $var or return;
206 my $str = "$var"; # force stringification
207 for (unpack "(A32)*", unpack "H*", $str) {
208 my @b = unpack "(A2)*", $_;
209 my $out = sprintf "%04x ", $off;
210 $out .= " ".($b[$_]||" ") for 0 .. 7;
211 $out .= " ";
212 $out .= " ".($b[$_]||" ") for 8 .. 15;
213 $out .= " ";
214 $out .= ($_ < 0x20 || $_ >= 0x7f ? "." : chr $_) for map { hex $_ } @b;
215 push @out, $out."\n";
216 $off += 16;
219 wantarray and return @out;
221 defined wantarray and return join "", @out;
223 warn join "", @out;
224 } # DHexDump
226 "Indent";
228 __END__
230 =head1 NAME
232 Data::Peek - A collection of low-level debug facilities
234 =head1 SYNOPSIS
236 use Data::Peek;
238 print DDumper \%hash; # Same syntax as Data::Dumper
239 DTidy { ref => $ref };
241 print DPeek \$var;
242 my ($pv, $iv, $nv, $rv, $magic) = DDual ($var [, 1]);
243 print DPeek for DDual ($!, 1);
244 print DDisplay ("ab\nc\x{20ac}\rdef\n");
245 print DHexDump ("ab\nc\x{20ac}\rdef\n");
247 my $dump = DDump $var;
248 my %hash = DDump \@list;
249 DDump \%hash;
251 my %hash = DDump (\%hash, 5); # dig 5 levels deep
253 my $dump;
254 open my $fh, ">", \$dump;
255 DDump_IO ($fh, \%hash, 6);
256 close $fh;
257 print $dump;
259 # Imports
260 use Data::Peek qw( :tidy VNR DGrow triplevar );
261 my $x = ""; DGrow ($x, 10000);
262 my $tv = triplevar ("\N{GREEK SMALL LETTER PI}", 3, "3.1415");
263 DDsort ("R");
264 DDumper [ $x ]; # use of :tidy make DDumper behave as DTidy
266 =head1 DESCRIPTION
268 Data::Peek started off as C<DDumper> being a wrapper module over
269 L<Data::Dumper>, but grew out to be a set of low-level data
270 introspection utilities that no other module provided yet, using the
271 lowest level of the perl internals API as possible.
273 =head2 DDumper ($var, ...)
275 Not liking the default output of Data::Dumper, and always feeling the need
276 to set C<$Data::Dumper::Sortkeys = 1;>, and not liking any of the default
277 layouts, this function is just a wrapper around Data::Dumper::Dumper with
278 everything set as I like it.
280 $Data::Dumper::Sortkeys = 1;
281 $Data::Dumper::Indent = 1;
283 If C<Data::Peek> is C<use>d with import argument C<:tidy>, the result is
284 formatted according to L<Perl::Tidy>, see L<DTidy> below, otherwise the
285 result is further beautified to meet my needs:
287 * quotation of hash keys has been removed (with the disadvantage
288 that the output might not be parseable again).
289 * arrows for hashes are aligned at 16 (longer keys don't align)
290 * closing braces and brackets are now correctly aligned
292 In void context, C<DDumper ()> warn ()'s.
294 Example
296 $ perl -MDP \
297 -e'DDumper { ape => 1, foo => "egg", bar => [ 2, "baz", undef ]};'
299 { ape => 1,
300 bar => [
302 'baz',
303 undef
305 foo => 'egg'
308 =head2 DTidy ($var, ...)
310 C<DTidy> is an alternative to C<DDumper>, where the output of C<DDumper>
311 is formatted using C<Perl::Tidy> (if available) according to your
312 C<.perltidyrc> instead of the default behavior, maybe somewhat like (YMMV):
314 $ perl -MDP=:tidy \
315 -we'DDumper { ape => 1, foo => "egg", bar => [ 2, "baz", undef ]};'
316 { 'ape' => 1,
317 'bar' => [2, 'baz', undef],
318 'foo' => 'egg'
321 If C<Data::Peek> is C<use>d with import argument C<:tidy>, this is the
322 default output method for C<DDumper>.
324 If L<Perl::Tidy> is not available, C<DTidy> will fallback to C<DDumper>.
326 This idea was shamelessly copied from John McNamara's L<Data::Dumper::Perltidy>.
328 =head2 DDsort ( 0 | 1 | R | V | VR | VN | VNR )
330 Set the hash sort algorithm for DDumper. The default is to sort by key value.
332 0 - Do not sort
333 1 - Sort by key
334 R - Reverse sort by key
335 V - Sort by value
336 VR - Reverse sort by value
337 VN - Sort by value numerical
338 VNR - Reverse sort by value numerical
340 These can also be passed to import:
342 $ perl -MDP=VNR \
343 -we'DDumper { foo => 1, bar => 2, zap => 3, gum => 13 }'
344 { gum => 13,
345 zap => 3,
346 bar => 2,
347 foo => 1
349 $ perl -MDP=V \
350 -we'DDumper { foo => 1, bar => 2, zap => 3, gum => 13 }'
351 { foo => 1,
352 gum => 13,
353 bar => 2,
354 zap => 3
357 =head2 DPeek
359 =head2 DPeek ($var)
361 Playing with C<sv_dump ()>, I found C<Perl_sv_peek ()>, and it might be
362 very useful for simple checks. If C<$var> is omitted, uses $_.
364 Example
366 print DPeek "abc\x{0a}de\x{20ac}fg";
368 PV("abc\nde\342\202\254fg"\0) [UTF8 "abc\nde\x{20ac}fg"]
370 In void context, C<DPeek ()> prints to C<STDERR> plus a newline.
372 =head2 DDisplay
374 =head2 DDisplay ($var)
376 Show the PV content of a scalar the way perl debugging would have done.
377 UTF-8 detection is on, so this is effectively the same as returning the
378 first part the C<DPeek ()> returns for non-UTF8 PV's or the second part
379 for UTF-8 PV's. C<DDisplay ()> returns the empty string for scalars that
380 no have a valid PV.
382 Example
384 print DDisplay "abc\x{0a}de\x{20ac}fg";
386 "abc\nde\x{20ac}fg"
388 =head2 DHexDump
390 =head2 DHexDump ($var)
392 Show the (stringified) content of a scalar as a hex-dump. If C<$var>
393 is omitted, C<$_> is dumped. Returns C<undef> or an empty list if
394 C<$var> (or C<$_>) is undefined.
396 In void context, the dump is done to STDERR. In scalar context, the
397 complete dump is returned as a single string. In list context, the dump
398 is returned as lines.
400 Example
402 print DHexDump "abc\x{0a}de\x{20ac}fg";
404 0000 61 62 63 0a 64 65 e2 82 ac 66 67 abc.de...fg
406 =head2 my ($pv, $iv, $nv, $rv, $hm) = DDual ($var [, $getmagic])
408 DDual will return the basic elements in a variable, guaranteeing that no
409 conversion takes place. This is very useful for dual-var variables, or
410 when checking is a variable has defined entries for a certain type of
411 scalar. For each String (PV), Integer (IV), Double (NV), and Reference (RV),
412 the current value of C<$var> is returned or undef if it is not set (yet).
413 The 5th element is an indicator if C<$var> has magic, which is B<not> invoked
414 in the returned values, unless explicitly asked for with a true optional
415 second argument.
417 Example
419 print DPeek for DDual ($!, 1);
421 In void context, DDual does the equivalent of
423 { my @d = DDual ($!, 1);
424 print STDERR
425 DPeek ($!), "\n",
426 " PV: ", DPeek ($d[0]), "\n",
427 " IV: ", DPeek ($d[1]), "\n",
428 " NV: ", DPeek ($d[2]), "\n",
429 " RV: ", DPeek ($d[3]), "\n";
432 =head2 my $len = DGrow ($pv, $size)
434 Fastest way to preallocate space for a PV scalar. Returns the allocated
435 length. If $size is smaller than the already allocated space, it will
436 not shrink.
438 cmpthese (-2, {
439 pack => q{my $x = ""; $x = pack "x20000"; $x = "";},
440 op_x => q{my $x = ""; $x = "x" x 20000; $x = "";},
441 grow => q{my $x = ""; DGrow ($x, 20000); $x = "";},
444 Rate op_x pack grow
445 op_x 62127/s -- -59% -96%
446 pack 152046/s 145% -- -91%
447 grow 1622943/s 2512% 967% --
450 =head2 my $tp = triplevar ($pv, $iv, $nv)
452 When making C<DDual ()> I wondered if it were possible to create triple-val
453 scalar variables. L<Scalar::Util> already gives us C<dualvar ()>, that creates
454 you a scalar with different numeric and string values that return different
455 values in different context. Not that C<triplevar ()> would be very useful,
456 compared to C<dualvar ()>, but at least this shows that it is possible.
458 C<triplevar ()> is not exported by default.
460 Example:
462 print DPeek for DDual
463 Data::Peek::triplevar ("\N{GREEK SMALL LETTER PI}", 3, 3.1415);
465 PV("\317\200"\0) [UTF8 "\x{3c0}"]
466 IV(3)
467 NV(3.1415)
468 SV_UNDEF
469 IV(0)
471 =head2 DDump ($var [, $dig_level])
473 A very useful module when debugging is C<Devel::Peek>, but is has one big
474 disadvantage: it only prints to STDERR, which is not very handy when your
475 code wants to inspect variables at a low level.
477 Perl itself has C<sv_dump ()>, which does something similar, but still
478 prints to STDERR, and only one level deep.
480 C<DDump ()> is an attempt to make the innards available to the script level
481 with a reasonable level of compatibility. C<DDump ()> is context sensitive.
483 In void context, it behaves exactly like C<Perl_sv_dump ()>.
485 In scalar context, it returns what C<Perl_sv_dump ()> would have printed.
487 In list context, it returns a hash of the variable's properties. In this mode
488 you can pass an optional second argument that determines the depth of digging.
490 Example
492 print scalar DDump "abc\x{0a}de\x{20ac}fg"
494 SV = PV(0x723250) at 0x8432b0
495 REFCNT = 1
496 FLAGS = (PADBUSY,PADMY,POK,pPOK,UTF8)
497 PV = 0x731ac0 "abc\nde\342\202\254fg"\0 [UTF8 "abc\nde\x{20ac}fg"]
498 CUR = 11
499 LEN = 16
501 my %h = DDump "abc\x{0a}de\x{20ac}fg";
502 print DDumper \%h;
504 { CUR => '11',
505 FLAGS => {
506 PADBUSY => 1,
507 PADMY => 1,
508 POK => 1,
509 UTF8 => 1,
510 pPOK => 1
512 LEN => '16',
513 PV => '0x731ac0 "abc\\nde\\342\\202\\254fg"\\0 [UTF8 "abc\\nde\\x{20ac}fg"]',
514 REFCNT => '1',
515 sv => 'PV(0x723250) at 0x8432c0'
518 my %h = DDump {
519 ape => 1,
520 foo => "egg",
521 bar => [ 2, "baz", undef ],
522 }, 1;
523 print DDumper \%h;
525 { FLAGS => {
526 PADBUSY => 1,
527 PADMY => 1,
528 ROK => 1
530 REFCNT => '1',
531 RV => {
532 PVIV("ape") => {
533 FLAGS => {
534 IOK => 1,
535 PADBUSY => 1,
536 PADMY => 1,
537 pIOK => 1
539 IV => '1',
540 REFCNT => '1',
541 sv => 'IV(0x747020) at 0x843a10'
543 PVIV("bar") => {
544 CUR => '0',
545 FLAGS => {
546 PADBUSY => 1,
547 PADMY => 1,
548 ROK => 1
550 IV => '1',
551 LEN => '0',
552 PV => '0x720210 ""',
553 REFCNT => '1',
554 RV => '0x720210',
555 sv => 'PVIV(0x7223e0) at 0x843a10'
557 PVIV("foo") => {
558 CUR => '3',
559 FLAGS => {
560 PADBUSY => 1,
561 PADMY => 1,
562 POK => 1,
563 pPOK => 1
565 IV => '1',
566 LEN => '8',
567 PV => '0x7496c0 "egg"\\0',
568 REFCNT => '1',
569 sv => 'PVIV(0x7223e0) at 0x843a10'
572 sv => 'RV(0x79d058) at 0x843310'
575 =head2 DDump_IO ($io, $var [, $dig_level])
577 A wrapper function around perl's internal C<Perl_do_sv_dump ()>, which
578 makes C<Devel::Peek> completely superfluous.
580 Example
582 my $dump;
583 open my $eh, ">", \$dump;
584 DDump_IO ($eh, { 3 => 4, ape => [5..8]}, 6);
585 close $eh;
586 print $dump;
588 SV = RV(0x79d9e0) at 0x843f00
589 REFCNT = 1
590 FLAGS = (TEMP,ROK)
591 RV = 0x741090
592 SV = PVHV(0x79c948) at 0x741090
593 REFCNT = 1
594 FLAGS = (SHAREKEYS)
595 IV = 2
596 NV = 0
597 ARRAY = 0x748ff0 (0:7, 2:1)
598 hash quality = 62.5%
599 KEYS = 2
600 FILL = 1
601 MAX = 7
602 RITER = -1
603 EITER = 0x0
604 Elt "ape" HASH = 0x97623e03
605 SV = RV(0x79d9d8) at 0x8440e0
606 REFCNT = 1
607 FLAGS = (ROK)
608 RV = 0x741470
609 SV = PVAV(0x7264b0) at 0x741470
610 REFCNT = 2
611 FLAGS = ()
612 IV = 0
613 NV = 0
614 ARRAY = 0x822f70
615 FILL = 3
616 MAX = 3
617 ARYLEN = 0x0
618 FLAGS = (REAL)
619 Elt No. 0
620 SV = IV(0x7467c8) at 0x7c1aa0
621 REFCNT = 1
622 FLAGS = (IOK,pIOK)
623 IV = 5
624 Elt No. 1
625 SV = IV(0x7467b0) at 0x8440f0
626 REFCNT = 1
627 FLAGS = (IOK,pIOK)
628 IV = 6
629 Elt No. 2
630 SV = IV(0x746810) at 0x75be00
631 REFCNT = 1
632 FLAGS = (IOK,pIOK)
633 IV = 7
634 Elt No. 3
635 SV = IV(0x746d38) at 0x7799d0
636 REFCNT = 1
637 FLAGS = (IOK,pIOK)
638 IV = 8
639 Elt "3" HASH = 0xa400c7f3
640 SV = IV(0x746fd0) at 0x7200e0
641 REFCNT = 1
642 FLAGS = (IOK,pIOK)
643 IV = 4
645 =head1 INTERNALS
647 C<DDump ()> uses an XS wrapper around C<Perl_sv_dump ()> where the
648 STDERR is temporarily caught to a pipe. The internal XS helper functions
649 are not meant for user space
651 =head2 DDump_XS (SV *sv)
653 Base interface to internals for C<DDump ()>.
655 =head1 BUGS
657 Windows and AIX might be using a build where not all symbols that were
658 supposed to be exported in the public API are not. Perl_pv_peek () is
659 one of them.
661 Not all types of references are supported.
663 No idea how far back this goes in perl support, but Devel::PPPort has
664 proven to be a big help.
666 =head1 SEE ALSO
668 L<Devel::Peek>, L<Data::Dumper>, L<Data::Dump>, L<Devel::Dumpvar>,
669 L<Data::Dump::Streamer>, L<Data::Dumper::Perltidy>, L<Perl::Tidy>.
671 =head1 AUTHOR
673 H.Merijn Brand <h.m.brand@xs4all.nl>
675 =head1 COPYRIGHT AND LICENSE
677 Copyright (C) 2008-2011 H.Merijn Brand
679 This library is free software; you can redistribute it and/or modify
680 it under the same terms as Perl itself.
682 =cut