2010-04-12 21 views
16

Necesito definir algunos módulos y usarlos todos en el mismo archivo. No, no puedo cambiar el requisito.¿Cómo puedo llamar a un paquete de Perl que defino en el mismo archivo?

me gustaría hacer algo como lo siguiente:

{ 
    package FooObj; 

    sub new { ... } 

    sub add_data { ... } 
} 

{ 
    package BarObj; 

    use FooObj; 

    sub new { 
     ... 
     # BarObj "has a" FooObj 
     my $self = (myFoo => FooObj->new()); 
     ... 
    } 

    sub some_method { ... } 
} 

my $bar = BarObj->new(); 

Sin embargo, esto se traduce en el mensaje:

No se puede encontrar en FooObj.pm @INC ...
COMENZAR fallado ...

¿Cómo consigo que esto funcione?

+3

La sugerencia aparece en el error aquí: "No se puede encontrar FooObj.pm". .pm siempre significa un archivo. –

Respuesta

23

Suelta el use. Seriamente.

use le dice a Perl que lea en el código de otro archivo, que no es necesario porque el código está en el mismo archivo.

+0

¿Y cómo importar cualquier cosa exportada por 'Exporter' sin el uso de' use'? – ceving

+0

@ceving Llamada 'import' directamente. p.ej., 'FooObj-> import (@params)' en el caso del código de esta pregunta (si usó 'Exporter'). Sin –

+0

que tenía una pregunta diferente en mente: http://stackoverflow.com/q/33634898/402322 – ceving

14

A menos que esté tratando de crear un paquete privado que nadie debería saber, puse un paquete por archivo. Eso resuelve el problema. Pero, pongámoslos en el mismo archivo.

El use carga un archivo y llama al método import en ese paquete. En realidad, solo es un incidente que su argumento se parece a un nombre de módulo. Está buscando el archivo. Si el archivo no está allí, es barfs.

Usted puede hacer esto, donde BarObj supone que FooObj está ya allí:

{ 
    package FooObj; 
    sub new  { bless { _count => 0 }, $_[0] } 
    sub add_data { $_[0]->{_count}++ } 
} 

{ 
    package BarObj; 
    use Data::Dumper; 

    sub new { 
     bless { myFoo => FooObj->new }, $_[0]; 
     } 

    sub foo   { $_[0]->{myFoo} } 
    sub some_method { print Dumper($_[0]) } 
} 

my $bar = BarObj->new; 
$bar->some_method; 

Si necesita interactuar con un paquete (y eso es todo lo que es: no es un módulo o un objeto), que acaba Necesito tenerlo definido antes de que quieras usarlo. Si tiene que importar algo, puede llamar a la import directamente:

FooObj->import(...); 

Supongamos que hay algo de FooObj que desea importar (pero no heredará!), Se llama a import directamente sin carga;

{ 
    package FooObj; 
    use Data::Dumper; 
    sub new  { bless { _count => 0 }, $_[0] } 
    sub add_data { $_[0]->{_count}++ } 

    use Exporter qw(import); 
    our @EXPORT = qw(dumper); 
    sub dumper { print Dumper($_[0]) } 
} 

{ 
    package BarObj; 
    FooObj->import; 

    sub new { 
     bless { myFoo => FooObj->new }, $_[0]; 
     } 

    sub foo   { $_[0]->{myFoo} } 

    # dumper mixin, not inherited. 
    sub some_method { dumper($_[0]) } 
} 

my $bar = BarObj->new; 
$bar->some_method; 
10

Por convención que puso un paquete en un archivo y las nombran la misma cosa, pero eso es sólo por conveniencia. Puede poner varios paquetes en un solo archivo. Como ya están cargados, no necesita usar use.

Tampoco necesita crear un ámbito especial para los paquetes, ya que la palabra clave del paquete se ocupa de eso. Usar las llaves ayuda con el alcance de las variables our. Entonces no necesitas estrictamente esos bloqueos, pero son una buena idea.

use usa una convención de nomenclatura de paquetes para encontrar el archivo apropiado para cargar. La palabra clave package dentro del módulo define el espacio de nombres. Y las funciones de importación manejan la carga del paquete (generalmente heredada de Exporter).

#!/usr/bin/perl 

use strict; 
use warnings; 

package FooObj; 

sub new 
{ 
     my $this = shift; 
     my $class = ref($this) || $this; 
     my $self = {}; 
     bless $self, $class; 
     $self->initialize(); 
     return $self; 
} 

sub initialize { } 
sub add_data { } 

package BarObj; 

#use FooObj; <-- not needed. 

sub new 
{ 
     my $this = shift; 
     my $class = ref($this) || $this; 
     my $self = { myFoo => FooObj->new() }; 
     bless $self, $class; 
     $self->initialize(); 
     return $self; 
} 
sub initialize { } 
sub some_method { } 
sub myFoo  { return $_[0]->{myFoo} } 

package main; 
use Test::More; 
my $bar = BarObj->new(); 
isa_ok($bar,  'BarObj', "bar is a BarObj"); 
isa_ok($bar->myFoo, 'FooObj', "bar->myFoo is a FooObj"); 
done_testing(); 

__DATA__ 

ok 1 - bar is a BarObj isa BarObj 
ok 2 - bar->myFoo is a FooObj isa FooObj 
1..2 
+2

1 Para información interesante, sin embargo yo prefiero usar las llaves ya que creo que añade claridad visual. –

+0

Robert, entiendo tu punto. A menudo utilizo llaves (nombradas) para mayor claridad visual, generalmente justo antes de decidir que una sección determinada necesita ser refactorizada en su propia rutina o que una secuencia de comandos del controlador necesita trasladar más funcionalidades al módulo. No suelo poner varios paquetes en un solo archivo, así que realmente no han considerado la necesidad de apoyarse o no que se preparen. – spazm

+6

No es solo claridad, sino un problema de alcance. Los paquetes no crean un ámbito, de modo que la variable my() que tiene allí tiene un ámbito de archivo sin las llaves que lo limitarían de lo contrario. –

Cuestiones relacionadas