dax*_*xim 7 perl metaprogramming
存在几个可以显示变量名称而不需要程序员明确重复名称的转储器.
› perl -MData::Dumper::Simple -e'my $foo = 42; print Dumper($foo)'
$foo = 42;
Run Code Online (Sandbox Code Playgroud)
诡计是源过滤器(经常中断).
› perl -MDDS -e'my $foo = 42; DumpLex $foo'
$foo = 42;
Run Code Online (Sandbox Code Playgroud)
技巧是PadWalker.
它们在某种程度上也适用于其他类型的变量,但切片或其他复杂表达式存在问题.
可以利用哪个现代(5.10之后)eval技巧来制作以下示例转储器(如:数据结构查看器,不可用的代码生成器)?重点是始终打印好的名称,接受多个表达式,而不需要使用额外的参考级别来更改表达式.
use 5.020; use Syntax::Construct qw(%slice);
use strictures;
use Acme::Hypothetical::Dumper 'd';
my %foo = (
Me => 'person',
You => 'beloved one',
Them => 'space aliens',
);
d %foo, $foo{'Me'}, @foo{qw(You Me)}, %foo{qw(You Me)};
# %foo = ('Me' => 'person', 'Them' => 'space aliens', 'You' => 'beloved one');
# $foo{'Me'} = 'person';
# @foo{qw(You Me)} = ('beloved one', 'person');
# %foo{qw(You Me)} = ('Me' => 'person', 'You' => 'beloved one');
my @bar = qw(Me You Them);
d @bar, $bar[0], @bar[2, 1], %bar[2, 1];
# @bar = ('Me', 'You', 'Them');
# $bar[0] = 'Me';
# @bar[2, 1] = ('Them', 'You');
# %bar[2, 1] = (2 => 'Them', 1 => 'You');
use LWP::UserAgent qw();
my $ua = LWP::UserAgent->new;
d $ua->{ssl_opts}{verify_hostname};
# $ua->{ssl_opts}{verify_hostname} = 1;
Run Code Online (Sandbox Code Playgroud)
输出中的空格与您的示例并不完全匹配,但这非常接近......
use v5.14;
use strict;
use warnings;
BEGIN {
package Acme::Hypothetical::Dumper;
use Keyword::Simple;
use PPR;
use Data::Dumper;
use B 'perlstring';
sub import {
my ( $class, $fname ) = ( shift, @_ );
$fname ||= 'd';
Keyword::Simple::define $fname => sub {
my $code = shift;
my ( @ws, @vars, @ws2 );
while ( $$code =~ / ^ ((?&PerlOWS)) ((?&PerlTerm)) ((?&PerlOWS)) $PPR::GRAMMAR /x ) {
my $len = length( $1 . $2 . $3 );
push @ws, $1;
push @vars, $2;
push @ws2, $3;
substr( $$code, 0, $len ) = '';
$$code =~ s/ ^ (?&PerlComma) $PPR::GRAMMAR //x;
}
my $newcode = perlstring( $class ) . '->d(';
while ( @vars ) {
my $var = shift @vars;
$newcode .= sprintf(
'%s%s,[%s],%s',
shift( @ws ),
perlstring( $var ),
$var,
shift( @ws2 ),
);
}
$newcode .= ');';
substr( $$code, 0, 0 ) = $newcode;
return;
};
}
our $OUTPUT = \*STDERR;
sub d {
my ( $class, @args ) = ( shift, @_ );
while ( @args ) {
my ( $label, $value ) = splice( @args, 0, 2 );
my $method = 'dump_list';
if ( $label =~ /^\$/ ) {
$method = 'dump_scalar';
$value = $value->[0];
}
elsif ( $label =~ /^\%/ ) {
$method = 'dump_hash';
}
printf { $OUTPUT } "%s = %s;\n", $label, $class->$method( $value );
}
}
sub dump_scalar {
my ( $class, $value ) = ( shift, @_ );
local $Data::Dumper::Terse = 1;
local $Data::Dumper::Indent = 0;
return Dumper( $value );
}
sub dump_list {
my ( $class, $value ) = ( shift, @_ );
my $dumped = $class->dump_scalar( $value );
$dumped =~ s/\[/(/;
$dumped =~ s/\]/)/;
return $dumped;
}
sub dump_hash {
my ( $class, $value ) = ( shift, @_ );
my $dumped = $class->dump_scalar( { @$value } );
$dumped =~ s/\{/(/;
$dumped =~ s/\}/)/;
return $dumped;
}
$INC{'Acme/Hypothetical/Dumper.pm'} = __FILE__;
};
use Acme::Hypothetical::Dumper 'd';
my %foo = (
Me => 'person',
You => 'beloved one',
Them => 'space aliens',
);
d %foo, $foo{'Me'}, @foo{qw(You Me)}, %foo{qw(You Me)};
my @bar = qw(Me You Them);
d @bar, $bar[0], @bar[2, 1], %bar[2, 1];
use LWP::UserAgent qw();
my $ua = LWP::UserAgent->new;
d $ua->{ssl_opts}{verify_hostname};
Run Code Online (Sandbox Code Playgroud)