2010-06-18 5 views
2

Ce code sent ... comment est-ce que je le réécris mieux?Comment réécrire ce bloc eval

my $record; 

eval { 
    while (
     # undef $record here, so if getRecord() failed, nothing will be written 
     # in the reject file 
     do { undef $record; defined($record = $dataFile->getRecord) } 
    ) { 
     $LT_DataFile->encode($record); 
    } 
    1; 
}; 

if (my $error = [email protected]) { 
    $rejectFile->writeRecord($error, $record); 
} 

Merci.

Répondre

2

Ok, retravaillé ma réponse.

Je pense que le problème REAL est comment vous gérez les erreurs. Il est déroutant à première vue de voir un gestionnaire d'erreur unique lorsque vous avez plusieurs endroits où les choses pourraient mal tourner. Je vois deux alternatives.

D'abord, garder la plupart du temps la même chose que vous avez maintenant, mais il faut vérifier spécifiquement pour chaque type d'erreur:

my $record; 
eval { 
    while (defined($record = $dataFile->getRecord)) { 
     $LT_DataFile->encode($record); 
    } 
}; 
if (my $error = [email protected]) { 
    given ($error) { 
     when (/get record error/) { $rejectFile->writeRecord($_, undef); } 
     when (/encode error/)  { $rejectFile->writeRecord($_, $record); } 
    } 
} 

De cette façon, vous êtes explicite dans la façon dont vous gérez vos erreurs. Bien sûr, avec Try :: minuscule, cela simplifie les éléments suivants dans

my $record; 
try { 
    while (defined($record = $dataFile->getRecord)) { 
     $LT_DataFile->encode($record); 
    } 
} catch { 
    when (/get record error/) { $rejectFile->writeRecord($_, undef); } 
    when (/encode error/)  { $rejectFile->writeRecord($_, $record); } 
} 

Sinon, vous pouvez ajouter l'enregistrement lexical par Daxim's answer. Cela nécessite une seconde eval ou d'essayer, plus près du problème et l'ajout d'un appel last:

eval { 
    while (defined(my $record = $dataFile->getRecord)) { 
     eval { $LT_DataFile->encode($record) }; 
     if (my $error = [email protected]) { $rejectFile->writeRecord($error, $record); last } 
    } 
}; 
if (my $error = [email protected]) { 
    $rejectFile->writeRecord($error, undef); 
} 

Malheureusement, cette méthode ne fonctionnera pas avec Try :: minuscule, parce que les blocs sont passés à essayer subrefs réellement.

+0

Mais vous avez ignoré le commentaire expliquant pourquoi '$ record' doit être' undef'. Si 'getRecord' renvoie une erreur, vous signalez l'enregistrement précédent (non erroné). – cjm

+0

Derp, en effet. Fixé. –

+0

Et maintenant vous avez le problème inverse. Si 'encoder' renvoie une erreur, vous rapporterez' undef' à la place de l'enregistrement qui a provoqué l'erreur. – cjm

8

Vous n'avez pas besoin d'une variable dans la partie de capture car lorsque l'exécution arrive, son contenu sera toujours undef. Remplacer cela par une valeur littérale permet de restreindre $record à une portée plus petite.

use Try::Tiny; 
try { 
    while (defined(my $record = $dataFile->getRecord)) { 
     $LT_DataFile->encode($record); 
    } 
} catch { 
    $rejectFile->writeRecord($_, undef); # T::T puts error in $_ 
} 
+1

+1 pour Try :: Tiny. Pour @est, faire le 'eval' et tester séparément' $ @' peut causer des problèmes (erreurs manquées, messages d'erreur incorrects) dans certains cas, car '$ @' est global. Utilisez plutôt Try :: Tiny car il gère tous ces détails pour vous. –

+4

Pourquoi dites-vous que $ record' serait toujours 'undef' s'il y a une erreur? On peut supposer que la méthode 'encoder 'est capable de lancer des erreurs, et dans ce cas' $ record' serait l'enregistrement qui a provoqué l'erreur de codage. C'est seulement 'undef' si' getRecord' est la méthode qui a échoué. – cjm

+0

Si $ record est un objet, alors vous pouvez laisser tomber 'defined', et vérifier la vérité:' while (mon $ record = ...)}} ' – Ether

2

je serais factoriser la boucle while à

while (defined($record = $dataFile->getRecord)) { 
    $LT_DataFile->encode($record); 
} continue { 
    undef $record; 
} 

Le bloc continue est exécuté après chaque itération avant est testée conditionnelle. Il sera toujours appelé si votre code utilise next pour démarrer la prochaine itération tôt. Si vous n'êtes pas susceptible d'appeler next simplifiant alors le code à

while (defined($record = $dataFile->getRecord)) { 
    $LT_DataFile->encode($record); 
    undef $record; 
} 

fonctionnerait aussi bien.

+0

Cela ne fonctionnera pas comme prévu .... quand $ dataFile-> getRecord() renvoie une exception, $ record a déjà la valeur de l'itération précédente, donc $ rejectFile-> writeRecord() reçoit la mauvaise information. – est

+0

@est comment? L'appel do 'undef $ record;' sera toujours appelé avant le conditionnel dans l'itération suivante de la boucle. Si '$ dataFile-> getRecord()' meurt alors '$ record' est undef. Toute action qui ignorera le bloc 'continue' mettra fin à la boucle ou ignorera le conditionnel. En supposant que $ record n'est pas défini avant la première itération, $ record sera toujours indéfini quand $ dataFile-> getRecord est appelé et toujours défini quand $ LT_DataFile-> encoder ($ record); . –