package Tracer;

use strict;
use vars qw($AUTOLOAD @EXPORT @ISA);

@ISA = qw(Exporter);
@EXPORT = qw(trace untrace);

# note: these assume that converting a reference to a number yields the
# address, it is possible to override this default behaviour (with Overload?)

my %real_class;

sub trace {
	for (@_) {
		$real_class{0+$_} = ref $_;
		bless $_, 'Tracer';
	}
}

sub untrace {
	for (@_) {
		bless $_, $real_class{0+$_};
		delete $real_class{0+$_};
	}
}

sub AUTOLOAD {
	my ($self, @args) = @_;
	local $| = 1;
	
        use Data::Dumper;
        local $Data::Dumper::Terse = 1;
        local $Data::Dumper::Indent = 0;

	my $printable_args = Dumper \@args;
        $printable_args = substr $printable_args, 1, -1; # lose [, ]

	my $method = $AUTOLOAD;
	$method =~ s/^Tracer:://; # a bit dodgy

	my $real_class = $real_class{0+$self};
	my $real_method = $real_class . "::$method";

	bless $self, $real_class;

	print STDERR "$self->$real_method($printable_args)";
	print $method eq "DESTROY" ?
		"\n" :
		" = ";
	
	# todo: catch dies?

	my @return = wantarray ?
		($self->$method(@args)) :
		(scalar($self->$real_method(@args)));

	print STDERR join ', ', @return; # todo - cope with undef; should use Dumper or not consistently
	print STDERR "\n";

	bless $self, 'Tracer';

	return wantarray ? @return : $return[0];
}

1
