如何覆盖File :: Copy :: move?

时间:2015-10-20 21:48:57

标签: perl override

考虑以下简单模块MyCode.pm。它包含一个函数my_function触摸文件然后重命名它。

#!/usr/bin/perl

package MyCode;

use strict;
use warnings;

use IO::File;
use File::Copy;

sub my_function {
  # touch /tmp/a
  my $fh = IO::File->new();
  $fh->open(">/tmp/a") || die "open failed ($!)";  
  $fh->close() || die "close failed ($!)";
  unlink("/tmp/aa"); # ignore errors; we want file removed
  move("/tmp/a", "/tmp/aa") || die "move failed ($!)";
}

1;

现在考虑以下测试程序。它会成功覆盖IO::File::openIO::File::close,但不会覆盖File::Copy::move。为什么呢?

#!/usr/bin/perl -l

use strict;
use warnings;

use IO::File;
use File::Copy;

use MyCode;

{
  no warnings 'redefine';
  local *IO::File::open = sub  { 
    eval {      
      $! = 44; # random value for illustration purposes
      die;
    };
  };

  eval {
    MyCode::my_function() 
  };
  print $@ if $@;
}

{
  no warnings 'redefine';
  local *IO::File::close = sub {
    eval {
      $! = 33; # random value for illustration purposes
      die;
    };
  };

  eval {
    MyCode::my_function() 
  };
  print $@ if $@;
}

{
  no warnings 'redefine';
  local *File::Copy::move = sub {
    eval {
      $! = 22; # random value for illustration purposes
      die;
    };
  };

  eval {
    MyCode::my_function() 
  };
  print $@ if $@;
}

下面的程序输出。 move覆盖没有输出,这意味着它没有启动。为什么?我也想知道为什么我会收到警告。

Name "IO::File::close" used only once: possible typo at ./test.pl line 28.
open failed (Channel number out of range) at MyCode.pm line 14.

close failed (Numerical argument out of domain) at MyCode.pm line 15.

2 个答案:

答案 0 :(得分:2)

  

它将成功覆盖IO :: File :: open,IO :: File :: close但不会覆盖File :: Copy :: move。为什么?

它会覆盖File::Copy::move。问题是您不是拨打File::Copy::move,而是MyCode::move。因此,您需要使用

local *MyCode::move = sub { ... };
  

我想知道为什么我会收到[警告Name "IO::File::close" used only once: possible typo]。

警告存在以帮助查找拼写错误。在编译期间仅遇到包符号一次时会发出它。在这种情况下,这是一个虚假的警告(就像您禁用的重新定义的警告一样)。

替换

no warnings 'redefine';

no warnings 'once';

答案 1 :(得分:1)

使用完整路径(File :: Copy :: move)可以很好地工作。只需要在运行时将'use'更改为'require'即可导入。

use strict;
use warnings;

# use File::Copy;
require File::Copy;
use Errno;

{
  no warnings 'redefine';
  local *move = sub { 
    eval {      
      $! = Errno::EREMMO;
      die "oops ($!)";
    };
  };

File::Copy::move("d:\\swadhi\\perl\\a.txt.bak", "D:\\swadhi\\perl\\bakkkkkup.txt") || print $@;