2012-07-26 10 views
5

Sto usando reval dal modulo Safe di Perl e voglio impedirgli di generare avvisi se la stringa sottoposta a valutazione non può essere analizzata (in realtà, voglio impedirgli di generare alcun avviso) ."nessun avviso;" in un compartimento sicuro

Ad esempio, il seguente codice:

use strict; use warnings; 
use Safe;  
use feature qw/say/; 
my $cft = Safe->new; 

my $x = $cft->reval(') 1'); 
my $y = $cft->reval('2' ); 
say "x: $x"; 
say "y: $y"; 

risultati in:

Number found where operator expected at (eval 5) line 1, near ") 1" 
    (Missing operator before 1?) 
Use of uninitialized value $x in concatenation (.) or string at ./test line 12. 
x: 
y: 2 

Quello che sto cercando di realizzare è quello di avere $ x = undef e $ y = 2, e non avvertenze. Ho provato a mettere un "nessun avviso"; all'interno di un nuovo campo di applicazione, ma non ha alcun effetto sulle avvertenze prodotte dall'interno del Reval (anche se, come sottolineato da @DavidO, tacita l'avviso 'valore non inizializzato'):

use strict; use warnings; 
use Safe;  
use feature qw/say/; 
my $cft = Safe->new; 
{ 
    no warnings; 
    my $x = $cft->reval(') 1'); 
    my $y = $cft->reval('2' ); 
    say "x: $x"; 
    say "y: $y"; 
} 

Credo che in qualche modo la 'nessun avvertimento' deve essere all'interno del compartimento sicuro, quindi ho anche cercato di anteporre "nessun avvertimento"; alle stringhe di essere eval'ed:

use strict; use warnings; 
use Safe; 
use feature qw/say/; 
my $cft = Safe->new; 
{ 
    my $x = $cft->reval('no warnings;' . ') 1'); 
    my $y = $cft->reval('no warnings;' . '2' ); 
    say "x: $x"; 
    say "y: $y"; 
} 

In questo modo Reval non emette eventuali avvisi, ma entrambe le variabili sono undef:

Use of uninitialized value $x in concatenation (.) or string at ./test line 10. 
x: 
Use of uninitialized value $y in concatenation (.) or string at ./test line 11. 
y: 

non so che altro per provare, e spero che la descrizione del problema era abbastanza chiara.

+1

Il tuo secondo tentativo in realtà non produce lo stesso risultato del primo. Produce ancora l'errore "compiletime" (in realtà l'errore compiletime reval), ma non l'avviso di runtime relativo all'interpolazione di un valore non inizializzato nella dichiarazione 'say'. Quindi hai effettivamente risolto metà del tuo problema (silenziato l'avviso) nel secondo frammento sopra. L'altra metà (sopprimere l'errore di compilazione) è più problematica. – DavidO

+0

Sì, hai ragione su questo. Non me ne sono nemmeno accorto perché la mia preoccupazione principale qui è stata davvero la rivalsa: gli avvertimenti variabili non inizializzati sono una conseguenza di me che sto cercando di mantenere l'esempio breve. Ad ogni modo, ho aggiornato il post per renderlo più chiaro. Grazie! – andrefs

risposta

4

Se si seleziona [email protected], si vedrà che $cft->reval('no warnings;' . ') 1'); non è riuscito. 'require' trapped by operation mask at (eval 5) line 1.. In altre parole, Safe sta facendo il suo lavoro e impedisce a quel codice di provare a caricare una libreria.

$cft->reval('BEGIN { warnings->unimport; }) 1'); funzionerebbe, presumendo che gli avvisi sono già stati caricati al di fuori del vano. Tuttavia, ciò non comporterà errori di compilazione del tempo. A differenza di eval, reval sembra lasciarli passare. Usa la tecnica di amon per calmare STDERR.

+0

Un approccio a due livelli funziona meglio. L'avvertimento viene generato al di fuori del 'reval', e può essere soffocato in questo ambito più ampio. L'errore compiletime viene generato all'interno del 'reval' ed è piuttosto testardo. Qui è dove reindirizzare STDERR è l'opzione meno male, imho. (L'altra opzione è quella di consentire esplicitamente l'eval all'interno del compartimento sicuro, ma allora perché preoccuparsi di usare Save? :)). – DavidO

+0

È divertente però; eseguendo un ''qr/[c-a] /'' all'interno del compartimento sicuro, che è una regex non valida che genera un errore mentre viene compilato, viene intrappolato con successo dal reval. – DavidO

+0

Grazie per le risposte. Il metodo di @ amon sembra essere la migliore alternativa per mettere a tacere anche gli errori di parsing più severi. L'istruzione BEGIN {warnings-> unimport;} sembra funzionare, tranne se si richiama esplicitamente qualcosa come warn "foo" nella stringa da valutare: P – andrefs

4

no warnings sopprime tutti gli avvisi generati dal pragma use warnings. Probabilmente vorrai rimuovere anche eventuali ure strict. Ma gravi errori di analisi appariranno in qualsiasi modo.

Se si desidera eseguire alcun codice, non importa quanto sia patologico, senza alcun output STDERR, si dovrebbe modificare localmente il gestore di segnale:

{ 
    # I know what I'm doing! 
    local $SIG{__WARN__} = sub {}; # locally ignore any warnings 
    eval $code; # catches all "die" 
} 

o potremmo riaprire STDERR-/dev/null:

{ 
    # I know what I'm doing! 
    open my $oldSTDERR, '>&' \*STDERR or die; 
    close STDERR or die; 
    open STDERR, '>', '/dev/null' or die; 

    eval $code; 

    close STDERR or die; 
    open STDERR, '>&', $oldSTDERR or die; 
    close $oldSTDERR; 
} 
+1

Ma "eval $ code" non è permesso all'interno di un compartimento sicuro. Penso che anche impostare handler '$ SIG {}' sia proibito (e per una buona ragione).Anche l'impostazione di un gestore '$ SIG {}' al di fuori di 'reval' non sarà efficace. Penso che il reindirizzamento di STDERR sia probabilmente il kludge più pulito rispetto all'errore generato durante la compilazione del codice reval. L'avviso può essere schiacciato attraverso i mezzi normali, poiché si verifica al di fuori del reval. – DavidO

+0

La prima soluzione proposta da @amon funziona nel seguente codice: use strict; usare avvertenze; usare sicuro; usa la funzione qw/say /; my $ cft = Safe-> new; { local $ SIG {__ WARN__} = sub {}; my $ x = $ cft-> reval (') 1'); my $ y = $ cft-> reval ('2'); dire "x: $ x"; dire "y: $ y"; } Questo sembra essere esattamente quello che stavo cercando, grazie! – andrefs

+0

@andrefs Se questa risposta ha funzionato per te, ti preghiamo di "accettare" questa risposta per contrassegnare la tua domanda come "chiusa". – amon

Problemi correlati