2009-12-23 22 views
11

CORE文檔向我展示瞭如何快速模擬各種構建的Perl函數。但是,我不確定如何替換'-d'& c。用我的方法。所以這實際上只是一個問題,我如何在CORE :: GLOBAL中用一個破折號替換一個函數。Perl:嘲笑-d -f和朋友。如何將它們放入CORE :: GLOBAL

手動引用會很好。

package Testing::MockDir; 

use strict; 
use warnings; 
use Exporter(); 
use Symbol 'qualify_to_ref'; 

*import = \&Exporter::import; 

our @EXPORT_OK = qw(SetMockDir UnsetMockDir); 

our %EXPORT_TAGS = (
    'all' => \@EXPORT_OK, 
); 

my %path2List =(); 
my %handle2List =(); 

BEGIN { 
    *CORE::GLOBAL::opendir = \&Testing::MockDir::opendir; 
    *CORE::GLOBAL::readdir = \&Testing::MockDir::readdir; 
    *CORE::GLOBAL::closedir = \&Testing::MockDir::closedir; 

    ######################### the "-" is really the problem here 
    *CORE::GLOBAL::-d = \&Testing::MockDir::mock_d; # This does not work <<<<< 
} 

sub mock_d ($) { 
    die 'It worked'; 
} 

sub SetMockDir { 
    my ($path, @files) = @_; 
    $path2List{$path} = [@files]; 
} 

sub UnsetMockDir { 
    my ($path) = @_; 
    delete $path2List{$path}; 
} 

sub opendir (*$) { 
    my $handle = qualify_to_ref(shift, caller); 
    my ($path) = @_; 
    return CORE::opendir($handle, $path) unless defined $path2List{$path}; 
    $handle2List{$handle} = $path2List{$path}; 
    return 1; 
} 

sub readdir (*) { 
    my $handle = qualify_to_ref(shift, caller); 
    return CORE::readdir($handle) unless defined $handle2List{$handle}; 
    return shift @{$handle2List{$handle}} unless wantarray; 

    my @files = @{$handle2List{$handle}}; 
    $handle2List{$handle} = []; 
    return @files; 
} 

sub closedir (*) { 
    my $handle = qualify_to_ref(shift, caller); 
    return CORE::closedir($handle) unless defined $handle2List{$handle}; 
    delete $handle2List{$handle}; 
    return 1; 
} 

1; 
+0

爲什麼'* import = \&Exporter :: import;'而不是'使用導出'導入';'? – Ether 2010-09-09 17:55:47

回答

6

這可能是不可能的。關於Overriding Built-in Functionsperlsub部分對哪些功能可以被覆蓋很模糊。 「許多」可以,「一些」不可以,但除了少數例子之外,沒有確定的列表。

通常情況下,我想試試這個:

{ 
    no strict 'refs'; 
    *{'CORE::GLOBAL::-d'} = \&Testing::MockDir::mock_d; 
} 

這不是一個語法錯誤,但沒有覆蓋-d的效果。

+0

如果是這種情況,那麼我將不得不使目標代碼更易於測試。謝謝 – telesphore4 2009-12-23 19:30:09

+6

重寫CORE :: GLOBAL必須在BEGIN時間發生,否則Perl將不會看到它。它的性能破壞。無論如何,CORE :: GLOBAL只適用於具有原型的東西。 -d沒有原型。 – Schwern 2009-12-23 22:20:40

11

CORE :: GLOBAL不適用於沒有原型的東西。我能想到的唯一方法就是重寫操作碼樹......這不是心靈的隱隱。你可以結合使用B::UtilsB::Generate以及大量的實驗。

最簡單的做法是使用File::Temp來製作一個臨時目錄結構以滿足您的需要。

1

你可以去源過濾路線:

package Testing::MockDir; 
use Filter::Simple; 
FILTER { s/\s+\-d (\S+)/ Testing::MockDir::filetest 'd',$1/g }; 
sub filetest { 
    my ($test, $file) = @_; 
    print "Mocking -$test $file\n"; 
    return 1; 
} 

(此示例代碼不是很健壯例如,它不會轉化-d$dir-d "dirname with spaces",但直至符合你牛起來您的目標代碼的需求)。

+0

這是一個有趣的想法...源代碼轉換...非常Lispish謝謝! – telesphore4 2010-01-05 18:26:16

2

問題是您的應用程序依賴於硬編碼的文件規範。您應該參數化文件規格;那麼你不必再嘲笑了,你可以使用Directory :: Scratch或其他東西。

+0

同意。不過,我正在將測試代碼添加到舊應用中。 – telesphore4 2010-01-05 18:26:58

3

謝謝你的回答。

我最終做的是,在每個模塊/測試目標的基礎上,我將帶有「-d」的代碼分解爲它自己的函數。是這樣的...

# Because I cannot mock -d directly 
sub dirExists { 
    return -d shift; 
} 

然後我就可以測試模塊與諸如替換該功能

my $doesDirExist = 1; 
*MyModule::dirExists = \&main::mock_dirExists; 

sub mock_dirExists { 
    return $doesDirExist; 
} 

這是非常醜陋的,但我不想先掛了這個時間過長,它爲我的目的很好enuf