Die ganzen Vorschläge die gemacht wurden haben leider (so wie ich das sehe) den grossen Haken, dass der Namensraum des Moduls/Plugins bekannt sein muss, um es anzusprechen, oder das zumindest im Hauptprogramm eine entsprechende Zeile hinzugefügt werden muss, um jeden einzelne PlugIn anzusprechen.
Ich hab in der zwischenzeit mal meine eigene Api zusammengebastelt. Ist noch nicht ganz fertig, sieht aber in etwa so aus:
Das Hauptprgramm, also die API:
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
sub GetPluginList{
# array fuer die hashreferenzen auf die plugindaten
my ( @plugins ) = GetPluginFromDir( 'plugins', '1' );
my $i;
for my $plugin ( @plugins ){
$i++;
print "\n Name: ".$plugin->{pluginname};
print "\n Version: ".$plugin->{version};
my $ref = $plugin->{'funktionen'};
for( keys %$ref ) {
print "\n Funktion: ".$_;
print "\n -->Rueckgabe: ";
print eval "$plugin->{package}::$_";
}
}
}
sub GetPluginFromDir{
# uebergeben wird der directory-path
my $directory = $_[0];
# die on error
die 'Not enough arguments to get Plugin.' if ! $directory;
# ist diese var gesetzt, werden auch unterverzeichnisse
# bis zu dieser Tiefe mit verarbeitet
my $tiefe = $_[1];
# enthaelt und uebergibt den gefunden plugin
my ( @plugins );
# die plugindirectory darf fuer jeden plugin
# ein eigenes verzeichnis mit allen templates
# etc. enthalten.
opendir( PLUGINS, $directory ) ||
die 'Can´t open Plugindirectory: ' . $directory;
for ( readdir( PLUGINS ) ){
# es werden nur verzeichnisse und .pl files gelesen.:
# weiter wenns uebergeordnete verzeichnisse sind
next if $_ =~ m|^\.+|;
my $fullpath = $directory . '/' . $_;
# diese routine rekursiv aufrufen, wenns ein verzeichnis
# ist und die tiefe mindestens 1 betraegt
if ( -d $fullpath && $tiefe >= 1 ){
# resttiefe fuer den naechsten aufruf um 1 tiefer setzen
my $resttiefe = $tiefe-1;
push( @plugins, GetPluginFromDir( $fullpath, $resttiefe ) );
}
# weiter wenns kein plugin ist
next if $_ !~ m|\.pl$|i;
# plugin validieren oder bei fehler einfach ueberspringen
my $pluginhashref = ValidatePlugin( $fullpath ) || next;
push( @plugins, $pluginhashref );
}
closedir PLUGINS;
return ( @plugins );
}
# pruefen der gueltigkeit des plugins
sub ValidatePlugin{
my $fullpath = $_[0];
my %pluginfo;
# plugin laden, rueckgabewert des moduls ist der namensraum
require $fullpath;
%pluginfo = &PlugIn::init;
# abbrechen und NULL zurückgeben, wenn nicht
# die mindestinfos zurueckgeliefert wurden
return undef if ! $pluginfo{'pluginname'};
return undef if ! $pluginfo{'version' };
return undef if ! $pluginfo{'package' };
return undef if ! $pluginfo{'package' };
return \%pluginfo;
}
und so sieht etwa ein PlugIn aus:
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package PlugIn;
sub init{ &HuhnPlugIN::PluginInfo() }
package HuhnPlugIN;
my $PACKAGE = 'HuhnPlugIN';
my $PLUGINNAME = 'HuhnPlugIN';
my $VERSION = '0.1';
# init() wird nach dem require aufgerufen und gibt den namen,
# die version und einen link zurueck
sub PluginInfo{
my %link;
# links werden folgendermassen definiert:
# der schluessel ist der name der funktion,
# der wert der link der aufgerufen wird.
# es koennen beliebig viele funktionen/links
# deklariert werden.
$link{ 'TestFunk' } = 'TestFunk';
# anhaengen des packagenamens an jeden link
for ( keys %link ){ $_ .= 'plugin=' . $PACKAGE }
# das hauptprogramm erhaelt die rueckgabewerte
# und erstellt fuer jeden eintrag im link-hash
# einen link in der pluginrubrik
# felder mit einem * sind optional, alle anderen
# felder muessen vorhanden sein, sonst wird's
# plugin nicht validiert und fliegt raus
return( 'pluginname' => $PLUGINNAME,
'package' => $PACKAGE,
'version' => $VERSION,
'menubutton' => \%link,
'folder' => '', # *
);
}
# PLUGIN Funktionen >>
sub TestFunk{
return "Huhn ist nicht Hase";
}
Ist wie gesagt noch nicht fertig, sondern erst mal ein Grundmodell... aber funktionstüchtig.
Die PlugIns liegen hierbei im Ordner Plugins, entweder direkt da, oder in einem Unterordner, wie mans lieber mag.
Eine registrierung der PlugIns an einer anderen Stelle ist nicht notwendig, was mir sehr wichtig ist.
Nachdem einbinden mit require und Prüfung auf validität, wird die Funktion init() aufgerufen, die in jedem Plugin im Namensraum PlugIn vorhanden ist.
Die Funktion init() ruft eine Funktion im Namensraum des PlugIns auf und liefert den Namensraum des PlugIns, sowie Name, Version und enthaltene Funktionen zurück.
So nun seid Ihr dran ;-) Was gibt's zu meckern? Wo könnt man's verbessern?
Ich bin der Meinung, damit hat man eine gute Mischung aus skalierbarkeit, nutzerfreundlichkeit und eweiterbarkeit, da so einfach Perlprogramme geschrieben und eingebunden werden könne , solang' die (wenigen) Vorgaben beachtet werden.
Gruss
Stefan\n\n
<!--EDIT|Magic|1089129046-->
Ein Weiser gibt nicht die richtigen Antworten, sondern er stellt die richtigen Fragen.