1 package Data::Dump::Trace;
7 # in/out parameters key/value style
10 # - configurable colors
11 # - show call depth using indentation
12 # - show nested calls sensibly
18 our @EXPORT_OK = qw(call mcall wrap autowrap trace);
31 $info = { prefix => $info } unless ref($info);
32 for ($info->{prefix}) {
37 $_ = '$' . $_ unless /^\$/;
39 $autowrap_class{$class} = $info;
45 my $name = $arg{name} || "func";
46 my $func = $arg{func};
47 my $proto = $arg{proto};
50 call($name, $func, $proto, @_);
53 if (my $obj = $arg{obj}) {
54 $name = '$' . $name unless $name =~ /^\$/;
55 $obj_name{overload::StrVal($obj)} = $name;
60 }, "Data::Dump::Trace::Wrapper";
63 croak("Either the 'func' or 'obj' option must be given");
67 my($symbol, $prototype) = @_;
69 no warnings 'redefine';
70 *{$symbol} = wrap(name => $symbol, func => \&{$symbol}, proto => $prototype);
77 my $fmt = Data::Dump::Trace::Call->new($name, $proto, \@_);
78 if (!defined wantarray) {
80 return $fmt->return_void(\@_);
83 return $fmt->return_list(\@_, $func->(@_));
86 return $fmt->return_scalar(\@_, scalar $func->(@_));
94 return if $method eq "DESTROY" && !$o->can("DESTROY");
95 my $oname = ref($o) ? $obj_name{overload::StrVal($o)} || "\$o" : $o;
96 my $fmt = Data::Dump::Trace::Call->new("$oname->$method", $proto, \@_);
97 if (!defined wantarray) {
99 return $fmt->return_void(\@_);
102 return $fmt->return_list(\@_, $o->$method(@_));
105 return $fmt->return_scalar(\@_, scalar $o->$method(@_));
109 package Data::Dump::Trace::Wrapper;
114 my $method = substr($AUTOLOAD, rindex($AUTOLOAD, '::')+2);
115 Data::Dump::Trace::mcall($self->{obj}, $method, $self->{proto}{$method}, @_);
118 package Data::Dump::Trace::Call;
120 use Term::ANSIColor ();
123 *_dump = \&Data::Dump::dump;
132 %COLOR = () unless -t STDOUT;
135 return "(" . _dump(@_) . ")" if @_ == 1;
140 return _dumpav(@_) if @_ % 2;
142 my $str = _dump(\%h);
143 $str =~ s/^\{/(/ && $str =~ s/\}\z/)/;
148 my($class, $name, $proto, $input_args) = @_;
153 my $proto_arg = $self->proto_arg;
154 if ($proto_arg =~ /o/) {
156 push(@{$self->{input_av}}, _dump($_));
160 $self->{input} = $proto_arg eq "%" ? _dumpkv(@$input_args) : _dumpav(@$input_args);
167 my($arg, $ret) = split(/\s*=\s*/, $self->{proto} || "");
174 my($arg, $ret) = split(/\s*=\s*/, $self->{proto} || "");
180 my($self, $category, $text) = @_;
181 return $text unless $COLOR{$category};
182 return Term::ANSIColor::colored($text, $COLOR{$category});
188 print $self->color("name", "$self->{name}");
189 if (my $input = $self->{input}) {
190 $input = "" if $input eq "()" && $self->{name} =~ /->/;
191 print $self->color("input", $input);
194 my $proto_arg = $self->proto_arg;
197 for (@{$self->{input_av}}) {
199 my $proto = substr($proto_arg, 0, 1, "");
201 print $self->color("input", $_);
203 if ($proto eq "o" || $proto eq "O") {
204 print " = " if $proto eq "O";
205 print $self->color("output", _dump($outarg->[$i]));
218 $self->print_call($arg);
226 $self->print_call($arg);
229 my $proto_ret = $self->proto_ret;
230 my $wrap = $autowrap_class{ref($s)};
231 if ($proto_ret =~ /^\$\w+\z/ && ref($s) && ref($s) !~ /^(?:ARRAY|HASH|CODE|GLOB)\z/) {
235 $name = $wrap->{prefix} if $wrap;
238 $name .= $name_count{$name} if $name_count{$name}++;
239 print " = ", $self->color("output", $name), "\n";
240 $s = Data::Dump::Trace::wrap(name => $name, obj => $s, proto => $wrap->{proto});
243 print " = ", $self->color("output", _dump($s));
244 if (!$s && $proto_ret =~ /!/ && $!) {
245 print " ", $self->color("error", errno($!));
255 $self->print_call($arg);
256 print " = ", $self->color("output", $self->proto_ret eq "%" ? _dumpkv(@_) : _dumpav(@_)), "\n";
278 Data::Dump::Trace - Helpers to trace function and method calls
282 use Data::Dump::Trace qw(autowrap mcall);
284 autowrap("LWP::UserAgent" => "ua", "HTTP::Response" => "res");
287 $ua = mcall(LWP::UserAgent => "new"); # instead of LWP::UserAgent->new;
288 $ua->get("http://www.example.com")->dump;
292 The following functions are provided:
296 =item autowrap( $class )
298 =item autowrap( $class => $prefix )
300 =item autowrap( $class1 => $prefix1, $class2 => $prefix2, ... )
302 =item autowrap( $class1 => \%info1, $class2 => \%info2, ... )
304 Register classes whose objects are are automatically wrapped when
305 returned by one of the call functions below. If $prefix is provided
306 it will be used as to name the objects.
308 Alternative is to pass an %info hash for each class. The recognized keys are:
312 =item prefix => $string
314 The prefix string used to name objects of this type.
316 =item proto => \%hash
318 A hash of prototypes to use for the methods when an object is wrapped.
322 =item wrap( name => $str, func => \&func, proto => $proto )
324 =item wrap( name => $str, obj => $obj, proto => \%hash )
326 Returns a wrapped function or object. When a wrapped function is
327 invoked then a trace is printed after the underlying function has returned.
328 When a method on a wrapped object is invoked then a trace is printed
329 after the methods on the underlying objects has returned.
331 See L</"Prototypes"> for description of the C<proto> argument.
333 =item call( $name, \&func, $proto, @ARGS )
335 Calls the given function with the given arguments. The trace will use
336 $name as the name of the function.
338 See L</"Prototypes"> for description of the $proto argument.
340 =item mcall( $class, $method, $proto, @ARGS )
342 =item mcall( $object, $method, $proto, @ARGS )
344 Calls the given method with the given arguments.
346 See L</"Prototypes"> for description of the $proto argument.
348 =item trace( $symbol, $prototype )
350 Replaces the function given by $symbol with a wrapped function.
356 B<Note: The prototype string syntax described here is experimental and
357 likely to change in revisions of this interface>.
359 The $proto argument to call() and mcall() can optionally provide a
360 prototype for the function call. This give the tracer hints about how
361 to best format the argument lists and if there are I<in/out> or I<out>
362 arguments. The general form for the prototype string is:
364 <arguments> = <return_value>
366 The default prototype is "@ = @"; list of values as input and list of
369 The value '%' can be used for both arguments and return value to say
370 that key/value pair style lists are used.
372 Alternatively, individual positional arguments can be listed each
373 represented by a letter:
387 both input and output argument
391 If the return value prototype has C<!> appended, then it signals that
392 this function sets errno ($!) when it returns a false value. The
393 trace will display the current value of errno in that case.
395 If the return value prototype looks like a variable name (with C<$>
396 prefix), and the function returns a blessed object, then the variable
397 name will be used as prefix and the returned object automatically
406 Copyright 2009 Gisle Aas.
408 This library is free software; you can redistribute it and/or
409 modify it under the same terms as Perl itself.