2009-02-07 10 views
4

Je viens de commencer à en apprendre davantage sur tie. J'ai une classe nommée lien que je voudrais faire la chose suivante:Comment puis-je appeler des méthodes sur une variable liée?

  • si tiré par les cheveux, retourner l'adresse
  • du lien si, mémorisez la nouvelle adresse
  • être en mesure d'appeler des méthodes sur elle

jusqu'à présent, mon code est:


package Link; 

sub FETCH { 
    my $this = shift; 
    return $this->{"site"}; 
} 

sub STORE { 
    my ($self,$site) = @_; 
    $self->{"site"} = $site; 
} 

sub print_method { 
    my $self = shift; 
    print $self->{"site"}; 
} 

sub TIESCALAR { 
    my $class = shift; 
    my $link = shift; 
    my $this = {}; 
    bless($this,$class); 
    $this->{"site"} = $link; 
    return $this; 
} 

1; 

Et le code que je utilise pour vérifier la fonctionnalité est:


use Link; 

tie my $var,"Link","http://somesite.com"; 
$var->print_method; 

Lorsque couru, le script se terminera avec l'erreur suivante: Impossible d'appeler la méthode « print_method » sans référence de colis ou objet à la ligne de tietest.pl 4..

Si je comprends bien son message, $var->print_method décide de la ficelle sur laquelle la méthode print_method est appelée. Comment pourrais-je bénéficier de la cravate, mais aussi utiliser la variable comme un objet?

EDIT: après avoir expérimenté un peu, j'ai découvert que si je retourne $ self sur fetch, je peux appeler les méthodes, cependant, fetch ne retournera pas l'adresse.

EDIT 2: les moines perl m'ont fourni la solution: liée. tied renvoie une référence à l'objet VARIABLE. En combinant mes méthodes et ma méthode, je peux accomplir tout ce que je voulais.

Répondre

9

Cravate est le mauvais outil pour ce travail. Vous utilisez des liens lorsque vous souhaitez utiliser la même interface que les types de données normaux mais que vous souhaitez personnaliser le fonctionnement des opérations.Puisque vous voulez accéder et stocker une chaîne comme le fait déjà un scalaire, tie ne fait rien pour vous.

On dirait que vous voulez le module URI, ou une sous-classe de celui-ci, et peut-être une certaine surcharge.

Si vous avez vraiment besoin de faire cela, vous devez utiliser la bonne variable. Le tie connecte la variable que vous spécifiez à la classe que vous spécifiez, mais il s'agit toujours d'un scalaire normal (et non d'une référence). Vous devez utiliser l'objet retourne si vous voulez appeler des méthodes:

my $secret_object = tie my($normal_scalar), 'Tie::Class', @args; 
$secret_object->print_method; 

Vous pouvez également obtenir l'objet secret si vous avez seulement le scalaire lié:

my $secret_object = tied $normal_scalar; 

J'ai un chapitre entier sur attacher Mastering Perl.

8

Je suggère de créer un objet Perl normal puis de overload. Vous perdez la possibilité de stocker une valeur via l'affectation, mais vous pouvez conserver la valeur en imprimant l'objet. Une fois que vous commencez à vouloir appeler les méthodes directement, un objet est probablement ce que vous voulez.

package Link; 

use strict; 
use Carp; 

use overload 
(
    '""'  => sub { shift->site }, 
    fallback => 1, 
); 

sub new 
{ 
    my $class = shift; 

    my $self = bless {}, $class; 

    if(@_) 
    { 
    if(@_ == 1) 
    { 
     $self->{'site'} = shift; 
    } 
    else { croak "$class->new() expects a single URL argument" } 
    } 

    return $self; 
} 

sub site 
{ 
    my $self = shift; 
    $self->{'site'} = shift if(@_); 
    return $self->{'site'}; 
} 

sub print_method 
{ 
    my $self = shift; 
    print $self->site, "\n"; 
} 

1; 

Exemple d'utilisation:

use Link; 

my $link = Link->new('http://somesite.com'); 

print $link, "\n"; # http://somesite.com 
$link->print_method; # http://somesite.com 

Si vous voulez vraiment, vraiment affectation à un travail aussi, vous pouvez combiner un objet normal avec mise en chaîne surchargée (Link, ci-dessus) avec tie:

package LinkTie; 

use strict; 
use Link; 

sub FETCH 
{ 
    my $this = shift; 
    return $this->{'link'}; 
} 

sub STORE 
{ 
    my($self, $site) = @_; 
    $self->{'link'}->site($site); 
    return $site; 
} 

# XXX: You could generalize this delegation with Class::Delegation or similar 
sub print_method 
{ 
    my $self = shift; 
    print $self->{'link'}->print_method; 
} 

sub TIESCALAR 
{ 
    my $class = shift; 
    my $self = bless {}, $class; 
    $self->{'link'} = Link->new(@_); 
    return $self; 
} 

1; 

Exemple d'utilisation:

tie my $link,'LinkTie','http://somesite.com'; 
print $link, "\n"; # http://somesite.com 
$link->print_method; # http://somesite.com 

$link = 'http://othersite.com'; 

print $link, "\n"; # http://othersite.com 
$link->print_method; # http://othersite.com 

Tout cela est assez hideux et un long chemin à parcourir juste pour obtenir la capacité douteuse à attribuer à quelque chose que vous pouvez également appeler des méthodes et aussi imprimer tel quel. Un objet URI standard avec stringification est probablement un meilleur pari.

+0

+1 aucune raison de lier si tout ce que vous voulez faire est de stringifier. – Axeman

+0

ouais, mais en lui affectant, n'aura pas l'effet que je cherche. Est ce que j'ai demandé impossible? – Geo

Questions connexes