I want to do two things:
我想做两件事:
In production code, I want to redefine the open command to enable me to add automagic file logging. I work on data processing applications/flows and as part of that, it's important for the user to know exactly what files are being processed. If they are using an old version of a file, one way for them to find out is by reading through the list of files being processed.
在生产代码中,我想重新定义open命令以使我能够添加自动文件记录。我从事数据处理应用程序/流程的工作,作为其中的一部分,用户必须确切地知道正在处理的文件。如果他们使用旧版本的文件,他们找到的一种方法是阅读正在处理的文件列表。
I could just create a new sub that does this logging and returns a file pointer and use that in place of open in my code.
我可以创建一个新的子进程来执行此日志记录并返回一个文件指针,并在我的代码中使用它代替open。
It would be really nice if I could just redefine open and have pre-existing code benefit from this behavior. Can I do this?
如果我可以重新定义open并且预先存在的代码可以从这种行为中获益,那将是非常好的。我可以这样做吗?
In debug code, I'd like to redefine the printf command to insert comments along with the written output indicating which code generated that line. Again, I have a sub that will optionally do this, but converting my existing code is tedious.
在调试代码中,我想重新定义printf命令以插入注释以及指示生成该行的代码的写入输出。同样,我有一个sub可以选择这样做,但转换我现有的代码是乏味的。
2 个解决方案
#1
9
For open: This worked for me.
对于开放:这对我有用。
use 5.010;
use strict;
use warnings;
use subs 'open';
use Symbol qw<geniosym>;
sub open (*$;@) {
say "Opening $_[-1]";
my ( $symb_arg ) = @_;
my $symb;
if ( defined $symb_arg ) {
no strict;
my $caller = caller();
$symb = \*{$symb_arg};
}
else {
$_[0] = geniosym;
}
given ( scalar @_ ) {
when ( 2 ) { return CORE::open( $symb // $_[0], $_[1] ); }
when ( 3 ) { return CORE::open( $symb // $_[0], $_[1], $_[2] ); }
}
return $symb;
}
open PERL4_FH, '<', 'D:\temp\TMP24FB.sql';
open my $lex_fh, '<', 'D:\temp\TMP24FB.sql';
For Printf: Did you check out this question? -> How can I hook into Perl’s print?
对于Printf:你看过这个问题吗? - >如何挂钩Perl的打印?
#2
13
If a CORE subroutine has a prototype*
it can be replaced. Replacing a function in the current namespace is simple enough.
如果CORE子例程具有原型*,则可以替换它。替换当前命名空间中的函数非常简单。
#!/usr/bin/perl
use strict;
use warnings;
use subs 'chdir';
sub chdir(;$) {
my $dir = shift;
$dir = $ENV{HOME} unless defined $dir;
print "changing dir to $dir\n";
CORE::chdir $dir;
}
chdir("/tmp");
chdir;
If you want to override the function for all modules as well you can read the docs.
如果要覆盖所有模块的功能,也可以阅读文档。
*
Here is code to test every function in Perl 5.10 (it will work on earlier versions as well). Note, some functions can be overridden that this program will tell you can't be, but the overridden function will not behave in the same way as the original function.
*这是测试Perl 5.10中每个函数的代码(它也适用于早期版本)。注意,某些函数可以被覆盖,该程序将告诉您不能,但被覆盖的函数将不会以与原始函数相同的方式运行。
from perldoc -f prototype
来自perldoc -f原型
If the builtin is not overridable (such as qw//) or if its arguments cannot be adequately expressed by a prototype (such as system), prototype() returns undef, because the builtin does not really behave like a Perl function
如果内置不可覆盖(例如qw //)或者它的参数不能被原型(例如系统)充分表达,那么prototype()会返回undef,因为内置函数的行为并不像Perl函数
#!/usr/bin/perl
use strict;
use warnings;
for my $func (map { split } <DATA>) {
my $proto;
#skip functions not in this version of Perl
next unless eval { $proto = prototype "CORE::$func"; 1 };
if ($proto) {
print "$func has a prototype of $proto\n";
} else {
print "$func cannot be overridden\n";
}
}
__DATA__
abs accept alarm atan2 bind
binmode bless break caller chdir
chmod chomp chop chown chr
chroot close closedir connect continue
cos crypt dbmclose defined delete
die do dump each endgrent
endhostent endnetent endprotoent endpwent endservent
eof eval exec exists exit
exp fcntl fileno flock fork
format formline getc getgrent getgrgid
getgrnam gethostbyaddr gethostbyname gethostent getlogin
getnetbyaddr getnetbyhost getnetent getpeername getpgrp
getppid getpriority getprotobyname getprotobynumber getprotoent
getpwent getpwnam getpwuid getservbyname getservbyport
getservent getsockname getsockopt glob gmtime
goto grep hex import index
int ioctl join keys kill
last lc lcfirst length link
listen local localtime lock log
lstat m map mkdir msgctl
msgget msgrcv msgsnd my next
no oct open opendir ord
our pack package pipe pop
pos print printf prototype push
q qq qr quotemeta qw
qx rand read readdir readline
readlink readpipe recv redo ref
rename require reset return reverse
rewinddir rindex rmdir s say
scalar seek seekdir select semctl
semget semop send setgrent sethostent
setnetent setpgrp setpriority setprotoent setpwent
setservent setsockopt shift shmctl shmget
shmread shmwrite shutdown sin sleep
socket socketpair sort splice split
sprintf sqrt srand stat state
study sub substr symlink syscall
sysopen sysread sysseek system syswrite
tell telldir tie tied time
times tr truncate uc ucfirst
umask undef unlink unpack unshift
untie use utime values vec
wait waitpid wantarray warn write
y -r -w -x -o
-R -W -X -O -e
-z -s -f -d -l
-p -S -b -c -t
-u -g -k -T -B
-M -A -C
#1
9
For open: This worked for me.
对于开放:这对我有用。
use 5.010;
use strict;
use warnings;
use subs 'open';
use Symbol qw<geniosym>;
sub open (*$;@) {
say "Opening $_[-1]";
my ( $symb_arg ) = @_;
my $symb;
if ( defined $symb_arg ) {
no strict;
my $caller = caller();
$symb = \*{$symb_arg};
}
else {
$_[0] = geniosym;
}
given ( scalar @_ ) {
when ( 2 ) { return CORE::open( $symb // $_[0], $_[1] ); }
when ( 3 ) { return CORE::open( $symb // $_[0], $_[1], $_[2] ); }
}
return $symb;
}
open PERL4_FH, '<', 'D:\temp\TMP24FB.sql';
open my $lex_fh, '<', 'D:\temp\TMP24FB.sql';
For Printf: Did you check out this question? -> How can I hook into Perl’s print?
对于Printf:你看过这个问题吗? - >如何挂钩Perl的打印?
#2
13
If a CORE subroutine has a prototype*
it can be replaced. Replacing a function in the current namespace is simple enough.
如果CORE子例程具有原型*,则可以替换它。替换当前命名空间中的函数非常简单。
#!/usr/bin/perl
use strict;
use warnings;
use subs 'chdir';
sub chdir(;$) {
my $dir = shift;
$dir = $ENV{HOME} unless defined $dir;
print "changing dir to $dir\n";
CORE::chdir $dir;
}
chdir("/tmp");
chdir;
If you want to override the function for all modules as well you can read the docs.
如果要覆盖所有模块的功能,也可以阅读文档。
*
Here is code to test every function in Perl 5.10 (it will work on earlier versions as well). Note, some functions can be overridden that this program will tell you can't be, but the overridden function will not behave in the same way as the original function.
*这是测试Perl 5.10中每个函数的代码(它也适用于早期版本)。注意,某些函数可以被覆盖,该程序将告诉您不能,但被覆盖的函数将不会以与原始函数相同的方式运行。
from perldoc -f prototype
来自perldoc -f原型
If the builtin is not overridable (such as qw//) or if its arguments cannot be adequately expressed by a prototype (such as system), prototype() returns undef, because the builtin does not really behave like a Perl function
如果内置不可覆盖(例如qw //)或者它的参数不能被原型(例如系统)充分表达,那么prototype()会返回undef,因为内置函数的行为并不像Perl函数
#!/usr/bin/perl
use strict;
use warnings;
for my $func (map { split } <DATA>) {
my $proto;
#skip functions not in this version of Perl
next unless eval { $proto = prototype "CORE::$func"; 1 };
if ($proto) {
print "$func has a prototype of $proto\n";
} else {
print "$func cannot be overridden\n";
}
}
__DATA__
abs accept alarm atan2 bind
binmode bless break caller chdir
chmod chomp chop chown chr
chroot close closedir connect continue
cos crypt dbmclose defined delete
die do dump each endgrent
endhostent endnetent endprotoent endpwent endservent
eof eval exec exists exit
exp fcntl fileno flock fork
format formline getc getgrent getgrgid
getgrnam gethostbyaddr gethostbyname gethostent getlogin
getnetbyaddr getnetbyhost getnetent getpeername getpgrp
getppid getpriority getprotobyname getprotobynumber getprotoent
getpwent getpwnam getpwuid getservbyname getservbyport
getservent getsockname getsockopt glob gmtime
goto grep hex import index
int ioctl join keys kill
last lc lcfirst length link
listen local localtime lock log
lstat m map mkdir msgctl
msgget msgrcv msgsnd my next
no oct open opendir ord
our pack package pipe pop
pos print printf prototype push
q qq qr quotemeta qw
qx rand read readdir readline
readlink readpipe recv redo ref
rename require reset return reverse
rewinddir rindex rmdir s say
scalar seek seekdir select semctl
semget semop send setgrent sethostent
setnetent setpgrp setpriority setprotoent setpwent
setservent setsockopt shift shmctl shmget
shmread shmwrite shutdown sin sleep
socket socketpair sort splice split
sprintf sqrt srand stat state
study sub substr symlink syscall
sysopen sysread sysseek system syswrite
tell telldir tie tied time
times tr truncate uc ucfirst
umask undef unlink unpack unshift
untie use utime values vec
wait waitpid wantarray warn write
y -r -w -x -o
-R -W -X -O -e
-z -s -f -d -l
-p -S -b -c -t
-u -g -k -T -B
-M -A -C