First, I'd like to offer my thanks to diotalevi for throwing all sorts of ideas at me early on (which prodded me to continue work on it), bart for giving me last minute feedback (which I haven't forgetten) and anyone else that I may be forgetting.

Data::Dumper::Lite was conceived as a "toy module" to help me grasp the different types of data structures (and references) and how best to get at the data inside of them. I am unhappy with the way that Data::Dumper dumps a subroutine as sub { "DUMMY" } so I added in some extra functionality using B::Deparse. I would also like to eventually be able to view referenced lvalues (i.e. I'd like my $lref = \substr("abc",1,1);print $dumper->Dump($lref); to print substr("abc",1,1) instead of 'b'.)

The documentation is nonexistant at this point since the guts of the module are still being hashed out. </bad pun>

Usage is extremely simple. Create a new instance and then pass a data structure reference to the Dump method of that instance.

#!/usr/bin/perl -w use strict; use Data::Dumper::Lite; my @array = qw(foo bar baz); my %hash = ( foo => \@array, bar => 'none', baz => 42, ); my $dumper = Data::Dumper::Lite->new(); print $dumper->Dump(\%hash);

Without any further adieu, give a nice walm welcome to Data::Dumper::Lite!

package Data::Dumper::Lite; use strict; use warnings; use Scalar::Util qw(blessed reftype looks_like_number); use B::Deparse; use vars qw($VERSION); $VERSION = "0.06"; *isa = \&UNIVERSAL::isa; # import UNIVERSAL::isa sub new { my $invocant = shift; my $class = ref($invocant) || $invocant; my $self = { DEPTH => 0, # data structure (DS) depth ORIG => undef, # original DS reference STRUCT => undef, # DS being examined. May switch to anon. array TYPE => undef, # type of DS being examined. May switch to anon +. array DUMP => undef, # data of the dump }; $self->{REF} = { # store our type handler subroutines SCALAR => sub { $self->{DUMP} .= $self->_quote(${$self->{STRUCT}}); }, CODE => sub { my $deparse = B::Deparse->new("-p", "-sC"); my $code = $deparse->coderef2text($self->{STRUCT}); $self->{DUMP} .= 'sub ' . $code; }, GLOB => sub { $self->{DUMP} .= '*' . *{$self->{STRUCT}}{PACKAGE} . '::' . *{$s +elf->{STRUCT}}{NAME}; }, REF => sub { $self->{DUMP} .= '\\'; $self->Dump(${$self->{STRUCT}}); }, HASH => sub { my %hash = %{$self->{STRUCT}}; $self->_openstruct; foreach my $key (keys %hash) { $self->{DUMP} .= $self->_spacer . $key . ' => '; my $value = $hash{$key}; if (reftype $value) { $self->Dump($value); } else { $self->{DUMP} .= $self->_quote($value) . ",\n"; } } $self->_closestruct('HASH'); }, ARRAY => sub { my @array = @{$self->{STRUCT}}; $self->_openstruct; foreach my $value (@array) { $self->{DUMP} .= $self->_spacer; if (reftype $value) { $self->Dump($value); } else { $self->{DUMP} .= $self->_quote($value) . ",\n"; } } $self->_closestruct('ARRAY'); }, LVALUE => sub { $self->{DUMP} .= "#LVALUE\n" . $self->_quote(${$self->{STRUCT}}) +; }, }; bless ($self, $class); return $self; } sub _spacer() { my $self = shift; return ($self->{DEPTH} == 1) ? '' : ' ' x $self->{DEPTH}; } sub _quote { my $self = shift; my $value = shift; return (!defined $value) ? '' : (looks_like_number $value) ? $value +: qq('$value'); } sub _openstruct { my $self = shift; $self->{DUMP} .= ($self->{TYPE} eq 'HASH' ? '{' : '[') . "\n"; ++$self->{DEPTH}; } sub _closestruct { my $self = shift; my $type = shift; # I need a reminder (but not for long) --$self->{DEPTH}; $self->{DUMP} .= $self->_spacer . ($type eq 'HASH' ? '}' : ']'); } sub Dump { my $self = shift; $self->{STRUCT} = shift; # Get the reference to a data structure $self->{TYPE} = reftype $self->{STRUCT}; # is it a reference? my $blessed = blessed $self->{STRUCT}; die "usage: Dump(REFERENCE)" if (!$self->{TYPE}); # if not, then die + quickly if ($self->{DEPTH} == 0) { $self->{ORIG} = $self->{STRUCT}; # store original reference $self->{DUMP} = '$VAR = '; } else { if ($self->{STRUCT} == $self->{ORIG}) { # see perlref $self->{DUMP} .= "\\\$VAR,\n"; return; } } ++$self->{DEPTH}; $self->{DUMP} .= "bless(" if ($blessed && !exists $self->{REF}{$bles +sed}); if (exists $self->{REF}{$self->{TYPE}}) { &{$self->{REF}{$self->{TYPE}}}; } else { $self->{DUMP} .= "Unknown {TYPE} $self->{TYPE}!\n"; } if ($blessed && !exists $self->{REF}{$blessed}) { $self->{DUMP} .= ", " . $self->_quote($blessed) . ")"; } if ($self->{DEPTH} == 1) { my $last = substr($self->{DUMP}, -2, 2); if ($last eq ",\n") { substr($self->{DUMP}, -2, 1) = ';'; } elsif ($last ne ";\n") { $self->{DUMP} .= ";\n" ; } } $self->{DUMP} .= ",\n" if ($self->{DEPTH} > 1); --$self->{DEPTH}; return $self->{DUMP}; } # end of sub Dump sub AUTOLOAD; 1;

I know that it is not exactly the prettiest module that you have ever seen but it gets the job done and weighs in at 139 lines (including the whitespace!).

This post is a Request For Comments. I.e. reply with questions, comments, suggestions, etc. I would like to upload this to CPAN once all of the kinks are worked out and the documentation has been added.

Replies are listed 'Best First'.
Re: RFC: Data::Dumper::Lite
by broquaint (Abbot) on May 27, 2003 at 16:11 UTC
    If you intend for this module to be a fully fledged data dumper then you'll want to make sure it can pass the whole Data::Dumper test suite successfully, and once that's done try the test suite from demerphq's Data::BFDump which have far more pathological test cases. Also for quoting strings you might want to check out another of demerphq's modules, Text::Quote, which will provide you with the correct quoting delimiters.

    While I'm all for the learning process what does D::D::L offer that other dumper modules on CPAN do not e.g Data::Dump is a relatively lightweight dumper written written in pure perl ?
    HTH

    _________
    broquaint

      broquaint, I wish that I could ++ this node several times. It didn't even occur to me to use Data::Dumper's test suite! I'll definately do that. If I don't try it, I will at least look at Data::BFDump's test suite.

      I'm trying to keep the footprint for this module as small as possible. That is the reason why I decided to roll my own quoting mechanism in this instance.

      what does D::D::L offer that other dumper modules on CPAN do not e.g Data::Dump is a relatively lightweight dumper written written in pure perl ?
      Like Data::Dump (which is not listed with the other Data:: modules on CPAN), I am trying to mimic Data::Dumper's functionality without the added complexity of options. Would I call D::D::L a full-fledged pretty-printer (like Data::Dumper is)? No, it is a 'lightweight, object-oriented perl data structure stringifier'. ;-) Hey, I'll have to add that to the name section of the POD (once it has POD)!

Re: RFC: Data::Dumper::Lite
by adrianh (Chancellor) on May 27, 2003 at 15:58 UTC
    I am unhappy with the way that Data::Dumper dumps a subroutine as sub { "DUMMY" } so I added in some extra functionality using B::Deparse

    Data::Dumper has been able to do this for some time. Check out $Data::Dumper::Deparse in the Data::Dumper POD.

    Question: Why? (i.e. Why should I use Data::Dumper::Lite instead of Data::Dumper or Storable :-)

      Data::Dumper has been able to do this for some time. Check out $Data::Dumper::Deparse in the Data::Dumper POD.
      A search of CPAN shows two versions, 2.101 (which I have) and 2.12 (bundled with Perl 5.8.0). As far as I can tell, $Data::Dumper::Deparse isn't supported until version 2.12.

      Why should I use Data::Dumper::Lite instead of Data::Dumper or Storable?
      That is a very good question and my knee jerk response is "Why not?" :-)

      I am trying to write a (mostly*) pure perl version of Data::Dumper that has a smaller code base (read: easier to maintain) and easier to use since there are no options what so ever. D::D::L started out as a way for me to learn more but it has grown in functionality while the code base has shrunk.

      * Mostly. I have to use B::Deparse to get at the code references. Perhaps I could make use of autouse or autoload to reduce the overhead of using B::Deparse when it is not used.

        I have to use B::Deparse to get at the code references. Perhaps I could make use of autouse or autoload to reduce the overhead of using B::Deparse when it is not used.

        perldoc -f require

        Juerd # { site => 'juerd.nl', plp_site => 'plp.juerd.nl', do_not_use => 'spamtrap' }

      His listed reason was for his own learning.

      So, if this will be a teaching tool for others to learn how to access various data structures and properties and innerds, the documentation and presentation is more important than the code!

      To that end, I think it should be a running example of a set of tutorials or cookbook recipies on how to do those things.

      —John

        I took:

        I would like to upload this to CPAN once all of the kinks are worked out and the documentation has been added.

        to mean that it was intended for use in the "real world" - so I still think it was a fair question :-)

        John M. Dlugosz, that sounds like a great idea. I could use it as the basis for an upcoming Perl Mongers meeting!

Re: RFC: Data::Dumper::Lite
by jryan (Vicar) on May 27, 2003 at 16:36 UTC

    3 things:

    1. Why would this module have an OO interface if only 1 exported subroutine would do? (i.e., similar to the existing interface to Data::Dumper)
    2. Why is this module called "Lite" if it actually provides additional functionality?
    3. Why not patch the existing Data::Dumper to have the additional functionality you want? That would be much more useful than polluting CPAN with Yet Another Dumper Module.

      1. Why would this module have an OO interface if only 1 exported subroutine would do? (i.e., similar to the existing interface to Data::Dumper)
        This is my first real attempt at module creation and I decided to add one more area of training by learning about OO. As it turns out, adding the object oriented interface reduced the amount of code while making it more difficult for someone to muck around with the innards.
      2. Why is this module called "Lite" if it actually provides additional functionality? Why not patch the existing Data::Dumper to have the additional functionality you want?
        As adrianh pointed out, it doesn't provide any additional functionality. My reply to broquaint should explain the "Lite" name.

        This is my first real attempt at module creation and I decided to add one more area of training by learning about OO. As it turns out, adding the object oriented interface reduced the amount of code while making it more difficult for someone to muck around with the innards.

        Great, but why do the people that use your module have to type Data::Dumper::Lite->new->Dump(...) when a simple change would allow them to write Dump ... instead?

        In your module:

        use Exporter::Tidy _map => { Dump => sub { __PACKAGE__->new->Dump(@_) +} };

        User's code:

        use Data::Dumper::Lite qw(Dump); print Dump(...);

        Juerd # { site => 'juerd.nl', plp_site => 'plp.juerd.nl', do_not_use => 'spamtrap' }

Re: RFC: Data::Dumper::Lite
by Mr. Muskrat (Canon) on May 27, 2003 at 18:57 UTC

    <TV announcer>Will this module be released on CPAN? Will it keep the name Data::Dumper::Lite? Tune in to next week's exciting conclusion!</TV announcer> ;-)

    The answer to both of these questions is a big, fat "I don't know yet!"

    I am hoping for many thought-provoking comments. I will make up my mind based on what you, the PerlMonks community, have to say about this.

Re: RFC: Data::Dumper::Lite
by Mr. Muskrat (Canon) on Jun 03, 2003 at 13:24 UTC

    I have been thinking about what everyone said. I really appreciate all of the feedback that I received! And while I will continue my work on it, I do not think that I will submit it to CPAN.

    I have also been meditating on the name, Data::Dumper::Lite. I have come to the conclusion that it should not necessarily mimic all of Data::Dumper's features, although it does most of it already.

    I can see incorporating this module into a tutorial or series of tutorials on data structures, references, and yes, even the B modules. Will I ever get a round tuit? Only time will tell.