📄 dumper.pm
字号:
## Data/Dumper.pm## convert perl data structures into perl syntax suitable for both printing# and eval## Documentation at the __END__#package Data::Dumper;$VERSION = '2.121_14';#$| = 1;use 5.006_001;require Exporter;require overload;use Carp;BEGIN { @ISA = qw(Exporter); @EXPORT = qw(Dumper); @EXPORT_OK = qw(DumperX); # if run under miniperl, or otherwise lacking dynamic loading, # XSLoader should be attempted to load, or the pure perl flag # toggled on load failure. eval { require XSLoader; }; $Useperl = 1 if $@;}XSLoader::load( 'Data::Dumper' ) unless $Useperl;# module vars and their defaults$Indent = 2 unless defined $Indent;$Purity = 0 unless defined $Purity;$Pad = "" unless defined $Pad;$Varname = "VAR" unless defined $Varname;$Useqq = 0 unless defined $Useqq;$Terse = 0 unless defined $Terse;$Freezer = "" unless defined $Freezer;$Toaster = "" unless defined $Toaster;$Deepcopy = 0 unless defined $Deepcopy;$Quotekeys = 1 unless defined $Quotekeys;$Bless = "bless" unless defined $Bless;#$Expdepth = 0 unless defined $Expdepth;$Maxdepth = 0 unless defined $Maxdepth;$Pair = ' => ' unless defined $Pair;$Useperl = 0 unless defined $Useperl;$Sortkeys = 0 unless defined $Sortkeys;$Deparse = 0 unless defined $Deparse;## expects an arrayref of values to be dumped.# can optionally pass an arrayref of names for the values.# names must have leading $ sign stripped. begin the name with *# to cause output of arrays and hashes rather than refs.#sub new { my($c, $v, $n) = @_; croak "Usage: PACKAGE->new(ARRAYREF, [ARRAYREF])" unless (defined($v) && (ref($v) eq 'ARRAY')); $n = [] unless (defined($n) && (ref($v) eq 'ARRAY')); my($s) = { level => 0, # current recursive depth indent => $Indent, # various styles of indenting pad => $Pad, # all lines prefixed by this string xpad => "", # padding-per-level apad => "", # added padding for hash keys n such sep => "", # list separator pair => $Pair, # hash key/value separator: defaults to ' => ' seen => {}, # local (nested) refs (id => [name, val]) todump => $v, # values to dump [] names => $n, # optional names for values [] varname => $Varname, # prefix to use for tagging nameless ones purity => $Purity, # degree to which output is evalable useqq => $Useqq, # use "" for strings (backslashitis ensues) terse => $Terse, # avoid name output (where feasible) freezer => $Freezer, # name of Freezer method for objects toaster => $Toaster, # name of method to revive objects deepcopy => $Deepcopy, # dont cross-ref, except to stop recursion quotekeys => $Quotekeys, # quote hash keys 'bless' => $Bless, # keyword to use for "bless"# expdepth => $Expdepth, # cutoff depth for explicit dumping maxdepth => $Maxdepth, # depth beyond which we give up useperl => $Useperl, # use the pure Perl implementation sortkeys => $Sortkeys, # flag or filter for sorting hash keys deparse => $Deparse, # use B::Deparse for coderefs }; if ($Indent > 0) { $s->{xpad} = " "; $s->{sep} = "\n"; } return bless($s, $c);}if ($] >= 5.006) { # Packed numeric addresses take less memory. Plus pack is faster than sprintf *init_refaddr_format = sub {}; *format_refaddr = sub { require Scalar::Util; pack "J", Scalar::Util::refaddr(shift); };} else { *init_refaddr_format = sub { require Config; my $f = $Config::Config{uvxformat}; $f =~ tr/"//d; our $refaddr_format = "0x%" . $f; }; *format_refaddr = sub { require Scalar::Util; sprintf our $refaddr_format, Scalar::Util::refaddr(shift); }}## add-to or query the table of already seen references#sub Seen { my($s, $g) = @_; if (defined($g) && (ref($g) eq 'HASH')) { init_refaddr_format(); my($k, $v, $id); while (($k, $v) = each %$g) { if (defined $v and ref $v) { $id = format_refaddr($v); if ($k =~ /^[*](.*)$/) { $k = (ref $v eq 'ARRAY') ? ( "\\\@" . $1 ) : (ref $v eq 'HASH') ? ( "\\\%" . $1 ) : (ref $v eq 'CODE') ? ( "\\\&" . $1 ) : ( "\$" . $1 ) ; } elsif ($k !~ /^\$/) { $k = "\$" . $k; } $s->{seen}{$id} = [$k, $v]; } else { carp "Only refs supported, ignoring non-ref item \$$k"; } } return $s; } else { return map { @$_ } values %{$s->{seen}}; }}## set or query the values to be dumped#sub Values { my($s, $v) = @_; if (defined($v) && (ref($v) eq 'ARRAY')) { $s->{todump} = [@$v]; # make a copy return $s; } else { return @{$s->{todump}}; }}## set or query the names of the values to be dumped#sub Names { my($s, $n) = @_; if (defined($n) && (ref($n) eq 'ARRAY')) { $s->{names} = [@$n]; # make a copy return $s; } else { return @{$s->{names}}; }}sub DESTROY {}sub Dump { return &Dumpxs unless $Data::Dumper::Useperl || (ref($_[0]) && $_[0]->{useperl}) || $Data::Dumper::Useqq || (ref($_[0]) && $_[0]->{useqq}) || $Data::Dumper::Deparse || (ref($_[0]) && $_[0]->{deparse}); return &Dumpperl;}## dump the refs in the current dumper object.# expects same args as new() if called via package name.#sub Dumpperl { my($s) = shift; my(@out, $val, $name); my($i) = 0; local(@post); init_refaddr_format(); $s = $s->new(@_) unless ref $s; for $val (@{$s->{todump}}) { my $out = ""; @post = (); $name = $s->{names}[$i++]; if (defined $name) { if ($name =~ /^[*](.*)$/) { if (defined $val) { $name = (ref $val eq 'ARRAY') ? ( "\@" . $1 ) : (ref $val eq 'HASH') ? ( "\%" . $1 ) : (ref $val eq 'CODE') ? ( "\*" . $1 ) : ( "\$" . $1 ) ; } else { $name = "\$" . $1; } } elsif ($name !~ /^\$/) { $name = "\$" . $name; } } else { $name = "\$" . $s->{varname} . $i; } # Ensure hash iterator is reset if (ref($val) eq 'HASH') { keys(%$val); } my $valstr; { local($s->{apad}) = $s->{apad}; $s->{apad} .= ' ' x (length($name) + 3) if $s->{indent} >= 2; $valstr = $s->_dump($val, $name); } $valstr = "$name = " . $valstr . ';' if @post or !$s->{terse}; $out .= $s->{pad} . $valstr . $s->{sep}; $out .= $s->{pad} . join(';' . $s->{sep} . $s->{pad}, @post) . ';' . $s->{sep} if @post; push @out, $out; } return wantarray ? @out : join('', @out);}# wrap string in single quotes (escaping if needed)sub _quote { my $val = shift; $val =~ s/([\\\'])/\\$1/g; return "'" . $val . "'";}## twist, toil and turn;# and recurse, of course.# sometimes sordidly;# and curse if no recourse.#sub _dump { my($s, $val, $name) = @_; my($sname); my($out, $realpack, $realtype, $type, $ipad, $id, $blesspad); $type = ref $val; $out = ""; if ($type) { # Call the freezer method if it's specified and the object has the # method. Trap errors and warn() instead of die()ing, like the XS # implementation. my $freezer = $s->{freezer}; if ($freezer and UNIVERSAL::can($val, $freezer)) { eval { $val->$freezer() }; warn "WARNING(Freezer method call failed): $@" if $@; } require Scalar::Util; $realpack = Scalar::Util::blessed($val); $realtype = $realpack ? Scalar::Util::reftype($val) : ref $val; $id = format_refaddr($val); # if it has a name, we need to either look it up, or keep a tab # on it so we know when we hit it later if (defined($name) and length($name)) { # keep a tab on it so that we dont fall into recursive pit if (exists $s->{seen}{$id}) {# if ($s->{expdepth} < $s->{level}) { if ($s->{purity} and $s->{level} > 0) { $out = ($realtype eq 'HASH') ? '{}' : ($realtype eq 'ARRAY') ? '[]' : 'do{my $o}' ; push @post, $name . " = " . $s->{seen}{$id}[0]; } else { $out = $s->{seen}{$id}[0]; if ($name =~ /^([\@\%])/) { my $start = $1; if ($out =~ /^\\$start/) { $out = substr($out, 1); } else { $out = $start . '{' . $out . '}'; } } } return $out;# } } else { # store our name $s->{seen}{$id} = [ (($name =~ /^[@%]/) ? ('\\' . $name ) : ($realtype eq 'CODE' and $name =~ /^[*](.*)$/) ? ('\\&' . $1 ) : $name ), $val ]; } } if ($realpack and $realpack eq 'Regexp') { $out = "$val"; $out =~ s,/,\\/,g; return "qr/$out/"; } # If purity is not set and maxdepth is set, then check depth: # if we have reached maximum depth, return the string # representation of the thing we are currently examining # at this depth (i.e., 'Foo=ARRAY(0xdeadbeef)'). if (!$s->{purity} and $s->{maxdepth} > 0 and $s->{level} >= $s->{maxdepth}) { return qq['$val']; } # we have a blessed ref if ($realpack) { $out = $s->{'bless'} . '( '; $blesspad = $s->{apad}; $s->{apad} .= ' ' if ($s->{indent} >= 2); } $s->{level}++; $ipad = $s->{xpad} x $s->{level}; if ($realtype eq 'SCALAR' || $realtype eq 'REF') { if ($realpack) { $out .= 'do{\\(my $o = ' . $s->_dump($$val, "\${$name}") . ')}'; } else { $out .= '\\' . $s->_dump($$val, "\${$name}"); } } elsif ($realtype eq 'GLOB') { $out .= '\\' . $s->_dump($$val, "*{$name}"); } elsif ($realtype eq 'ARRAY') { my($v, $pad, $mname); my($i) = 0; $out .= ($name =~ /^\@/) ? '(' : '['; $pad = $s->{sep} . $s->{pad} . $s->{apad}; ($name =~ /^\@(.*)$/) ? ($mname = "\$" . $1) : # omit -> if $foo->[0]->{bar}, but not ${$foo->[0]}->{bar} ($name =~ /^\\?[\%\@\*\$][^{].*[]}]$/) ? ($mname = $name) : ($mname = $name . '->'); $mname .= '->' if $mname =~ /^\*.+\{[A-Z]+\}$/; for $v (@$val) { $sname = $mname . '[' . $i . ']'; $out .= $pad . $ipad . '#' . $i if $s->{indent} >= 3; $out .= $pad . $ipad . $s->_dump($v, $sname); $out .= "," if $i++ < $#$val; } $out .= $pad . ($s->{xpad} x ($s->{level} - 1)) if $i; $out .= ($name =~ /^\@/) ? ')' : ']'; } elsif ($realtype eq 'HASH') { my($k, $v, $pad, $lpad, $mname, $pair); $out .= ($name =~ /^\%/) ? '(' : '{'; $pad = $s->{sep} . $s->{pad} . $s->{apad}; $lpad = $s->{apad}; $pair = $s->{pair}; ($name =~ /^\%(.*)$/) ? ($mname = "\$" . $1) : # omit -> if $foo->[0]->{bar}, but not ${$foo->[0]}->{bar} ($name =~ /^\\?[\%\@\*\$][^{].*[]}]$/) ? ($mname = $name) : ($mname = $name . '->'); $mname .= '->' if $mname =~ /^\*.+\{[A-Z]+\}$/; my ($sortkeys, $keys, $key) = ("$s->{sortkeys}"); if ($sortkeys) { if (ref($s->{sortkeys}) eq 'CODE') { $keys = $s->{sortkeys}($val); unless (ref($keys) eq 'ARRAY') { carp "Sortkeys subroutine did not return ARRAYREF"; $keys = []; } } else { $keys = [ sort keys %$val ]; } } while (($k, $v) = ! $sortkeys ? (each %$val) : @$keys ? ($key = shift(@$keys), $val->{$key}) : () ) { my $nk = $s->_dump($k, ""); $nk = $1 if !$s->{quotekeys} and $nk =~ /^[\"\']([A-Za-z_]\w*)[\"\']$/; $sname = $mname . '{' . $nk . '}'; $out .= $pad . $ipad . $nk . $pair; # temporarily alter apad $s->{apad} .= (" " x (length($nk) + 4)) if $s->{indent} >= 2; $out .= $s->_dump($val->{$k}, $sname) . ","; $s->{apad} = $lpad if $s->{indent} >= 2; } if (substr($out, -1) eq ',') { chop $out; $out .= $pad . ($s->{xpad} x ($s->{level} - 1)); } $out .= ($name =~ /^\%/) ? ')' : '}';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -