Data-Dump-Streamer
view release on metacpan or search on metacpan
lib/Data/Dump/Streamer.pm view on Meta::CPAN
package Data::Dump::Streamer;
use strict;
use warnings;
use warnings::register;
use B ();
use B::Deparse ();
use B::Utils ();
use Data::Dumper ();
use DynaLoader ();
use Exporter ();
use IO::File ();
use Symbol ();
use Text::Abbrev ();
use Text::Balanced ();
use overload ();
use Data::Dump::Streamer::_::Printers;
# The style of this file is determined by:
#
# perltidy -w -ple -bbb -bbc -bbs -nolq -l=80 -noll -nola -nwls='=' \
# -isbc -nolc -otr -kis -ci=4 -se -sot -sct -nsbl -pt=2 -fs \
# -fsb='#start-no-tidy' -fse='#end-no-tidy' -cpb -bfvt=2
# use overload qw("" printit); # does diabolical stuff.
use vars qw(
$VERSION
$XS_VERSION
$AUTOLOAD
@ISA
@EXPORT @EXPORT_OK @EXPORT_FAIL %EXPORT_TAGS
%Freeze
%Thaw
$DEBUG
$HasPadWalker
);
$DEBUG= 0;
BEGIN { $HasPadWalker= eval "use PadWalker 0.99; 1"; }
BEGIN {
$VERSION= '2.42';
$XS_VERSION= $VERSION;
$VERSION= eval $VERSION; # used for beta stuff.
@ISA= qw(Exporter DynaLoader);
@EXPORT= qw(Dump DumpLex DumpVars);
@EXPORT_OK= qw(
Dump
DumpLex
DumpVars
Stream
alias_av
alias_hv
alias_ref
push_alias
dualvar
alias_to
blessed
reftype
refaddr
refcount
sv_refcount
looks_like_number
regex
readonly
make_ro
_make_ro
reftype_or_glob
refaddr_or_glob
globname
is_numeric
all_keys
legal_keys
hidden_keys
lock_ref_keys
lock_keys
lock_ref_keys_plus
lock_keys_plus
SvREADONLY_ref
SvREFCNT_ref
isweak
weaken
weak_refcount
readonly_set
Dumper
DDumper
alias
sqz
usqz
);
%EXPORT_TAGS= (
undump => [
lib/Data/Dump/Streamer.pm view on Meta::CPAN
When C<$pass> is 0 the C<$thaw> variable may be supplied as well as the
keyorder. If it is defined then it specifies what thaw action to perform
after dumping the hash. See L<C<$thaw>|/$thaw> in L<Controlling Object
Representation> for details as to how it works. This allows an object
to define those keys needed to recreate itself properly, and a followup
hook to recreate the rest.
B<Note> that if a L<Freezer()|/Freezer> method is defined and returns
a L<C<$thaw>|/$thaw> then the L<C<$thaw>|/$thaw> returned by the sorter
will override it.
=head2 Controlling Array Presentation and Run Length Encoding
By default Data::Dump::Streamer will "run length encode" array values.
This means that when an array value is simple (ie, its not referenced and
does contain a reference) and is repeated multiple times the output will
be single a list multiplier statement, and not each item output
separately. Thus: L<C<Dump([0,0,0,0])>|/Dump> will be output something like
$ARRAY1 = [ (0) x 4 ];
This is particularly useful when dealing with large arrays that are only
partly filled, and when accidentally the array has been made very large,
such as with the improper use of pseudo-hash notation.
To disable this feature you may set the L<Rle()|/Rle> property to FALSE, by
default it is enabled and set to TRUE.
=head2 Installing I<DDS> as a package alias
Its possible to have an alias to Data::Dump::Streamer created and
installed for easier usage in one liners and short scripts.
Data::Dump::Streamer is a bit long to type sometimes. However because this
technically means polluting the root level namespace, and having it listed
on CPAN, I have elected to have the installer not install it by default.
If you wish it to be installed you must explicitly state so when
Build.Pl is run:
perl Build.Pl DDS [Other Module::Build options]
Then a normal './Build test, ./Build install' invocation will install DDS.
Using DDS is identical to Data::Dump::Streamer.
=head2 use-time package aliasing
You can also specify an alias at use-time, then use that alias in the rest
of your program, thus avoiding the permanent (but modest) namespace
pollution of the previous method.
use Data::Dumper::Streamer as => 'DDS';
# or if you prefer
use Data::Dumper::Streamer;
import Data::Dumper::Streamer as => 'DDS';
You can use any alias you like, but that doesn't mean you should.. Folks
doing as => 'DBI' will be mercilessly ridiculed.
=head2 PadWalker support
If PadWalker 1.0 is installed you can use DumpLex() to try to
automatically determine the names of the vars being dumped. As
long as the vars being dumped have my or our declarations in scope
the vars will be correctly named. Padwalker will also be used
instead of the B:: modules when dumping closures when it is available.
=head1 INTERFACE
=head2 Data::Dumper Compatibility
For drop in compatibility with the Dumper() usage of Data::Dumper, you may
request that the L<Dumper()|/Dumper> method is exported. It will not be exported by
default. In addition the standard Data::Dumper::Dumper() may be exported
on request as C<DDumper>. If you provide the tag C<:Dumper> then both will
be exported.
=over 4
=item Dumper
=item Dumper LIST
A synonym for scalar Dump(LIST)->Out for usage compatibility with
L<Data::Dumper|Data::Dumper>
=item DDumper
=item DDumper LIST
A secondary export of the actual L<Data::Dumper::Dumper|Data::Dumper>
subroutine.
=back
=head2 Constructors
=over 4
=item new
Creates a new Data::Dump::Streamer object. Currently takes no
arguments and simply returns the new object with a default style
configuration.
See C<Dump()> for a better way to do things.
=cut
sub _compressor {
return "use Data::Dump::Streamer qw(usqz);\n"
if !@_;
return sqz($_[0], "usqz('", "')");
}
sub new {
my $class= shift;
my $self= bless {
style => {
hashsep => '=>', # use this to separate key vals
arysep => ',',
pairsep => ',',
lib/Data/Dump/Streamer.pm view on Meta::CPAN
print Dump($x,$y);
but it will not affect the behaviour of
print scalar Dump($x,$y);
B<Note> As of 1.11 Dump also works as a method, with identical properties
as when called as a subroutine, with the exception that when called with
no arguments it is a synonym for C<Out()>. Thus
$obj->Dump($foo)->Names('foo')->Out();
will work fine, as will the odd looking:
$obj->Dump($foo)->Names('foo')->Dump();
which are both the same as
$obj->Names('foo')->Data($foo)->Out();
Hopefully this should make method use more or less DWIM.
=cut
my %args_insideout;
sub DESTROY {
my $self= shift;
delete $args_insideout{ Data::Dump::Streamer::refaddr $self} if $self;
}
sub Dump {
my $obj;
if (blessed($_[0]) and blessed($_[0]) eq __PACKAGE__) {
$obj= shift;
}
if (@_) {
if (defined wantarray and !wantarray) {
$obj ||= __PACKAGE__->new();
$obj->_make_args(@_);
return $obj;
}
else {
$obj ||= __PACKAGE__;
return $obj->Data(@_)->Out();
}
}
else {
if ($obj) {
return $obj->Out();
}
else {
return __PACKAGE__->new();
}
}
}
=item DumpLex VALUES
DumpLex is similar to Dump except it will try to automatically determine
the names to use for the variables being dumped by using PadWalker to
have a poke around the calling lexical scope to see what is declared. If
a name for a var can't be found then it will be named according to the
normal scheme. When PadWalker isn't installed this is just a wrapper for
L<Dump()|/Dump>.
Thanks to Ovid for the idea of this. See L<Data::Dumper::Simple> for a
similar wrapper around L<Data::Dumper>.
=cut
sub DumpLex {
if (!$HasPadWalker) {
#warn( "Can't use DumpLex without ".
# "PadWalker v1.0 or later installed.");
goto &Dump;
}
my $obj;
if (blessed($_[0]) and blessed($_[0]) eq __PACKAGE__) {
$obj= shift;
}
my @names;
# = map {
# PadWalker::var_name(1,\$_)
# || PadWalker::var_name(1,\$_)
# (ref $_ && PadWalker::var_name(1,$_));
# $str
# } @_;
#if ( !@names && @_ ) {
my %pad_vars;
foreach my $pad (PadWalker::peek_my(1), PadWalker::peek_our(1)) {
while (my ($var, $ref)= each %$pad) {
$pad_vars{ refaddr $ref } ||= $var;
}
}
foreach (@_) {
my $name;
INNER: foreach (\$_, $_) {
$name= $pad_vars{ refaddr $_}
and last INNER;
}
push @names, $name;
}
if (defined wantarray and !wantarray) {
$obj ||= __PACKAGE__->new();
$obj->_make_args(@_);
$obj->Names(@names);
return $obj;
}
else {
$obj ||= __PACKAGE__;
return $obj->Names(@names)->Data(@_)->Out();
}
}
=item DumpVars PAIRS
This is wrapper around L<Dump()|/Dump> which expect to receive
a list of name=>value pairs instead of a list of values.
Otherwise behaves like L<Dump()|/Dump>. Note that names starting
with a '-' are treated the same as those starting with '*' when
passed to L<Names()|/Names>.
=cut
sub DumpVars {
my $obj;
if (blessed($_[0]) and blessed($_[0]) eq __PACKAGE__) {
$obj= shift;
}
if (@_ % 2) {
warnings::warnif "Odd number of arguments in DumpVars";
pop @_;
}
my @names;
my @args;
for (0 .. $#_ / 2) {
$names[$_]= $_[ $_ * 2 ];
$args[$_]= $_ * 2 + 1;
}
#die "@_:@names|@args";
if (defined wantarray and !wantarray) {
$obj ||= __PACKAGE__->new();
$obj->_make_args(@_[@args]);
$obj->Names(@names);
return $obj;
}
else {
$obj ||= __PACKAGE__;
return $obj->Data(@_[@args])->Names(@names)->Out();
lib/Data/Dump/Streamer.pm view on Meta::CPAN
}
if (my $postop= $self->{ref_postop}{ $raddr || $addr }) {
if (ref $postop) {
$postop->($_[1]);
}
else {
$_[1]->$postop();
}
}
$self->{do_nl}= 1;
return;
}
=item Names
=item Names LIST
=item Names ARRAYREF
Takes a list of strings or a reference to an array of strings to use for
var names for the objects dumped. The names may be prefixed by a *
indicating the variable is to be dumped as its dereferenced type if it is
an array, hash or code ref. Otherwise the star is ignored. Other sigils
may be prefixed but they will be silently converted to *'s.
If no names are provided then names are generated automatically based on
the type of object being dumped, with abbreviations applied to compound
class names.
If called with arguments then returns the object itself, otherwise in list
context returns the list of names in use, or in scalar context a reference
or undef. In void context with no arguments the names are cleared.
B<NOTE:>
Must be called before C<Data()> is called.
If you wish to have no names, use L<Terse>.
=cut
sub Names {
my $self= shift->_safe_self;
if (@_) {
my $v= (@_ == 1 and reftype $_[0] eq 'ARRAY') ? shift @_ : \@_;
$self->{unames}= [
map {
(my $s= $_) =~ s/^[\@\%\&-]/*/;
$s =~ s/^\$//;
Carp::confess "Bad name '$_'"
if $s && $s !~ /^\*?\w+$/;
$s
} grep { defined } @$v
];
return $self;
}
elsif (!defined wantarray) {
$self->{unames}= [];
}
#elsif ( eval { require PadWalker; 1 } ) {
# print DDumper(PadWalker::peek_my(1));
# return $self;
#}
return wantarray ? @{ $self->{unames} || [] } : $self->{unames};
}
=item Terse
=item Terse BOOL
When true, no variable names will be created. Data will be dumped as
anonymous references or values.
Dump([])->Out; # $ARRAY1 = []
Dump([])->Terse(1)->Out; # []
=cut
sub Terse {
my $self= shift->_safe_self;
if (@_) {
$self->{style}{terse}= shift;
return $self;
}
else {
return $self->{style}{terse};
}
}
=for UEDIT
sub Purity {}
=item Purity
=item Purity BOOL
This option can be used to set the level of purity in the output. It
defaults to TRUE, which results in the module doing its best to ensure
that the resulting dump when eval()ed is precisely the same as the input.
However, at times such as debugging this can be tedious, resulting in
extremely long dumps with many "fix" statements involved. By setting
Purity to FALSE the resulting output won't necessarily be legal Perl, but
it will be more legible. In this mode the output is broadly similar to
that of the default setting of Data::Dumper (Purity(0)). When set to TRUE
the behaviour is likewise similar to Data::Dumper in Purity(1) but more
accurate.
When Purity() is set to FALSE aliases will be output with a function call
wrapper of 'alias_to' whose argument will be the value the item is an
alias to. This wrapper does nothing, and is only there as a visual cue.
Likewise, 'make_ro' will be output when the value was readonly, and again
the effect is cosmetic only.
=item To
=item To STREAMER
Specifies the object to print to. Data::Dump::Streamer can stream its
output to any object supporting the print method. This is primarily meant
for streaming to a filehandle, however any object that supports the method
lib/Data/Dump/Streamer.pm view on Meta::CPAN
die "Unknown sortkeys '$val', and "
. (ref($obj) || $obj)
. " doesn't know how to do it.\n"
if !$subref;
$self->{style}{sortkeys_string}{$name}= $val;
$val= $subref;
}
elsif (reftype($val) eq 'ARRAY') {
my $aryref= $val;
$val= sub { return $aryref; };
}
elsif (reftype($val) ne 'CODE') {
Carp::confess("Can't use '$val' as KeyOrder() value");
}
$self->{style}{sortkeys}{$name}= $val;
}
}
return $self;
}
*Keyorder= *KeyOrder;
sub SortKeys {
my $self= shift;
$self->KeyOrder("", @_);
}
*Sortkeys= *SortKeys;
*HashKeys= *Hashkeys= *KeyOrder;
my %scalar_meth= map { $_ => lc($_) } qw(Declare Indent IndentCols IndentKeys
Verbose DumpGlob Deparse DeparseGlob DeparseFormat CodeStub
FormatStub Rle RLE Purity DualVars Dualvars EclipseName
Compress Compressor OptSpace);
sub AUTOLOAD {
(my $meth= $AUTOLOAD) =~ s/^((?:\w+::)+)//;
my $name;
if (defined($name= $scalar_meth{$meth})) {
$DEBUG and print "AUTLOADING scalar meth $meth ($name)\n";
eval '
sub ' . $meth . ' {
my $self=shift->_safe_self();
if (@_) {
$self->{style}{' . $name . '}=shift;
return $self
} else {
return $self->{style}{' . $name . '}
}
}
';
$@ and die "$meth:$@\n";
goto &$meth;
}
elsif ($meth =~ /[^A-Z]/) {
Carp::confess "Unhandled method/subroutine call $AUTOLOAD";
}
}
sub _get_lexicals {
my $cv= shift;
if ($HasPadWalker) {
my ($names, $targs)= PadWalker::closed_over($cv);
if ($PadWalker::VERSION < 1) {
$names->{$_}= $names->{ $targs->{$_} } for keys %$targs;
}
else {
%$names= (%$names, %$targs);
}
return $names;
}
my $svo= B::svref_2object($cv);
my @pl_array= eval { $svo->PADLIST->ARRAY };
my @name_obj= eval { $pl_array[0]->ARRAY };
my %named;
for my $i (0 .. $#name_obj) {
if (ref($name_obj[$i]) !~ /SPECIAL/) {
$named{$i}= $name_obj[$i]->PV;
}
}
my %inited;
my %used;
B::Utils::walkoptree_filtered(
$svo->ROOT,
sub { B::Utils::opgrep { name => [qw[ padsv padav padhv ]] }, @_ },
sub {
my ($op, @items)= @_;
my $targ= $op->targ;
my $name= $named{$targ}
or return;
$inited{$name}++
if $op->private & 128;
if (!$inited{$name}) {
$used{$name}= $pl_array[1]->ARRAYelt($targ)->object_2svref;
$used{$targ}= $used{$name};
$inited{$name}++;
}
});
return \%used;
}
package Data::Dump::Streamer::Deparser;
use B::Deparse;
our @ISA= qw(B::Deparse);
my %cache;
our $VERSION= '2.42';
$VERSION= eval $VERSION;
if ($VERSION ne $Data::Dump::Streamer::VERSION) {
die
"Incompatible Data::Dump::Streamer::Deparser v$VERSION vs Data::Dump::Streamer v$Data::Dump::Streamer::VERSION";
}
sub dds_usenames {
my $self= shift;
my $names= shift;
$cache{ Data::Dump::Streamer::refaddr $self}= $names;
}
( run in 0.663 second using v1.01-cache-2.11-cpan-39bf76dae61 )