| Current File : //var/wcp4/demo1812/public_html/file/file/private/lib/GT/Dumper.pm |
# ==================================================================
# Gossamer Threads Module Library - http://gossamer-threads.com/
#
# GT::Dumper
# Author : Scott Beck
# $Id: Dumper.pm,v 1.30 2002/04/05 02:45:13 jagerman Exp $
#
# Copyright (c) 2001 Gossamer Threads Inc. All Rights Reserved.
# ==================================================================
#
# Description:
# Implements a simple data dumper, useful for converting complex
# data structures to strings.
#
package GT::Dumper;
# ===============================================================
use strict;
use vars qw /$DEBUG $ATTRIBS $VERSION @EXPORT @ISA $TAB $EOL/;
use GT::Base;
use Exporter;
$TAB = ' ';
$EOL = "\n";
$VERSION = sprintf "%d.%03d", q$Revision: 1.30 $ =~ /(\d+)\.(\d+)/;
$ATTRIBS = {
var => undef,
data => undef,
sort => undef,
order => undef,
compress => undef,
structure => undef
};
@EXPORT = qw(Dumper);
@ISA = qw(Exporter GT::Base);
sub Dumper {
# -----------------------------------------------------------
# Dumper acts similar to Dumper in Data::Dumper when called as a
# class method. If called as a instance method it assumes you
# have set the options for the dump and does not change them.
# It only takes a single argument - the variable to dump.
#
my $self;
if (@_ == 1) {
if (ref $_[0] eq 'GT::Dumper') {
$self = shift;
}
else {
$self = GT::Dumper->new (
var => '$VAR',
data => shift
);
}
}
elsif (@_ == 2) {
if ($_[0] eq 'GT::Dumper') {
$self = GT::Dumper->new (
var => '$VAR',
data => $_[1]
);
}
else {
$self = shift;
$self->{data} = shift;
$self->{var} ||= '$VAR';
}
}
else {
die "Bad args to Dumper";
}
return $self->dump;
}
sub dump {
# -----------------------------------------------------------
# my $dump = $class->dump (%opts);
# --------------------------------
# Returns the data structure specified in %opts flatened.
# %opts is optional if you have created an object with the
# options.
#
my $this = shift;
# See if options were passed in
my $self;
if (!ref $this) {
$self = $this->new (@_);
}
elsif (@_ > 0) {
$self = $this;
$self->init (@_);
}
else {
$self = $this;
}
my $level = 0;
my $ret;
$ret .= "$self->{var} = " unless defined $self->{var} and $self->{var} eq '';
$self->_dump_value ($level + 1, $self->{data}, \$ret);
$ret .= ';'.$EOL unless $self->{structure};
return $ret ? $ret : 1;
}
sub dump_structure {
my ($self, $data) = @_;
return $self->dump(var => '', structure => 1, data => $data);
}
sub _dump_value {
# -----------------------------------------------------------
# Internal method to decide what to dump.
#
my ($self, $level, $val, $ret, $n) = @_;
my $was;
if (ref $val and $val =~ /=/) { $self->_dump_obj ($level + 1, $val, $ret) }
elsif (ref $val eq 'HASH') { $self->_dump_hash ($level + 1, $val, $ret) }
elsif (ref $val eq 'ARRAY') { $self->_dump_array ($level + 1, $val, $ret) }
elsif (ref $val eq 'SCALAR' or ref $val eq 'REF'
or ref $val eq 'LVALUE') { $self->_dump_scalar ($level + 1, $val, $ret) }
else {
$val = _escape ($val);
$$ret .= $val;
}
return 1;
}
sub _dump_scalar {
# -----------------------------------------------------------
# Dump a scalar reference.
#
my ($self, $level, $val, $ret, $n) = @_;
my $v = $$val;
$$ret .= '\\';
$self->_dump_value($level + 1, $v, $ret, 1);
return 1;
}
sub _dump_hash {
# -----------------------------------------------------------
# Internal method to for through a hash and dump it.
#
my ($self, $level, $hash_ref, $ret) = @_;
$$ret .= '{';
my $lines;
if ($self->{sort}) {
for (sort { ref ($self->{order}) eq 'CODE' ? $self->{order}->($a, $b, $hash_ref->{$a}, $hash_ref->{$b}) : $a cmp $b } keys %{$hash_ref}) {
$$ret .= "," if $lines++;
$$ret .= $EOL.($TAB x ($level / 2)) unless $self->{compress};
my $key = _escape($_);
$$ret .= $self->{compress} ? "$key," : "$key => ";
$self->_dump_value ($level + 1, $hash_ref->{$_}, $ret, 1);
}
}
else {
for (keys %{$hash_ref}) {
$$ret .= "," if $lines++;
$$ret .= $EOL.($TAB x ($level / 2)) unless $self->{compress};
my $key = _escape($_);
$$ret .= $self->{compress} ? "$key," : "$key => ";
$self->_dump_value ($level + 1, $hash_ref->{$_}, $ret, 1);
}
}
$$ret .= $EOL if $lines and not $self->{compress};
$$ret .= ($lines and not $self->{compress}) ? (($TAB x (($level - 1) / 2)) . "}") : "}";
return 1;
}
sub _dump_array {
# -----------------------------------------------------------
# Internal method to for through an array and dump it.
#
my ($self, $level, $array_ref, $ret) = @_;
$$ret .= "[";
my $lines;
for (@{$array_ref}) {
$$ret .= "," if $lines++;
$$ret .= $EOL.($TAB x ($level / 2)) unless $self->{compress};
$self->_dump_value ($level + 1, $_, $ret, 1);
}
$$ret .= ($lines and not $self->{compress}) ? $EOL.(($TAB x (($level - 1) / 2)) . "]") : "]";
return 1;
}
sub _dump_obj {
# -----------------------------------------------------------
# Internal method to dump an object.
#
my ($self, $level, $obj, $ret) = @_;
my $class = ref $obj;
$$ret .= "bless(";
$$ret .= $EOL.($TAB x ($level / 2)) unless $self->{compress};
if ($obj =~ /ARRAY\(/) { $self->_dump_array ($level + 2, \@{$obj}, $ret) }
elsif ($obj =~ /HASH\(/) { $self->_dump_hash ($level + 2, \%{$obj}, $ret) }
elsif ($obj =~ /SCALAR\(/ or $obj =~ /REF\(/ or $obj =~ /LVALUE\(/)
{ $self->_dump_value ($level + 2, $$obj, $ret) }
$$ret .= ",";
$$ret .= $EOL.($TAB x ($level / 2)) unless $self->{compress};
$$ret .= _escape($class);
$$ret .= $EOL.($TAB x (($level - 1) / 2)) unless $self->{compress};
$$ret .= ")";
return 1;
}
sub _escape {
# -----------------------------------------------------------
# Internal method to escape a dumped value.
my ($val) = @_;
defined ($val) or return 'undef';
$val =~ s/('|\\(?=['\\]|$))/\\$1/g;
return "'$val'";
}
1;
__END__
=head1 NAME
GT::Dumper - Implements a simple data dumper.
=head1 SYNOPSIS
use GT::Dumper;
print Dumper($complex_var);
print GT::Dumper->dump ( var => '$MYVAR', data => $complex_var);
=head1 DESCRIPTION
GT::Dumper by default exports a method Dumper() which will
behave similar to Data::Dumper's Dumper(). It differs in that
it will only take a single argument, and the variable dumped
will be $VAR instead of $VAR1. Also, to provide easier control
to change the variable name that gets dumped, you can use:
GT::Dumper->dump ( var => string, data => yourdata );
and the dump will start with string = instead of $VAR = .
=head1 EXAMPLE
use GT::Dumper;
my %foo;
my @bar = (1, 2, 3);
$foo{alpha} = \@bar;
$foo{beta} = 'a string';
print Dumper(\%foo);
This will print:
$VAR = {
'beta' => 'a string',
'alpha' => [
'1',
'2',
'3',
],
};
You may specify a blank variable name ('') and the variable
and = sign will be omitted from the output.
The "compress" option can be used to eliminate all whitespace.
=head1 COPYRIGHT
Copyright (c) 2001 Gossamer Threads Inc. All Rights Reserved.
http://www.gossamer-threads.com/
=head1 VERSION
Revision: $Id: Dumper.pm,v 1.30 2002/04/05 02:45:13 jagerman Exp $
=cut