代码之家  ›  专栏  ›  技术社区  ›  Aakash Goel

用Perl编写宏

  •  13
  • Aakash Goel  · 技术社区  · 14 年前
    open $FP, '>', $outfile or die $outfile." Cannot open file for writing\n";
    
    • 我在我的代码里有很多次这样的语句。

    • 我想对所有这些语句保持相同的格式,这样当某些内容发生更改时,它只在一个地方发生更改。

    • 在Perl中,我应该如何着手解决这种情况?

    我见过这样的线 How can I use macros in Perl?

    #define fw(FP, outfile) open $FP, '>', \
            $outfile or die $outfile." Cannot open file for writing\n";
    
    4 回复  |  直到 7 年前
        1
  •  25
  •   Sinan Ünür    5 年前

    首先,你应该这样写:

    open my $FP, '>', $outfile or die "Could not open '$outfile' for writing:$!";
    

    包括原因 open 失败。

    如果你想封装它,你可以写:

    use Carp;
    
    sub openex {
        my ($mode, $filename) = @_; 
        open my $h, $mode, $filename
            or croak "Could not open '$filename': $!";
        return $h;
    }
    
    # later
    
    my $FP = openex('>', $outfile);
    

    autodie 是在核心,我将第二次查斯。欧文斯建议使用它。

        2
  •  10
  •   Chas. Owens    14 年前

    Perl5真的没有宏(有源代码过滤器,但它们既危险又难看,所以即使我也不会将您链接到文档)。函数可能是正确的选择,但您会发现,它使新用户更难阅读您的代码。更好的选择可能是使用 autodie or die 部分。

    另一种选择,如果你使用 Vim ,是用来 snipMate . 你只是打字 fw<tab>FP<tab>outfile<tab>

    open my $FP, '>', $outfile
        or die "Couldn't open $outfile for writing: $!\n";
    

    snipMate文本是

    snippet fw
        open my $${1:filehandle}, ">", $${2:filename variable}
            or die "Couldn't open $$2 for writing: $!\n";
    
        ${3}
    

    我相信其他编辑器也有类似的功能,但我是Vim用户。

        3
  •  7
  •   tellme    7 年前

    源过滤器

    如果必须有一个C/CPP风格的预处理器宏,那么可以使用预编译用Perl(或者,实际上,任何语言)编写一个 source filter . 您可以编写相当简单到复杂的Perl类,对源代码的文本进行操作,并在代码进入Perl编译器之前对其执行转换。您甚至可以通过CPP预处理器直接运行Perl代码,以获得在C/CPP中使用的宏扩展的确切类型 Filter::CPP .

    Filter::Simple 是Perl核心发行版的一部分。使用Filter::Simple,您可以轻松地编写一个简单的模块来执行所描述的宏。举个例子:

    package myopinion;
    # save in your Perl's @INC path as "myopinion.pm"...
    use Filter::Simple;
    FILTER { 
        s/Hogs/Pigs/g; 
        s/Hawgs/Hogs/g;
        }
    1; 
    

    然后是一个Perl文件:

    use myopinion;
    print join(' ',"Hogs", 'Hogs', qq/Hawgs/, q/Hogs/, "\n");
    print "In my opinion, Hogs are Hogs\n\n";
    

    Pigs Pigs Hogs Pigs 
    In my opinion, Pigs are Pigs
    

    根据我的经验,源代码过滤器并没有被广泛使用。我经常看到他们试图加密Perl源代码或幽默的Perl obfuscators . 换言之,我知道可以这样做,但我个人对它们了解不够,不能推荐或说不用它们。

    子程式

    思南nr openex subroutine 是实现这一目标的好方法。我只想补充一点,您将看到的一个常见的较老的习惯用法涉及传递对typeglob的引用,如下所示:

    sub opensesame {
       my $fn=shift;
       local *FH;
       return open(FH,$fn) ? *FH : undef;
    }
    
    $fh=opensesame('> /tmp/file');
    

    阅读 perldata 为什么是这样。。。

    伪语言

    Template::Toolkit 可以用来处理Perl源代码。例如,您可以按照以下行编写模板:

    [% fw(fp, outfile) %] 
    

    通过Template::Toolkit运行该工具会导致扩展和替换到:

    open my $FP, '>', $outfile or die "$outfile could not be opened for writing:$!"; 
    

    文本编辑器

    查斯。欧文斯有一个 method 使用Vim。我使用BBEdit,可以很容易地编写一个文本工厂,用我想要使用的精确且不断发展的open替换open的骨架。或者,您可以在“Perl”文件夹的“Resources”目录中放置一个完成模板。按定义的一系列键时,将使用这些完成骨架。几乎任何严肃的编辑器都会有类似的功能。

    Perl::Critic 这种方式。你可以用 Template::Toolkit

    使用文本编辑器的两个潜在问题。首先是单向/一次性转换。如果您想更改“宏”的功能,则不能更改,因为“宏”的上一个文本已经被使用。您必须手动更改它们。第二个潜在问题是,如果使用模板表单,则无法将源代码的宏版本发送给其他人,因为预处理是在编辑器中完成的。

    别这样!

    如果你打字 perl -h 要获取有效的命令开关,您可能会看到一个选项:

    -P                run program through C preprocessor before compilation
    

    #defines . 放下枪;走开;不要这样做。存在许多平台不兼容和语言不兼容。

    你会遇到这样的问题:

    #!/usr/bin/perl -P
    #define BIG small
    print "BIG\n";
    print qq(BIG\n);
    

    印刷品:

    BIG
    small
    

    -P

    结论

    这里最灵活的解决方案就是编写一个子程序。您的所有代码都在子例程中可见,易于更改,并且调用时间更短。除了代码的可读性之外,没有什么真正的缺点。

    Template::Toolkit被广泛使用。您可以编写类似宏的复杂替换,甚至比C宏更复杂。如果您对宏的需求值得学习,请使用Template::Toolkit。

    如果你真的想要C风格的宏,你可以使用 筛选器::CPP . 这可能与 perl -P 开关。我不推荐这样做,只要学习Perl方法就行了。

    如果要在代码编译之前对其运行Perl单行程序和Perl regex,请使用Filter::Simple。

    -第 开关。无论如何,在新版本的Perl上也不能这样做。

        4
  •  0
  •   choy    14 年前

    对于像open这样的东西,我认为在分解例程中包含close是很有用的。这里的方法看起来有点古怪,但是封装了一个典型的打开/关闭习惯用法。

    sub with_file_do(&$$) {
      my ($code, $mode, $file) = @_;
      open my $fp, '>', $file or die "Could not open '$file' for writing:$!";
      local $FP = $fp;
      $code->(); # perhaps wrap in an eval
      close $fp;
    }
    
    # usage
    with_file_do {
      print $FP "whatever\n";
      # other output things with $FP
    } '>', $outfile;
    

    附属的 关键字。