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

How to override File::Copy::move?

考虑以下简单模块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.

使用完整路径 (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 $@;

It will successfully override IO::File::open, IO::File::close but not File::Copy::move. Why?

它确实覆盖了 File::Copy::move。问题是您没有调用 File::Copy::move,而是调用 MyCode::move。因此,您需要使用

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

I'd like to know also why I am getting [the warning Name "IO::File::close" used only once: possible typo].

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

替换

no warnings 'redefine';

no warnings 'once';