2009-12-23 8 views
11

La documentación CORE me ha mostrado cómo burlarse alegremente de varias funciones integradas de Perl. Sin embargo, no estoy seguro de cómo reemplazar '-d' & c. con mis métodos Entonces, esta es realmente solo una pregunta sobre cómo reemplazar una función con un guion en CORE :: GLOBAL.Perl: mocking -d -f y amigos. Cómo ponerlos en CORE :: GLOBAL

Una referencia manual sería agradable.

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

por qué '* import = \ y exportador :: importación;' 'en lugar de utilizar 'importación' exportador;'? – Ether

Respuesta

6

Es posible que no sea posible. La sección perlsub en Overriding Built-in Functions es vaga sobre qué funciones se pueden anular. "Muchos" pueden, "algunos" no pueden, pero aparte de algunos ejemplos, no hay una lista definitiva.

Normalmente, me gustaría probar este:

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

que no es un error de sintaxis, pero no tiene el efecto de anular -d.

+0

Si ese es el caso, tendré que hacer que el código objetivo sea más comprobable. gracias – telesphore4

+6

Anulación de CORE :: GLOBAL tiene que suceder al COMIENZO o Perl no lo verá. Es un hack de rendimiento. De todos modos, CORE :: GLOBAL solo funciona con cosas con prototipos. -d no tiene prototipo. – Schwern

11

CORE :: GLOBAL no funciona en cosas sin prototipos. La única forma en que puedo pensar es en volver a escribir el árbol de códigos de operación ... que no es para los débiles de corazón. Puede llevarlo a cabo con una combinación de B::Utils y B::Generate y mucha experimentación.

Lo más simple sería usar File::Temp para hacer una estructura de directorios temporal a su gusto.

1

Se podía ir a la ruta filtro de origen:.

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; 
} 

(Este código de ejemplo no es muy robusto Por ejemplo, no se traducirá -d$dir o -d "dirname with spaces", pero se puede reforzar hacia arriba hasta que se encuentra con el necesidades de su código objetivo).

+0

Esa es una idea interesante ... transformaciones de código fuente ... muy Lispish Gracias! – telesphore4

2

El problema es que su aplicación depende de las especificaciones del archivo codificado. Debe parametrizar las especificaciones del archivo; entonces no tiene que seguir burlándose, solo puede usar Directory :: Scratch o algo así.

+0

De acuerdo. Sin embargo, estoy agregando código de prueba a una aplicación heredada. – telesphore4

3

Gracias por todas sus respuestas.

Lo que terminé haciendo, es decir, sobre una base por objetivo módulo/prueba, refactorizada el código con el "-d" en ella en su propia función. Al igual que ...

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

Entonces puede reemplazar esta función en el módulo de prueba con igual

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

sub mock_dirExists { 
    return $doesDirExist; 
} 

Es bastante feo, pero yo no quería que se colgó en este demasiado largo y se enuf funciona bien para mis propósitos