Schrift
[thread]11249[/thread]

code innerhalb von {} (kA ^^)



<< >> 7 Einträge, 1 Seite
keksinat0r
 2008-02-05 20:00
#105599 #105599
User since
2008-02-05
3 Artikel
BenutzerIn
[default_avatar]
hi,

Ich bastel mit gereade einen Errorhandler, der spaeter eine Art Mischung aus CGI::Carp, eval und einem Ausgabepuffer werden soll.

und Zwar wuerde ich gerne soetwas bauen:

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/perl5.10.0

use strict;
use warning;

use lib '.';
use ErrorHandler;

ErrorHandler {

#der vermeindlich fehlerhafter Code

}

#weiterer fehlerfreier Code

__END__


Und zwar soll jetzt der Code innerhalb der {} in einem eval{} ausgefuehrt werden.
Desweiteren sollen alle Fehlermeldungen von einer extra Subroutine gehandhabt werden.
Alle Ausgaben (print) sollen nicht nach STDOUT geschickt werden, sondern sollen in einem Puffer landen.
Bei erfolgreichem Ausfuehern des Codes soll die Ausgabe nach STDOUT geschickt werden.
Bei Auftreten eines Fehlers soll der Fehler in eine externe log-Datei geschrieben,
und nach STDOUT eine Fehlermeldung geschickt werden.

Das ist eigentlich auch alles kein Problem:

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/bin/perl5.10.0

use strict;
use warnings;

sub Fatal {
push( @ErrorHandler::Error, join( '', @_ ) );
last ErrorHandler;
}

sub Warning {
push( @ErrorHandler::Error, join( '', @_ ) );
}

$main::SIG{__DIE__} = \&main::Fatal;
$main::SIG{__WARN__} = \&main::Warning;

ErrorHandler:eval{
#vermeindlich fehlerhafter Code
#alle Ausgaben werden anstatt mit "print" mit einer eigenen
#Subroutine gemacht, die die Ausgabe in $ErrorHandler::Buffer speichert
}

$main::SIG{__DIE__} = \&CORE::die;
$main::SIG{__WARN__} = \&CORE::warn;

# pruefen ob Fehler aufgetreten, wenn ja @ErrorHandler::Error
# in errorlog speichern und Fehlermeldung ausgeben. Wenn nein,
# $ErrorHandler::Buffer ausgeben


Wie man unschwer erkennen kann, ist erstere Loesung uebersichtlicher,
besser verstaendlich und besser zur Erstellung eines entsprechenden Modules geeignet.

Nur mein Problem ist jetzt, wie komme ich an den Code innerhalb von den {}?
Wenn ich es einfach so ausfuehre wie es oben (1. Bsp) steht fuehert er einfach den Code aus...
Ich moechte gern innerhalb der Subroutine "ErrorHandler" auf den Code innerhalb der {} zugreifen.

MFG - Keks :)
murphy
 2008-02-05 20:22
#105600 #105600
User since
2004-07-19
1776 Artikel
HausmeisterIn
[Homepage]
user image
Um das gewünschte Verhalten von ErrorHandler zu erreichen empfiehlt sich die Verwendung des & Prototypen. Irgendwie so sollte es gehen:
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
sub ErrorHandler(&) {
  my $block = shift;

  my $output = '';
  my $warnings = '';

  {
    local *STDOUT;
    tie *STDOUT, 'Some::Class::Collecting::The::Output', \$output;

    local $SIG{__WARN__} = sub {
      local $_ = shift;
      $warnings .= $_;
      $warnings .= "\n" unless (/\n$/);
    };

    eval {
      $block->();
    }
  }

  if ($@) {
    # handle the errors
  }
  elsif ($warnings) {
    # handle the warnings
  }
  else {
    print $output;
  }
}

When C++ is your hammer, every problem looks like your thumb.
keksinat0r
 2008-02-05 21:41
#105606 #105606
User since
2008-02-05
3 Artikel
BenutzerIn
[default_avatar]
hey danke fuer die schnelle Hilfe :)
Funktioniert super, bis auf die Umleitung der Ausgabe.. die will noch et so wirklich, aber das schaff ich auch alleine.

Hauptproblem war ja an den Code innerhalb der {} zu kommen :)

danke :)
ptk
 2008-02-05 22:20
#105607 #105607
User since
2003-11-28
3645 Artikel
ModeratorIn
[default_avatar]
Ein kleines syntaktisches Problem kann man nicht lösen: und zwar ist nach der schließenden Klammer zwingend ein Semikolon notwendig.
keksinat0r
 2008-02-05 23:23
#105609 #105609
User since
2008-02-05
3 Artikel
BenutzerIn
[default_avatar]
Joa, das kennt man ja schon von eval{} von daher ist das kein Problem ^^

Da ich gereade erfahren hab, dass ich morgen 2 Stunden spaeter aufstehen muss,
hab ich mich eben nochmal an meinen Errorhandler gesetzt...
Jetzt ist mir noch eine Idee gekommen:

Code (perl): (dl )
1
2
3
4
my $ErrorHandler = ErrorHandler -> new;
$ErrorHandler -> eval { 'der_evtl_fehlerhafte_code' };
print "STDOUT: " . $ErrorHandler -> stdout;
print "STDERR: " . $ErrorHandler -> stderr;


Hier wuerde dann STDOUT udn STDERR innerhalb des Handlers entsprechend umgeleitet
und ueber die Methoden stderr und stdout verfuegbar gemacht...
Das waere ziemlich praktisch :)

Leider scheitere ich gerade an der Umsetzung, denn wenn ich es oo-style mache, meckert der Compiler rum:
Code: (dl )
syntax error at ./index.cgi line 22, near "->eval {"


Er will die {} dann nichtmehr...

zZ sieht mein Code folgendermassen aus:
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
sub ErrorHandler (&) {

    my( $STDOUT, $STDERR );

    my $real_STDOUT = *STDOUT;
    my $real_STDERR = *STDERR;

    open( local_STDOUT, '>', \$STDOUT ); *STDOUT = *local_STDOUT;
    open( local_STDERR, '>', \$STDERR ); *STDERR = *local_STDERR;

    eval{ (shift)->() };

    my $error = $@;

    *STDERR = $real_STDERR; close( local_STDERR );
    *STDOUT = $real_STDOUT; close( local_STDOUT );

    push( @ErrorHandler::ErrorBuffer, $STDERR );

    if( $error ){
      die "an error occured!\n";
    }else{
      return $STDOUT;
    }

  }


Hier speichere ich alle Fehlermeldungen (landen ja alle auf STDERR) einfach in einem globalen Array "@ErrorHandler::ErrorBuffer", so kann ich von ueberall darauf zugreiffen.
Wenn ein Fehelr auftritt, wird eine Fehlermeldung ausgegeben, wenn alles gut geht, gibt die Funktion die Ausgabe des Codes zurueck.

Schoener waere hier aber die obere Alternative mit Objekt und Methode.
Kann man das irgendwie umsetzen?

MFG - Keks :)
murphy
 2008-02-06 00:14
#105610 #105610
User since
2004-07-19
1776 Artikel
HausmeisterIn
[Homepage]
user image
Ich glaube es ist ein generelles Problem, dass bei Subroutinen, die über die $object->method() Syntax aufgerufen werden, die Prototypen ignoriert werden :-(
When C++ is your hammer, every problem looks like your thumb.
ptk
 2008-02-06 00:35
#105613 #105613
User since
2003-11-28
3645 Artikel
ModeratorIn
[default_avatar]
Brauchst du nicht zu glauben. Es ist so.

Das liegt an der dynamischen Natur des OO-Systems in perl5. Welcher Code bei einem Methodenaufruf verwendet wird, wird dynamisch während der Laufzeit entschieden. Bei normalen Funktionsaufrufen ist es hingegegen möglich, schon während des Compilierens zu entscheiden, welche sub verwendet wird. Und somit ist es auch möglich, den richtigen Prototypen festzulegen.
<< >> 7 Einträge, 1 Seite



View all threads created 2008-02-05 20:00.