=head1 NAME SuikaWiki::Plugin - SuikaWiki: WikiPlugin common interface =head1 DESCRIPTION This module provides WikiPlugin interface implementation. There are two interface: class methods collection and WikiPlugin object. Class methods collection provides some useful facilities to be called by WikiPlugin module and/or by contexts using WikiPlugin. This module is part of SuikaWiki. =cut package SuikaWiki::Plugin; use strict; our $VERSION = do{my @r=(q$Revision: 1.17 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r}; =head1 CLASS METHODS =over 4 =item $formatter = SuikaWiki::Plugin->formatter ($category_name) Returns an instance of formatter whose category (context) is $category_name. =cut {my %Formatter; sub formatter ($$) { my $t = $_[1]; $t =~ tr/-/_/; unless ($Formatter{$t}) { $Formatter{$t} = new SuikaWiki::Plugin::xml_formatter -category_name => $t; } return $Formatter{$t}; }} {my %Formatter; sub text_formatter ($$) { my $t = $_[1]; $t =~ tr/-/_/; unless ($Formatter{$t}) { $Formatter{$t} = new SuikaWiki::Plugin::text_formatter -category_name => $t; } return $Formatter{$t}; }} {my %Formatter; sub boolean_formatter ($$) { my $t = $_[1]; $t =~ tr/-/_/; unless ($Formatter{$t}) { $Formatter{$t} = new SuikaWiki::Plugin::boolean_formatter -category_name => $t; } return $Formatter{$t}; }} =item $package = SuikaWiki::Plugin->module_package ($plugin_name) Returns package name of the plugin module named $plugin_name. =cut ## NOTE: Fix mkplugin2.pl when modify this function. sub module_package ($$;%) { my ($self, $module, %opt) = @_; my $pack = $SuikaWiki::Plugin::Registry::Info{$module}->{module_name}; if ($pack) { return $pack; } elsif (not $opt{allow_undef}) { throw SuikaWiki::Plugin::error -type => 'PLUGIN_NOT_FOUND', module => $module, -object => $self, method => 'module_package'; } else { return undef; } } =item SuikaWiki::Plugin->load_directory ($dir1, $dir2,...) Loads plugin modules in specified directories. =cut sub load_directory ($;@) { my $self = shift; for my $dir (@_) { opendir PDIR, $dir or throw SuikaWiki::Plugin::error -type => 'PLUGIN_DIRECTORY_CANT_OPEN', file => $dir, message => $!, -object => $self, method => 'load_directory'; for (grep {substr ($_, -3) eq '.pm'} readdir PDIR) { eval { require $dir.'/'.$_ }; if ($@) { throw SuikaWiki::Plugin::error -type => 'PLUGIN_COMPILE_ERROR', file => $dir.'/'.$_, message => $@, method => 'load_directory', -object => $self; } } closedir PDIR; } } sub load_file ($@) { my $self = shift; for (@_) { eval { require $_.'.pm' }; if ($@) { throw SuikaWiki::Plugin::error -type => 'PLUGIN_COMPILE_ERROR', file => $_.'.pm', message => $@, method => 'load_file', -object => $self; } } } =back =head1 WIKIPLUGIN MANAGER OBJECT This part implements WikiPlugin manager object of SuikaWiki WikiPlugin implementation model, second edition. Note that class methods such as C<< ->load_directory >> and C<< ->formatter >> as also available as methods of WikiPlugin object, although result of those operation is still "global". WikiPlugin manager object is usually instantiated by C method of Wiki implementation object (C module). $wiki = ; $wiki->init_plugins; $plugin_manager = $wiki->{plugin}; =over 4 =item $p = SuikaWiki::Plugin->new (wiki => $WIKI) Constructs new instance of WikiPlugin manager =cut sub new ($;%) { my $class = shift; bless {@_}, $class; } sub exit ($) { my $self = shift; delete $self->{wiki}; $self->{exited} = 1; } sub DESTROY ($) { my $self = shift; $self->exit unless $self->{exited}; } =item $p->{wiki} Wiki implementation $p is associated with =back =cut package SuikaWiki::Plugin::xml_formatter; require Message::Util::Formatter::Node; our @ISA = 'Message::Util::Formatter::Node'; require Message::Markup::XML::Node; sub ___rule_def ($) { $SuikaWiki::Plugin::Rule{$_[0]->{-category_name}} || {}; } sub replace_option () {+{ -class => 'Message::Markup::XML::Node', }} package SuikaWiki::Plugin::text_formatter; require Message::Util::Formatter::Text; our @ISA = 'Message::Util::Formatter::Text'; sub ___rule_def ($) { $SuikaWiki::Plugin::Rule{$_[0]->{-category_name}} || {}; } package SuikaWiki::Plugin::boolean_formatter; require Message::Util::Formatter::Boolean; our @ISA = 'Message::Util::Formatter::Boolean'; sub ___rule_def ($) { $SuikaWiki::Plugin::Rule{$_[0]->{-category_name}} || {}; } package SuikaWiki::Plugin::error; require Message::Util::Error; our @ISA = 'Message::Util::Error'; =head1 EXCEPTIONS =over 4 =item PLUGIN_COMPILE_ERROR Something wrong while loading WikiPlugin module file C, because of C. =item PLUGIN_DIRECTORY_CANT_OPEN WikiPlugin directory C cannot be opened, because of C. =item PLUGIN_NOT_FOUND WikiPlugin module C not found. =cut sub ___error_def () {+{ PLUGIN_COMPILE_ERROR => { description => q(%t(name => method);: %t(name => file);: %t(name => message);), }, PLUGIN_DIRECTORY_CANT_OPEN => { description => q(%t(name => method);: %t(name => file);: %t(name => message);), }, PLUGIN_NOT_FOUND => { description => q(%t(name => method);: WikiPlugin module "%t(name => module);" not loaded), }, }} =back =head1 SEE ALSO C, C =head1 LICENSE Copyright 2002-2003 Wakaba This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; # $Date: 2004/07/25 06:54:29 $