UNIVERSAL::dump - add dump methods to all classes and objects


UNIVERSAL-dump documentation Contained in the UNIVERSAL-dump distribution.

Index


Code Index:

NAME

Top

UNIVERSAL::dump - add dump methods to all classes and objects

SYNOPSIS

Top

  use UNIVERSAL::dump; # implicit 'dump'

 or:

  use UNIVERSAL::dump qw(dump peek); # create both "dump" and "peek"

 or:

  use UNIVERSAL::dump ( { _dump => 'dump' } ); # dump using "_dump"

 or:

  use UNIVERSAL::dump ( { bar => 'Bar::Dumper' } ); # "foo" dumper

 my $foo = Foo->new;
 print $foo->dump;         # send dump of $foo to STDOUT
 print $foo->dump( $bar ); # send dump of $bar to STDOUT

 $foo->dump;         # send dump of $foo to STDERR
 $foo->dump( $bar ); # send dump of $bar to STDERR

DESCRIPTION

Top

Loading the UNIVERSAL::dump module adds one or more methods to all classes and methods. It is intended as a debugging aid, alleviating the need to add and remove debugging code from modules and programs.

By default, it adds a method "dump" to all classes and objects. This method either dumps the object, or any parameters specified, using Data::Dumper.

As an extra feature, the output is sent to STDERR whenever the method is called in a void context. This makes it easier to dump variable structures while debugging modules and programs.

The name of the method can be specified by parameters when loading the module. These are the method names that are currently recognized:

blessed

Return or prints with which class the object (or any value) is blessed. Uses Scalar::Util's "blessed" subroutine.

dump

Return or prints a representation of the object (or any value that is specified). Uses Data::Dumper's "Dumper" subroutine.

peek

Return or prints the internal representation of the object (or any value that is specified). Uses Devel::Peek's "Dump" subroutine.

refaddr

Return or prints with the memory address of the object (or any value specified). Uses Scalar::Util's "refaddr" subroutine.

If you cannot use one of the preset names of methods, you can specify a reference to a hash instead, in which the key is the new name of the method and the value is the name with which the dumping method is normally indicated.

If you have a dumping subroutine that is not available by default, you can add your own by specifying a reference to a hash, in which the key is the method name, and the value is the (fully qualified) name of the subroutine.

To prevent different modules fighting over the same method name, a check has been built in which will cause an exception when the same method is attempted with a different subroutine name.

WHY?

Top

One day, I finally had enough of always putting a "dump" and "peek" method in my modules. I came across UNIVERSAL::moniker one day, and realized that I could do something similar for my "dump" methods.

REQUIRED MODULES

Top

 Data::Dumper (any)

CAVEATS

Top

AUTOLOADing methods

Any method called "dump" (or whichever class or object methods you activate with this module) will not be AUTOLOADed because they are already found in the UNIVERSAL package..

AUTHOR

Top

Elizabeth Mattijsen, <liz@dijkmat.nl>.

Please report bugs to <perlbugs@dijkmat.nl>.

COPYRIGHT

Top


UNIVERSAL-dump documentation Contained in the UNIVERSAL-dump distribution.

package UNIVERSAL::dump;

# Make sure we have version info for this module
# Be strict from now on

$VERSION = '0.04';
use strict;

# Initialize the hash with presets

my %preset = (
 blessed => 'Scalar::Util::blessed',
 dump    => 'Data::Dumper::Dumper',
 peek    => 'Devel::Peek::Dump',
 refaddr => 'Scalar::Util::refaddr',
);

# Hash with installed handlers

my %installed;

# Satisfy require

1;

#---------------------------------------------------------------------------

# Perl specific subroutines

#---------------------------------------------------------------------------
#  IN: 1 class (ignored)
#      2..N method => subroutine pairs

sub import {

# Obtain the class (ignored for now)
# Set default method if nothing specified

    my $class = shift;
    unshift( @_,'dump' ) unless @_;

# Allow for redefining subroutines
# For all of the parameters to be handled
#  If we got a preset
#   Die now if we don't know how to handle the preset
#   Handle the preset by calling ourselves
#   And reloop

    no warnings 'redefine';
    foreach (@_) {
        unless (ref) {
            die qq{Don't know how to install method "UNIVERSAL::$_"\n}
             unless my $sub = $preset{$_};
            $class->import( {$_ => $sub} );
            next;
        }

#  For all the method / subroutine pairs
#   Normalize if another method name was specified
#   If there is already a method installed with that name
#    Croak if we're trying to install a different one

        while (my ($method,$sub) = each %{$_}) {
            $sub = $preset{$sub} if $preset{$sub};
            if (my $installed = $installed{$method}) {
                die qq{Cannot install "UNIVERSAL::$method" with "$sub": already installed with "$installed"\n} if $sub ne $installed;
            }

#   Fetch the module name from it
#   Turn it into something that can be used in a -require-
#   Mark this method as installed

            (my $module = $sub) =~ s#::[^:]+$##;
            $module =~ s#::#/#; $module .= ".pm";
            $installed{$method} = $sub;

#   Allow for variable references to subroutines
#   Create a method which
#    Obtains the object / class
#    Makes sure that we have the right module (even if it doesn't really exists)
#    Return dumper output if not in void context
#    Send dumper output to STDERR otherwise

            no strict 'refs';
            *{"UNIVERSAL::$method"} = sub {
                my $self = shift;
                eval { require $module };
                return $sub->( @_ ? @_ : $self ) if defined wantarray;
                print STDERR $sub->( @_ ? @_ : $self );
            } #$method
        }
    }
} #import

#---------------------------------------------------------------------------

__END__