Wie kann ich um einen ‚sterben‘ Anruf in einer Perl-Bibliothek kann ich nicht ändern?

StackOverflow https://stackoverflow.com/questions/451227

  •  19-08-2019
  •  | 
  •  

Frage

Ja, das ist das Problem mit einer Bibliothek Ich verwende, und nein, ich kann es nicht ändern. Ich brauche eine Abhilfe.

Grundsätzlich bin ich mit einem schlecht geschriebenen Perl-Bibliothek zu tun, die mit ‚sterben‘ beendet, wenn eine bestimmte Fehlerbedingung eine Datei gefunden zu lesen. Ich nenne diese Routine aus einem Programm, das durch Tausende von Dateien, eine Handvoll von denen Looping ist schlecht. Bad Dateien geschehen; Ich will nur meine Routine einen Fehler protokollieren und bewegen.

Wenn ich die Bibliothek ändern könnte, würde ich einfach das ändern

die "error";

a

print "error";return;

, aber ich kann es nicht. Gibt es eine Möglichkeit kann ich Couch die Routine, so dass die schlechten Dateien werden den gesamten Prozess nicht abstürzen?

Followup FRAGE: eine „eval“ auf der Couch den Absturz anfälligen Anruf Mit funktioniert gut, aber wie kann ich in diesem Rahmen für Fang-able Fehlerbehandlung auf? Um zu beschreiben:

Ich habe ein Unterprogramm, das die Bibliothek-which-Abstürze-manchmal oft aufruft. Anstatt Couch in diesem Unterprogramm jeden Anruf mit einem eval {}, ich erlaube es nur zu sterben, und verwenden Sie ein eval {} auf das Niveau, das mein Unterprogramm aufruft:

my $status=eval{function($param);};
unless($status){print $@; next;}; # print error and go to next file if function() fails

Es gibt jedoch Fehlerbedingungen, die ich kann und in Funktion fangen Sie (). Was ist die richtige / elegante Art und Weise des Fehler Fang im Unterprogramm und die Aufrufroutine so zu gestalten, dass ich das richtige Verhalten für beide gefangen und nicht abgefangene Fehler bekommen?

War es hilfreich?

Lösung

Sie können es in einem eval wickeln. Siehe auch:

perldoc -f eval

Zum Beispiel könnten Sie schreiben:

# warn if routine calls die
eval { routine_might_die }; warn $@ if $@;

Dies wird den fatalen Fehler in eine Warnung drehen, die mehr oder weniger das, was Sie vorgeschlagen. Wenn die genannt wird, $@ enthält die Zeichenfolge an sie übergeben.

Andere Tipps

Ist es Falle $SIG{__DIE__}? Ist dies der Fall, dann ist es mehr lokale, als Sie sind. Aber es gibt ein paar Strategien:

  • Sie können ihr Paket evozieren und außer Kraft setzen sterben:

    package Library::Dumb::Dyer;
    use subs 'die';
    sub die {
        my ( $package, $file, $line ) = caller();
        unless ( $decider->decide( $file, $package, $line ) eq 'DUMB' ) {
            say "It's a good death.";
            die @_;
       }
    } 
    
  • Wenn nicht, können href="http://perldoc.perl.org/perlvar.html" rel="noreferrer"> Falle es

    my $old_die_handler = $SIG{__DIE__};
    sub _death_handler { 
        my ( $package, $file, $line ) = caller();
        unless ( $decider->decide( $file, $package, $line ) eq 'DUMB DIE' ) {
            say "It's a good death.";
            goto &$old_die_handler;
        }
    }
    $SIG{__DIE__} = \&_death_handler;
    
  • Sie können die Bibliothek zu scannen haben, eine Unter finden, dass es immer Anrufe, und verwenden Sie, dass Ihre $SIG Handler durch zwingende that zu laden.

    my $dumb_package_do_something_dumb = \&Dumb::do_something_dumb;
    *Dumb::do_something_dumb = sub { 
        $SIG{__DIE__} = ...
        goto &$dumb_package_do_something_dumb;
    };
    
  • oder eine builtin außer Kraft setzen, dass es immer ruft ...

    package Dumb; 
    use subs 'chdir';
    sub chdir { 
        $SIG{__DIE__} = ...
        CORE::chdir @_;
    };
    
  • Wenn alle Stricke reißen, können Sie das Pferd Augen mit dieser Peitsche:

    package CORE::GLOBAL;
    use subs 'die';
    
    sub die { 
        ... 
        CORE::die @_;
    }
    

Dies wird außer Kraft setzen die global, der einzige Weg, wieder die bekommen kann, ist es als CORE::die zu adressieren.

Einige Kombination von dies funktionieren wird.

Obwohl ein die Ändern sterben nicht eine bestimmte Lösung hat wie in der allgemeinen in den anderen Antworten, gezeigt können Sie immer außer Kraft setzen Subroutinen in anderen Paketen. Sie haben nicht die ursprüngliche Quelle überhaupt ändern.

Laden Sie zuerst das ursprüngliche Paket, so dass Sie alle ursprünglichen Definitionen erhalten. Sobald das Original an seinem Platz ist, können Sie das lästige Unterprogramm neu zu definieren:

 BEGIN {
      use Original::Lib;

      no warnings 'redefine';

      sub Original::Lib::some_sub { ... }
      }

Sie können sogar die ursprüngliche Definition ausschneiden und einfügen und optimieren, was Sie brauchen. Es ist nicht eine große Lösung, aber wenn Sie nicht die ursprüngliche Quelle ändern können (oder wollen, etwas versuchen, bevor Sie das Original aus), kann es funktionieren.

Außerdem können Sie die Originaldatei in ein separates Verzeichnis für Ihre Anwendung kopieren. Da Sie das Verzeichnis steuern, können Sie die Dateien darin bearbeiten. Sie diese Kopie ändern und laden, indem Sie das Verzeichnis in der Perl-Modul-Suchpfad hinzufügen:

use lib qw(/that/new/directory);
use Original::Lib;  # should find the one in /that/new/directory

Ihre Kopie Sticks um selbst wenn jemand das ursprüngliche Modul aktualisiert (obwohl Sie Änderungen zusammenführen müssen, könnten).

Ich spreche über diese ziemlich viel in Mastering Perl , wo ich zeigen einige andere Techniken zu tun diese Art von Ding. Der Trick ist, die Dinge nicht noch mehr zu brechen. Wie Sie die Dinge nicht brechen hängt davon ab, was Sie tun.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top