File Coverage

blib/lib/Data/Inspect.pm
Criterion Covered Total %
statement 86 96 89.5
branch 22 30 73.3
condition 13 21 61.9
subroutine 17 19 89.4
pod 6 6 100.0
total 144 172 83.7


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Data::Inspect - human-readable object representations
4              
5             =head1 SYNOPSIS
6              
7             use Data::Inspect;
8             my $insp = Data::Inspect->new;
9             $insp->p($object);
10              
11             use Data::Inspect qw(p);
12             p $object;
13              
14             =head1 DESCRIPTION
15              
16             Data::Inspect provides a human-readable representation of any Perl
17             scalar. Classes can be extended with user-defined inspect methods. It
18             is heavily inspired by Ruby's C

method and inspect functionality.

19              
20             The purpose of this module is to provide debugging/logging code with a
21             more readable representation of data structures than the extremely
22             literal form output by Data::Dumper.
23              
24             It is especially useful in an object-oriented system, since each class
25             can define its own C method, indicating how that particular
26             object should be displayed.
27              
28             The L

method inspects its arguments and outputs them to the default
29             filehandle. It can be exported to your package's namespace, in which
30             case it will silently create the Inspect object with the default
31             options, if this sort of brevity is desired.
32              
33             =cut
34              
35             package Data::Inspect;
36              
37             our $VERSION = '0.04';
38              
39 1     1   23356 use strict;
  1         2  
  1         29  
40 1     1   4 use warnings;
  1         2  
  1         21  
41              
42 1     1   926 use Data::Dumper ();
  1         9367  
  1         28  
43 1     1   9 use Scalar::Util ();
  1         1  
  1         21  
44              
45 1     1   6 use base 'Exporter';
  1         2  
  1         1523  
46             our @EXPORT_OK = qw(p pe pf);
47              
48             =head1 PUBLIC METHODS
49              
50             =over 4
51              
52             =item new
53              
54             my $insp = Data::Inspect->new;
55              
56             Create a new Data::Inspect object.
57              
58             =cut
59              
60             sub new {
61 2     2 1 15 my ($class) = @_;
62 2         6 my $self = bless {}, $class;
63              
64             # Initialize values
65 2         11 $self->{tracker} = {};
66 2         7 $self->{options}{truncate_strings} = undef;
67              
68 2         6 return $self;
69             }
70              
71             =item p
72              
73             $insp->p($var1, $var2);
74              
75             use Data::Inspect qw(p);
76             p $var1, $var2;
77              
78             Inspects each of the provided arguments and outputs the result to the
79             default filehandle (usually STDOUT).
80              
81             C

can be exported to the current namespace if you don't want to

82             create a Data::Inspect object to do your inspecting for you.
83              
84             =cut
85              
86             sub p {
87 4 100   4 1 3477 my $self = UNIVERSAL::isa($_[0], __PACKAGE__) ? shift : __PACKAGE__->new;
88 4         14 print $self->inspect($_)."\n" for @_;
89             }
90              
91             =item pe
92              
93             $insp->pe($var1, $var2);
94              
95             Exactly like L

but outputs to STDERR instead of the default
96             filehandle.
97              
98             =cut
99              
100             sub pe {
101 0 0   0 1 0 my $self = UNIVERSAL::isa($_[0], __PACKAGE__) ? shift : __PACKAGE__->new;
102 0         0 print STDERR $self->inspect($_)."\n" for @_;
103             }
104              
105             =item pf
106              
107             $insp->pf($somefh, $var1, $var2);
108              
109             Like L

and L but outputs to the filehandle specified in the
110             first argument.
111              
112             Note that the filehandle must be a reference. If you want to use a
113             filehandle that isn't a reference, you can create one using the
114             L::qualify_to_ref function.
115              
116             =cut
117              
118             sub pf {
119             # Create a new $self if this is called in the non-OO manner.
120 0 0   0 1 0 my $self = UNIVERSAL::isa($_[0], __PACKAGE__) ? shift : __PACKAGE__->new;
121 0         0 my $fh = shift;
122 0         0 print $fh $self->inspect($_)."\n" for @_;
123             }
124              
125             =item inspect
126              
127             my $value = $insp->inspect($var);
128              
129             Inspects the given scalar value and returns the result.
130              
131             =cut
132              
133             sub inspect {
134 68     68 1 946 my ($self, $val) = @_;
135              
136             # If no $val is provided or $val is $self, someone is probably
137             # trying to inspect this object!
138 68 100 100     354 if (@_ < 2 or (ref $val and
      33        
139             Scalar::Util::refaddr($val) == Scalar::Util::refaddr($self))) {
140 1         7 return "#";
141             }
142              
143             # If it's a reference, we delegate it to _inspect_reference
144 67 100       123 if (ref $val) {
145 18         42 return $self->_inspect_reference($val);
146             }
147              
148             # Otherwise, delegate to _inspect_non_reference
149             else {
150 49         98 return $self->_inspect_non_reference($val);
151             }
152             }
153              
154             =item set_option
155              
156             $insp->set_option('truncate_strings', 30);
157              
158             Set the given option to the given value. Options alter the output of
159             Inspect.
160              
161             Available options are:
162              
163             =over
164              
165             =item truncate_strings
166              
167             If set to a positive integer, truncates strings after that number of
168             characters, replacing the end with '...'.
169              
170             default: undef
171              
172             =item sort_keys
173              
174             If set to the string 'cmp' or '<=>', hashes will have their keys
175             sorted using the specified comparison before being output.
176              
177             default: undef
178              
179             =back
180              
181             =cut
182              
183             sub set_option {
184 2     2 1 438 my ($self, $option, $value) = @_;
185 2 50       5 if (not grep {$_ eq $option} qw/truncate_strings sort_keys/) {
  4         16  
186 0         0 warn "Inspect: option '$option' is not a valid option";
187 0         0 return;
188             }
189 2         7 $self->{options}{$option} = $value;
190             }
191              
192             =back
193              
194             =cut
195              
196             # Aux method for inspecting non-references. Mostly the grunt work here
197             # is done by Data::Dumper.
198             sub _inspect_non_reference {
199 49     49   63 my ($self, $val) = @_;
200              
201             # Data::Dumper is good at inspecting non-references. If they're
202             # strings, it sorts out all the escaping.
203 49         247 my $dumper = Data::Dumper->new([$val]);
204 49         1350 $dumper->Useqq(1); # Use double quotes so we get nice things like \n
205 49         284 $dumper->Terse(1); # Just the data, please. No $VAR1!
206 49         250 chomp(my $dump = $dumper->Dump);
207              
208             # If we're truncating strings, do it here
209 49 100 100     1045 if ($self->{options}{truncate_strings} and
      66        
210             length $dump > $self->{options}{truncate_strings}+2
211             and $dump =~ /^"/) {
212 1         5 $dump = substr($dump, 0, $self->{options}{truncate_strings}+1).'..."';
213             }
214              
215 49         391 return $dump;
216             }
217              
218             # Aux method for inspecting references. This is the bit we have to do
219             # ourselves because Data::Dumper is just too literal.
220             #
221             # The second argument, reftype, is taken to be the reftype instead of
222             # the autodetected one.
223             sub _inspect_reference {
224 21     21   38 my ($self, $val, $reftype) = @_;
225              
226             # Avoid circular references by keeping track of the references we're
227             # currently inspecting. We have to ignore this check if $reftype is
228             # set because we are technically re-evaluating the same old thing.
229 21         38 my $refaddr = Scalar::Util::refaddr($val);
230 21 100 100     103 if (not $reftype and exists $self->{tracker}{$refaddr}) {
231 1         9 return sprintf "#", $refaddr;
232             }
233 20         55 local $self->{tracker}{$refaddr} = 1;
234              
235             # Set $reftype to 'HASH', 'ARRAY', 'object' etc.
236 20 100       40 if (not $reftype) {
237 17 100       43 if (Scalar::Util::blessed($val)) {
238 5         28 $reftype = 'object';
239             }
240             else {
241 12         24 $reftype = ref $val;
242             }
243             }
244              
245             # If we have a method for inspecting this reftype, call it
246 20         37 my $method = "_inspect_$reftype";
247 20 100       78 if ($self->can($method)) {
248 19         49 $self->$method($val);
249             }
250             # Otherwise, we call the _inspect_other with $val and $reftype
251             else {
252 1         4 $self->_inspect_other($val, $reftype);
253             }
254             }
255              
256             # Inspect an object. If the object defines an inspect() method this is
257             # easy. If it doesn't, we just return the class and the underlying
258             # reference inspected.
259             sub _inspect_object {
260 5     5   9 my ($self, $val) = @_;
261             # Object's class defines an 'inspect'
262 5 100       64 if ($val->can('inspect')) {
263 2         8 return $val->inspect($self);
264             }
265             # Otherwise return the object's class name followed by an inspection
266             # of the underlying representation.
267             else {
268 3         8 my $class = Scalar::Util::blessed($val);
269 3         18 my $inspected =
270             $self->_inspect_reference($val, Scalar::Util::reftype($val));
271 3         36 return "#<$class $inspected>";
272             }
273             }
274              
275             # Inspect a scalar reference. Well, this is just the same as
276             # inspecting the scalar it references but with a \ in front.
277             sub _inspect_SCALAR {
278 1     1   3 my ($self, $val) = @_;
279 1         4 return q{\\}.$self->inspect($$val);
280             }
281              
282             # Inspect a hash reference. This is a lot like Data::Dumper except we
283             # inspect all the keys and values and provide it in a nice one-line
284             # format.
285             sub _inspect_HASH {
286 7     7   11 my ($self, $val) = @_;
287              
288             # Do the keys need sorting?
289 7         9 my @keys;
290 7 50 33     38 if ($self->{options}{sort_keys} and $self->{options}{sort_keys} eq 'cmp') {
    0 0        
291 7         42 @keys = sort keys %$val;
292             }
293             elsif ($self->{options}{sort_keys} and $self->{options}{sort_keys} eq '<=>') {
294 0         0 @keys = sort {$a<=>$b} keys %$val;
  0         0  
295             }
296             else {
297 0         0 @keys = keys %$val;
298             }
299              
300 7         13 my $ostr = '{';
301 7         12 my @vals = map { $self->inspect($_).' => '.$self->inspect($val->{$_}) } @keys;
  12         26  
302 7         20 $ostr .= join ', ', @vals;
303 7         55 return "$ostr}";
304             }
305              
306             # Inspect an array reference.
307             sub _inspect_ARRAY {
308 5     5   7 my ($self, $val) = @_;
309 5         9 my $ostr = '[';
310 5         9 my @vals = map { $self->inspect($_) } @$val;
  20         45  
311 5         16 $ostr .= join ', ', @vals;
312 5         54 return "$ostr]";
313             }
314              
315             # Inspect a glob reference.
316             sub _inspect_GLOB {
317 1     1   2 my ($self, $val) = @_;
318 1         2 my $ostr = '#
319 1         4 foreach (qw/NAME SCALAR ARRAY HASH CODE IO GLOB FORMAT PACKAGE/) {
320 9 100       10 if (defined *{$val}{$_}) {
  9         33  
321 6         9 $ostr .= " $_=".$self->inspect(*{$val}{$_});
  6         18  
322             }
323             }
324 1         5 return "$ostr>";
325             }
326              
327             # Inspect anything else. This takes a second argument, which is the
328             # type of reference we're inspecting.
329             sub _inspect_other {
330 1     1   2 my ($self, $val, $reftype) = @_;
331 1         6 return "#<$reftype>";
332             }
333              
334             =head1 EXAMPLES
335              
336             =head2 Inspecting built-in Perl types
337              
338             In this example, we use the L

method to output the inspected contents
339             of a Perl hash:
340              
341             use Data::Inspect qw(p);
342             p \%some_hash;
343              
344             The output is something like:
345              
346             {"baz" => "qux\n\n", "foo" => "bar"}
347              
348             =head2 Changing how an object looks
349              
350             In this example, objects of class C are blessed hashrefs
351             containing a lot of data. They are uniquely identifiable by one key,
352             C; so we create an inspect method that just displays that C:
353              
354             package Wibble;
355            
356             sub inspect {
357             my ($self, $insp) = @_;
358             "#{id}>";
359             }
360              
361             If we have a hash full of Wibbles we can now see its contents easily
362             by inspecting it:
363              
364             use Data::Inspect qw(p);
365             p \%hash_of_wibbles;
366              
367             The output will be something like:
368              
369             {"bar" => #, "baz" => #, "foo" => #}
370              
371             =head2 Recursive inspecting
372              
373             $_[1] is set to the current Data::Inspect object in calls to an
374             object's C method. This allows you to recursively inspect
375             data structures contained within the object, such as hashes:
376              
377             package Wibble;
378              
379             sub inspect {
380             my ($self, $insp) = @_;
381             "#{id} data=".$insp->inspect($self->{data}).">";
382             }
383              
384             =head2 Using Data::Inspect in the OO form
385              
386             The OO form provides a greater degree of flexibility than just
387             importing the L

method. The behaviour of Data::Inspect can be
388             modified using the L method and there is also an
389             L method that returns the inspected form rather than
390             outputting it.
391              
392             use Data::Inspect;
393             my $insp = Data::Inspect->new;
394            
395             # Strings are truncated if they are more than 10 characters long
396             $insp->set_option('truncate_strings', 10);
397            
398             $insp->p("Supercalifragilisticexpialidocious");
399              
400             Outputs:
401              
402             "Supercalif..."
403              
404             =head1 SEE ALSO
405              
406             L
407              
408             The Ruby documentation for C and C at
409             http://www.ruby-doc.org/core/
410              
411             =head1 CHANGES
412              
413             - 0.04 Fixed test case 7 to work with Perl 5.11.5
414              
415             - 0.03 Fixed documentation and tests further.
416              
417             - 0.02 Added support and documentation for recursive inspecting.
418             Fixed tests on versions of perl built without useperlio.
419              
420             - 0.01 Initial revision
421              
422             =head1 AUTHOR
423              
424             Rich Daley
425              
426             =head1 COPYRIGHT
427              
428             Copyright (c) 2009 Rich Daley. All rights reserved.
429              
430             This library is free software; you can redistribute it and/or modify
431             it under the same terms as Perl itself.
432              
433             =cut
434              
435             1;