index | project | pods | responsabili

NOME

perltie - come nascondere una classe in una semplice variabile


SINOSSI

 tie VARIABILE, NOME_CLASSE, LISTA
 $oggetto = tied VARIABILE
 untie VARIABILE


DESCRIZIONE

Prima della versione 5.0 di Perl, un programmatore poteva usare dbmopen() per collegare magicamente un database su disco nel formato Unix standard dbm(3x) ad un %HASH nel suo programma. Ad ogni modo, Perl era compilato con una particolare della libreria dbm oppure con un'altra, ma non con entrambe, e non si poteva estendere questo meccanismo ad altri package o tipi di variabile.

Adesso si puo`.

La funzione tie() lega una variabile ad una classe (un package) che fornira` l'implementazione per i metodi di accesso a quella variabile. Una volta che questa magia si e` realizzata, l'accesso alla variabile legata fa automaticamente scattare le chiamate ai metodi nella classe opportuna. La complessita` della classe e` nascosta dietro alle magiche chiamate ai metodi. I nomi dei metodi sono in LETTERE MAIUSCOLE, che e` una convenzione usata da Perl per indicare che vengono chiamati implicitamente anziche` esplicitamente -- proprio come le funzioni BEGIN() e END().

Nella chiamata a tie(), VARIABILE e` il nome della variabile su cui lanciare l'incantesimo. CLASSNAME e` il nome della classe che implementa oggetti del tipo corretto. Qualunque argomento aggiuntivo nella LISTA viene passato all'appropriato costruttore per quella classe -- vale a dire TIESCALAR(), TIEARRAY(), TIEHASH() o TIEHANDLE(). (Tipicamente si tratta di argomenti come quelli che potrebbero essere passati alla funzione dbminit() del C.) L'oggetto restituito dal metodo ``new'' viene restituito anche dalla funzione tie(), cosa che potrebbe risultare utile se voleste accedere ad altri metodi in NOME_CLASSE. (Non dovete necessariamente restituire un riferimento al tipo ``giusto'' (ad esempio HASH o NOME_CLASSE), basta che sia un oggetto [?]``blessed'' {come tradurre blessed?}[/?].) Potete inoltre recuperare un riferimento all'oggetto sottostante usando la funzione tied().

A differenza di dbmopen(), la funzione tie() non ricorre a use o require [?]per caricare un modulo {qui mi sono preso molta liberta`: da rivedere}[/?]-- dovete farlo esplicitamente per conto vostro.

[?]Legare scalari {orribile}[/?]

Una classe che implementa uno scalare legato dovrebbe definire i seguenti metodi: TIESCALAR, FETCH, STORE, e possibilmente UNTIE e/o DESTROY.

Esaminiamoli uno ad uno {at each in turn}, usando come esempio una classe per scalari legati che permette all'utente di fare qualcosa come:

    tie $la_sua_velocita, 'Nice', getppid();
    tie $la_mia_velocita, 'Nice', $$;

E ora ogniqualvolta si accede ad una di queste variabili, la sua priorita` di sistema corrente e` recuperata e restituita. Se queste variabili vengono impostate, allora la priorita` del processo viene modificata!

Useremo classe BSD::Resource di Jarkko Hietaniemi <jhi@iki.fi> per accedere alle costanti PRIO_PROCESS, PRIO_MIN, e PRIO_MAX dal vostro sistema, e alle chiamate di sistema getpriority() e setpriority(). Ecco il preambolo della classe.

    package Nice;
    use Carp;
    use BSD::Resource;
    use strict;
    $Nice::DEBUG = 0 unless defined $Nice::DEBUG;
TIESCALAR nome_classe, LISTA
E` il costruttore della classe. Questo significa che e` richiesto che restituisca un riferimento ``blessed'' al nuovo scalare (probabilmente anonimo) che sta creando. Per esempio:
    sub TIESCALAR {
        my $classe = shift;
        my $pid = shift || $$; # 0 vuol dire me
        if ($pid !~ /^\d+$/) {
            carp "Nice::Tie::Scalar ha ricevuto un pid $pid non numerico" 
              if $^W;
            return undef;
        }
        unless (kill 0, $pid) { # EPERM oERSCH, senza dubbio 
            carp "Nice::Tie::Scalar ha ricevuto un pid $pid sbagliato: $!" 
              if $^W;
            return undef;
        }
        return bless \$pid, $classe;
    }

Questa classe tie ha scelto di restituire un errore anziche` sollevare un'eccezione se il suo costruttore dovesse fallire. Benche` questo sia il modo in cui dbmopen() funziona, altre classi potrebbero non volere essere cosi` di manica larga. Controlla la variabile globale $^W per vedere se deve comunque fare un po' di rumore.

FETCH this
Questo metodo viene fatto scattare tutte le volte che si accede (si legge) alla variabile legata. Non accetta argomenti a parte il riferimento stesso, che e` l'oggetto che rappresenta lo scalare con cui abbiamo a che fare. Poiche` in questo caso stiamo usando solo un riferimento a SCALARE per l'oggetto scalare legato, un semplice $$self permette al metodo di recuperare il valore ivi memorizzato. Nell'esempio qui sotto, il valore e` l'ID del processo al quale abbiamo legato la nostra variabile

    sub FETCH {
        my $self = shift;
        confess "wrong type" unless ref $self;
        croak "usage error" if @_;
        my $nicety;
        local($!) = 0;
        $nicety = getpriority(PRIO_PROCESS, $$self);
        if ($!) { croak "getpriority failed: $!" }
        return $nicety;
    }

Questa volta abbiamo deciso di [?]fare i capricci {ho tradotto cosi` blow up, forse serve qualcosa di piu` forte?}[/?] (sollevare un'eccezione) se renice fallisce -- altrimenti non c'e` un posto dove restituire un'eccezione, e probabilmente e` la cosa giusta da fare.

STORE this, valore

Mon Jun 11 22:02:20 2012