2017-04-20 5 views
3

Je suis d'ajouter dynamiquement des classes, méthodes et attributs à l'aide Moose :: Meta :: Class.même appel de fonction apporter des résultats différents dans les internes de l'objet?

Quelqu'un peut-il expliquer pourquoi ce code fonctionne (appel interne sous-programme generate(), à l'intérieur Cat classe):

package Cat; 

use Moose; 

sub generate { 

    my $siberian = Moose::Meta::Class->create('Siberian'); 
    $siberian->add_method(echo => sub { print "yeah!\n" }); 


    my $tiger = Moose::Meta::Class->create('Tiger'); 
    $tiger->add_attribute(
     Siberian => { 
      is  => 'ro', 
      default => sub { $siberian->new_object; } 
     }, 
    ); 

    __PACKAGE__->meta->add_attribute(
     Tiger => { 
      is  => 'ro', 
      default => sub { $tiger->new_object }, 
     }, 
    ); 

    print "Generation done!\n"; 
} 

generate(); 


package main; 

use Data::Printer; 

my $a = Cat->new; 

# $a->generate; 
p($a); 
$a->Tiger->Siberian->echo; # returns 'yeah!' 

sortie p($a):

Cat { 
    Parents  Moose::Object 
    public methods (3) : generate, meta, Tiger 
    private methods (0) 
    internals: { 
     Tiger Tiger 
    } 
} 

et celui-ci (appelant generate sous l'extérieur, via $a->generate) ne fait pas:

package Cat; 
use Moose; 

sub generate { 

    my $siberian = Moose::Meta::Class->create('Siberian'); 
    $siberian->add_method(
     echo => sub { print "yeah!\n" } 
    ); 

    my $tiger = Moose::Meta::Class->create('Tiger'); 
    $tiger->add_attribute(
     Siberian => { 
      is  => 'ro', 
      default => sub { $siberian->new_object; } 
     }, 
    ); 

    __PACKAGE__->meta->add_attribute(
     Tiger => { 
      is  => 'ro', 
      default => sub { $tiger->new_object }, 
     }, 
    ); 

    print "Generation done!\n"; 

} 

# generate(); 


package main; 
use Data::Printer; 

my $a = Cat->new; 
$a->generate; 
p($a); 
$a->Tiger->Siberian->echo; # returns 'yeah!' 

sortie p($a):

Cat { 
    Parents  Moose::Object 
    public methods (3) : generate, meta, Tiger 
    private methods (0) 
    internals: {} 
} 

et le programme renvoie une erreur:

Can't call method "Siberian" on an undefined value at base2.pl line 39.

+0

Parce que quand vous appelle $ a-> vous ajoutez cette générer à la classe Cat attribut, pas à l'instance de cette classe Cat ($ a). Et même si vous ajoutez à l'instance (objet) ce champ ne sera pas initialisé. –

Répondre

0

Depuis generate est pas objet, mais la méthode de classe, il est nécessaire d'appeler avant new:

Cat->generate; 
my $a = Cat->new;