Open Source im professionellen Einsatz
Linux-Magazin 03/2005

Per Plugin erweiterbarer Viewer fürs persönliche Vermögen

Seid umschlungen, Millionen!

Das Perl-Skript »dagobert« zeigt auf Kommando die aktuellen Vermögensverhältnisse seines Besitzers an. Es rechnet den Inhalt mehrerer Konten und Aktiendepots zusammen und gestattet es dem Anwender, eigene Plugins einzuhängen.

1018

Entgegen früheren Erkenntnissen belegen neue sozialwissenschaftliche Studien: Reiche Menschen sind nicht unglücklicher als mittellose. Ein Aufatmen geht durchs Land - die Angst vor monetär bedingter Miesepetrigkeit ist weg. Viele trauen sich nach Jahren erstmals an eine Summation ihrer Vermögensverhältnisse. Aber wie ging das nur?

Wer nicht alles in bar unter den Dielen seiner Villa versteckt hat, sondern in Konten und Depots bei der Bank, greift zu Programmen wie Gnucash, die bei der Buchführung unterstützen und Kontostände sauber formatiert oder gar grafisch ausgeben. Doch verlangen die in der Tradition von Quicken und Microsoft Money stehenden freien Ableger eiserne Disziplin bei der Buchführung.

Aber welcher Freizeitbuchhalter hat die Zeit, minutiös alle Ausgaben einzutragen? Mal ganz abgesehen von der Installationsorgie, die Gnucash den Anwenderfreuden vorausschickt, birgt es eine weitere Hürde: Es ist nicht einfach und beliebig erweiterbar. Das vorgestellte Perl-Skript dient kleinen Dagoberts, die nur einmal im Monat zehn Minuten dafür erübrigen, Kontostände aufzufrischen, dann aber täglich mit online verfügbaren Börsenkursen ruck zuck ihr Hab und Gut in bare Münze umrechnen können.

Außerdem lässt sich das System per Plugin flexibel erweitern. Währungsumrechnungen oder Steuergesetze sind schnell eingearbeitet und der Benutzer passt das System an seine speziellen Bedürfnisse an, ohne gleich Bloatware zu erzeugen.

Freilich kann man\'s auch übertreiben: Für Aktiensplits, die sich alle paar Jahre mal ereignen, ist kein besonderes Modul erforderlich, die kann man auch von Hand korrigieren. (Motto: Wer jedermanns Liebling sein will, ist irgendwann jedermanns Depp.) Das Skript »dagobert« sucht den Mittelweg. Es bietet Basisfunktionen, die den Inhalt mehrerer Konten und Aktiendepots zusammenrechnen, überlässt es aber dem Anwender, Plugins für spezielle Anforderungen einzuhängen.

Skript als Interpreter

Kontendaten definiert der Anwender in einer Datei »money« nach Abbildung 1. Das Schlüsselwort »account« definiert ein neues Konto, eine Aktienposition startet mit »stock« und der Bargeldbestand mit »cash«. Der Interpreter dieser Finanzdaten ist »dagobert« aus Listing 1, der die Kontodefinitionen einliest, aktuelle Börsenkurse einholt und Gewinne, Verluste und Gesamtstand ausrechnet. Das Finanzskript lässt sich mit

dagobert money


aus der Kommandozeile aufrufen, aber es geht einfacher: Man macht die Konfigurationsdatei »money« ausführbar und hängt den »dagobert«-Interpreter in die She-Bang-Zeile. So läuft »money« als Skript ab, nicht mit »perl« als Interpreter, sondern mit »dagobert«.

Wer nicht gerade unter der hypermodernen Zsh-Shell arbeitet, sondern mit der guten alten Bash, die Skripte und Programme ohne Magie gleich vom Kernel ausführen lässt, muss aber in der She-Bang-Zeile auf Skripte verzichten. Stattdessen wird einfach schnell ein C-Wrapper in einem C-Programm »dago.c« herumgewickelt:

main(int argc, char **argv) {
    execv("/usr/bin/dagobert", argv); }


Kompiliert man »dago.c« jetzt mit

cc -o dago dago.c


dann lässt sich das Executable »dago« im She-Bang als Interpreter der Finanzdaten verwenden:

#!/usr/bin/dago

account DeutscheBank
  stock SIEGn.DE 10 62.38
  # ...


Falls nun die diesen Code enthaltende Datei »money« ausführbar ist, genügt der Aufruf »money« - und der Geldzähler startet. Was eigentlich aussieht wie eine Konfigurationsdatei, ist in Wirklichkeit ein ausführbares Skript. Abbildung 2 zeigt die Ausgabe. Praktisch!

Abbildung 1: Die Daten des Kontoinhabers definiert eine Konfigurationsdatei, die gleichzeitig ein ausführbares Skript ist.

Listing 1:
»dagobert«

01 #!/usr/bin/perl -w
02 ###########################################
03 # dagobert - Money Counting Interpreter
04 # Mike Schilli, 2004 (m@perlmeister.com)
05 ###########################################
06 use strict;
07 
08 use Plugger;
09 my $string = join '', <>;
10 
11 my $plugger = Plugger->new();
12 $plugger->init();
13 $plugger->parse($string);

Abbildung 2: Geldzähler »dagobert« in Aktion: Von der Kommandozeile aus aufgerufen zeigt er Einzelkonten und Gesamtvermögen farbig angehübscht an.

Interpreter lernt durch Plugins dazu

Der Interpreter in Listing 1 ist sehr kurz gehalten: Er erzeugt eine neue Instanz eines Objekts vom Typ »Plugger«, initialisiert die dahinter liegende Plugin-Architektur mit »init()« und übergibt die zuvor mit »<>« von der Standardeingabe eingelesenen Konfigurationsdaten der »parse()«-Methode des Plugin-Systems. Das Framework in Listing 2 interpretiert das jeweils erste Wort einer Zeile als Kommando. Ohne Plugins ist es jedoch erst mal nicht in der Lage, irgendein Kommando zu interpretieren. Lediglich Kommentarzeilen, die mit einem »#« beginnen, verwirft es vorsorglich.

Listing 2:
»Plugger.pm«

01 ###########################################
02 package Plugger;
03 ###########################################
04 use strict; use warnings;
05 
06 use Module::Pluggable
07   require     => 1,
08   search_path => [qw(Plugger)];
09 
10 our %DISPATCH = ();
11 our %MEM      = ();
12 
13 ###########################################
14 sub new {
15 ###########################################
16     my($class) = @_;
17 
18     bless my $self = {}, $class;
19 
20     return $self;
21 }
22 
23 ###########################################
24 sub init {
25 ###########################################
26     my($self) = @_;
27 
28     $_->init($self) for $self->plugins();
29 }
30 
31 sub mem { return %MEM; }
32 
33 ###########################################
34 sub parse {
35 ###########################################
36     my($self, $string) = @_;
37 
38     for(sort keys %DISPATCH) {
39         $DISPATCH{$_}->{start}->($self) if
40             $DISPATCH{$_}->{start};
41     }
42 
43     for(split /n/, $string) {
44 
45         s/#.*//;
46         next if /^s*$/;
47         last if /^__END__/;
48         chomp;
49 
50         my($cmd, @args) = split ' ', $_;
51 
52         die "Unknown command: $cmd" unless
53             exists $DISPATCH{$cmd};
54 
55         $DISPATCH{$cmd}->{process}->($self,
56                               $cmd, @args);
57     }
58 
59     for(sort keys %DISPATCH) {
60         $DISPATCH{$_}->{finish}->($self) if
61             $DISPATCH{$_}->{finish};
62     }
63 }
64 
65 ###########################################
66 sub register_cmd {
67 ###########################################
68     my($self, $cmd, $start,
69        $process, $finish) = @_;
70 
71     $DISPATCH{$cmd} = {
72         start   => $start,
73         process => $process,
74         finish  => $finish,
75     };
76 }
77 
78 1;

»Plugger.pm« liest jedes zum Verzeichnis »Plugger/« hinzugefügte Modul während der Compile-Phase automatisch ein. Dies erledigt das in Zeile 6 eingebundene CPAN-Modul Module::Pluggable, denn die Zeilen 7 und 8 setzen dessen »require«-Flag und den Suchpfad zu den Plugins relativ zum aktuellen Verzeichnis oder zum »@INC«-Pfad.

Die Plugins haben keinen »new()«-Konstruktor, wie in der Objektorientierung eigentlich üblich, sondern eine »init()«-Funktion, die »Plugger.pm« als Herr aller Plugins für jedes gefundene Plugin-Modul nacheinander aufruft. Module::Pluggable fügt in seinen Wirt - »Plugger« in diesem Fall - automatisch die Methode »plugins()« ein. Sie gibt die Namen aller gefundenen Plugins als Liste zurück. Zeile 28 nutzt diesen Mechanismus, um durch die »init()«-Funktionen aller Plugins zu orgeln.

Damit ein Plugin weiß, wer der Aufrufer ist und gegebenenfalls dessen Methoden aufruft, übergibt »Plugger.pm« der »init()«-Methode des Plugins jeweils die Referenz » (von Context). Dahinter steckt nichts anderes als eine Referenz auf das einzige existierende Plugger-Objekt, den Plugin-Verwalter. Damit vermag ein Plugin nun seinerseits Anweisungen an den Verwalter »Plugger« zu schicken. Da »Plugger« die Kommandos in einer Konfigurationsdatei interpretiert, ruft das Plugin die Verwalter-Methode »register_cmd()« auf, um neue Kommandos zu registrieren.

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • Heilig nach Punkten

    Der Instant-Messenger-Client Gaim spricht nicht nur viele Protokolle, sondern lässt sich auch noch mit Perl-Plugins erweitern. Eines versetzt sogar Atheisten in die Lage, katholisch aufzusteigen.

  • Top in Form

    Den Datenverkehr im eigenen Netzwerk nicht nur überwachen, sondern detailliert auswerten - bei dieser Aufgabe hilft Ntop. Mit den gewonnenen Einblicken hält der Admin sein Netz in Form.

  • Thunderbird 3 im Anflug - Linux-Tester gesucht

    Während Firefox 3 mit Download-Rekorden prahlt, lässt die dritte Version von Thunderbird noch auf sich warten.

  • Sicher im Web 2.0: Eben Moglen gründet Freedom Box Foundation

    Die neu gegründete Freedom Box Foundation unter Leitung des Juristen Eben Moglen will mit ihrem Kompaktserver zum Schutz der Privatsphäre im Internet beitragen.

  • SIM-IDS mit Prelude

    Das hybride Security-Information-Management-System (SIM) Prelude empfängt sowohl Host- als auch Netzwerk-basierte IDS-Meldungen und zeigt diese in einem übersichtlichen Webinterface an. Selbst komplexe, korrelierte Alarme von unterschiedlichen Endgeräten mit eigenen Plugins sind da kein Problem.

comments powered by Disqus

Ausgabe 07/2017

Digitale Ausgabe: Preis € 6,40
(inkl. 19% MwSt.)

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.