从Perl模块导入有条件编译的函数

Rob*_*nes 2 perl

我有一组日志和调试功能,我想在多个模块/对象中使用它们.我希望能够使用命令行开关全局打开/关闭它们.

下面的代码执行此操作,但是,我希望能够省略包名并将所有内容保存在单个文件中.

更具体地说,我想将日志记录函数名称导入到每个模块中,以便可以在没有任何包名称限定的情况下调用它们(类似于C++ use namespace;指令),并且我希望能够从使用的脚本全局启用/禁用它们它们在我下面的示例代码中.

这与我在此处此处提出的前两个问题有关.

另一件事 - 我不认为我完全理解为什么以下代码有效.

#! /usr/bin/perl -w

use strict;
use Getopt::Long;

{
    package LogFuncs;

    use threads;
    use Time::HiRes qw( gettimeofday );

    # provide tcpdump style time stamp
    sub _gf_time {
        my ( $seconds, $microseconds ) = gettimeofday();
        my @time = localtime($seconds);

        return sprintf( "%02d:%02d:%02d.%06ld",
            $time[2], $time[1], $time[0], $microseconds );
    }

    sub logerr;

    sub compile {
        my %params = @_;

        *logerr = $params{do_logging}
            ? sub {
                my $msg = shift;
                warn _gf_time() . " Thread " . threads->tid() . ": $msg\n";
            }
            : sub { };
    }            
}

{
    package FooObj;

    sub new {
        my $class = shift;
        bless {}, $class; 
    };

    sub foo_work { 
        my $self = shift;
        # do some foo work
        LogFuncs::logerr($self);
    }
}

{
    package BarObj;

    sub new {
        my $class = shift;
        my $data  = { fooObj => FooObj->new() };
        bless $data, $class;
    }

    sub bar_work { 
        my $self = shift;
        $self->{fooObj}->foo_work();
        LogFuncs::logerr($self);
    }
}        

my $do_logging = 0;

GetOptions(
    "do_logging"    => \$do_logging,
);

LogFuncs::compile(do_logging => $do_logging);

my $bar = BarObj->new();
LogFuncs::logerr("Created $bar");
$bar->bar_work();
Run Code Online (Sandbox Code Playgroud)

Eri*_*rom 6

如果您想将所有内容保存在同一个文件中,为什么不将记录器放在文件范围词汇的顶部.

GetOptions( do_logging => \$do_logging );

my $logerr = $do_logging ? sub {logging_code_here()} : sub {};
Run Code Online (Sandbox Code Playgroud)

$logerr 现在可以在同一文件中该点之后定义的任何包中使用.

但是,构建日志记录调用通常更快,如下所示:

my $logerr = sub { logging_code_here() };

$logerr->("some string $some_var") if $do_logging;
Run Code Online (Sandbox Code Playgroud)

这样你就可以避免子程序调用,如果日志记录关闭,则不需要计算$ logerr的字符串参数.

您还可以设置日志记录级别:

$logerr->("starting loop")     if $do_logging;

for (@big_array) {
    $logerr->("processing $_") if $do_logging > 1;
    ...
}
Run Code Online (Sandbox Code Playgroud)

编辑:虽然我不认为这是最好的做法,根据你的意见,这是你可能正在寻找的(一个pragma):

use 5.010;
use warnings;
use strict;
BEGIN {  # compile time
    $INC{'log.pm'}++;  # block 'require log;'
    package log;
    sub is_active {(caller 1)[10]{log}}  # test the hints hash
    sub import {
        $^H{log} = 1;  # set the hints hash for 'log'
        my $logmsg = (caller).'::logmsg';  # name of caller's sub
        no strict 'refs';
        *$logmsg = sub {print "logging: @_\n" if is_active}  # install sub
            unless *{$logmsg}{CODE}; # unless we did already
    }
    sub unimport {
        $^H{log} = 0;  # unset the hints hash
    }
}

package MyPkg;

use log;
logmsg 'hello, world!';

{
  no log;
  logmsg 'nope, not here';
}

logmsg 'back again';
Run Code Online (Sandbox Code Playgroud)