Skip to content

Commit

Permalink
Item14237: Finished documenting extension manager
Browse files Browse the repository at this point in the history
  • Loading branch information
vrurg committed Sep 23, 2017
1 parent 8e90e55 commit 6a84c9f
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 24 deletions.
127 changes: 113 additions & 14 deletions core/lib/Foswiki/ExtManager.pm
Expand Up @@ -112,7 +112,7 @@ list of extensions topological sorting algorithm is used. If a circular
dependency is encountered in a chain of extension dependencies, the whole chain
is disabled. (See the note below)
*NOTE:* Currently =extAfter= and =extBefore= are been considered 'dependencies'.
*%X% NOTE:* Currently =extAfter= and =extBefore= are been considered 'dependencies'.
It means that if for a reason _Ext2_ is disabled then _Ext1_, which is depending
on it, will be disabled too. This behavior is temporary and is a subjuect to
change making these two subs used for merely declaring the order and nothing
Expand Down Expand Up @@ -227,6 +227,16 @@ all be built using =[[CPAN:Moo::Role][Moo::Role]]=.
More implementation details are in the code of =prepareRegisteredClasses()=
method.
#PluggableMethods
---+++ Pluggable Methods
Alongside with subclassing there is a less radical method of redefining core
behavior. It is called 'pluggable methods' and it depends on the good will of
a core class which can declare itself an _extensible_ (see =Foswiki::Class=).
With this modifier it acquires the power of declaring some of its methods
as _pluggables_. A pluggable method is extensions' plaything. But more details
on this subject can be found in =Foswiki::Extension::Empty= documentation.
=cut

use File::Spec ();
Expand Down Expand Up @@ -261,8 +271,8 @@ our $MIN_VERSION = version->declare("2.99.0");
# extensions are built.
# NOTE All data stored in globals is raw and must be revalidated before used.
our @extModules
; # List of the extension modules in the order they were registered with registerExtModule().
our %registeredModules; # Modules registered with registerExtModule().
; # List of the extension modules in the order they were registered with _registerExtModule().
our %registeredModules; # Modules registered with _registerExtModule().
our %extSubClasses; # Subclasses registered by extensions.
our %extDeps; # Module dependecies; defines the order of extensions.
our %extTags; # Tags registered by extensions.
Expand Down Expand Up @@ -334,7 +344,7 @@ locating extension by their =.pm= files.
*Example:* if an extension is referred by its short name _Ext1_ then internaly
it will be normalized and the full form _Foswiki::Extension::Ext1_ will be used.
*NOTE:* Changing this attribute will most likely break loading of standard
*%X% NOTE:* Changing this attribute will most likely break loading of standard
extensions. Though it could be useful for testing/debugging.
=cut
Expand Down Expand Up @@ -641,7 +651,7 @@ sub _loadExtModule {

try {
Foswiki::load_class($extModule);
registerExtModule($extModule);
_registerExtModule($extModule);
}
catch {
Foswiki::Exception::Ext::Load->rethrow(
Expand Down Expand Up @@ -1027,7 +1037,7 @@ sub prepareExtSubDirs {
Returns extensions disabled for this installation or host. %disabled hash keys
are extension names, values are text reasons for disabling the extension.
*NOTE* Extension =Foswiki::Extension::Empty= is hard coded into the list of
*%X% NOTE:* Extension =Foswiki::Extension::Empty= is hard coded into the list of
disabled extensions because its purpose is to be a template for developing
functional extensions.
Expand Down Expand Up @@ -1380,6 +1390,20 @@ sub _callPluggable {

=begin TML
---+++ StaticMethod isRegistered( $extModule ) => $registered
Returns _true_ if =$extModule= is already registered with the core.
=cut

sub isRegistered {
my ($extModule) = @_;

return $registeredModules{$extModule} // 0;
}

=begin TML
---+++ StaticMethod extName( $extFullName )
Returns extension's name. The name is either the part of extension's module
Expand Down Expand Up @@ -1415,6 +1439,16 @@ sub extName {

=begin TML
---++ Registration methods
Registration methods though publicly available but are not recommended for
end-user code and mostly intended to support corresponding shortcuts in
=Foswiki::Class=.
=cut

=begin TML
---+++ StaticMethod registerSubClass( $extModule, $class, $subClass )
Registers a sub-class =$subClass= for =$class= by extension =$extModule=.
Expand All @@ -1432,7 +1466,9 @@ registerSubClass(
);
</verbatim>
See =[[?%QUERYSTRING%#SubClassing][Subclassing]].
Shortcut: =extClass=
See [[?%QUERYSTRING%#SubClassing][Subclassing]].
=cut

Expand All @@ -1446,13 +1482,38 @@ sub registerSubClass {
};
}

sub registerExtModule {
=begin TML
---+++ StaticMethod _registerExtModule( $module )
Creates a record about a recently loaded extension module.
For internal use.
=cut

sub _registerExtModule {
my ($extModule) = @_;

push @extModules, $extModule;
$registeredModules{$extModule} = 1;
}

=begin TML
---+++ StaticMethod registerExtTagHandler( $extModule, $tagName [, $tagClass] )
Registers a tag named =$tagName= for extension =$extModule=. If =$tagClass= is
passed in then it's interpreted as a macro class (the one which consumes
=Foswiki::Macro= role; see =registerTagHandler()= method in =Foswiki::Macros=).
If =$tagClass= is not used then the extension must have a method named after
=$tagName=.
Shortcut: =tagHandler=
=cut

sub registerExtTagHandler {
my ( $extModule, $tagName, $tagClass ) = @_;

Expand All @@ -1463,6 +1524,16 @@ sub registerExtTagHandler {
};
}

=begin TML
---+++ StaticMethod registerExtCallback( $extModule, $cbName, $cbCode )
Registers extension's code =$cbCode= as a handler for callback =$cbName=.
Shortcut: =callbackHandler=
=cut

sub registerExtCallback {
my ( $extModule, $cbName, $cbCode ) = @_;

Expand All @@ -1473,6 +1544,16 @@ sub registerExtCallback {
};
}

=begin TML
---+++ StaticMethod registerDeps( $extModule, @deps )
With this method we register what extensions must go before =$extModule=.
Shortcuts: =extAfter=, =extBefore=
=cut

# TODO Rename deps (dependencies) into something order-related as extBefore
# and extAfter shall only declare wishful order. For real dependecies more
# strict extRequire must be introduced.
Expand All @@ -1482,6 +1563,18 @@ sub registerDeps {
push @{ $extDeps{$extModule} }, @_;
}

=begin TML
---+++ StaticMethod registerPluggable( $class, $method, $code )
Registers =$code= as pluggable method =$method= for =$class=.
Shortcut: =pluggable=
See [[?%QUERYSTRING%#PluggableMethods][Pluggable Methods]].
=cut

sub registerPluggable {
my ( $target, $method, $code ) = @_;

Expand Down Expand Up @@ -1518,6 +1611,18 @@ sub registerPluggable {
);
}

=begin TML
---+++ StaticMethod registerPlugMethod( $extModule, $where, $pluggableMethod, $code )
Registers a handler defined by coderef in =$code= for a pluggable method
=$pluggableMethod=. =$where= defines the execution stage: _before_, _after_,
or _around_.
Shortcuts: =plugBefore=, =plugAfter=, =plugAround=
=cut

sub registerPlugMethod {
my ( $extModule, $where, $pluggableMethod, $code ) = @_;

Expand All @@ -1532,12 +1637,6 @@ sub registerPlugMethod {
$plugMethods{$extModule}{$target}{$method}{$where} = $code;
}

sub isRegistered {
my ($extModule) = @_;

return $registeredModules{$extModule} // 0;
}

=begin TML
---++ SEE ALSO
Expand Down
27 changes: 17 additions & 10 deletions core/lib/Foswiki/Macros.pm
Expand Up @@ -49,14 +49,21 @@ sub BUILD {
---++ ObjectMethod registerTagHandler( $tag, $handler, $syntax )
STATIC Add a tag handler to the function tag handlers.
* =$tag= name of the tag e.g. MYTAG
* =$handler= Reference to a sub or object with Foswiki::Macro role. See below on more details.
* =$syntax= somewhat legacy - 'classic' or 'context-free' (context-free may be removed in future)
Add a new tag handler.
$ =$tag=: name of the tag e.g. MYTAG
$ =$handler=: Reference to a sub, or a object with Foswiki::Macro role, or an
extension class. See below on more details.
$ =$syntax=: _classic_ or _context-free_
=$handler= parameter:
* If it is a sub then it will be passed ($app, \%params, $web, $topic ).
* If it is an object then method =expand()= will be called with arguments (\%params, $topicObject)
* If it is a sub then it will be passed with
=($app, \%params, $web, $topic)=.
* If it is an object then method =expand()= will be called with arguments
=(\%params, $topicObject, @macroArgs)=
* Extension must have a method named after the =$tag=. The method will be
called with same parameters, as =expand()= above.
=$syntax= parameter:
Way back in prehistory, back when the dinosaur still roamed the earth,
Expand Down Expand Up @@ -664,12 +671,12 @@ sub parseSections {

=begin TML
---++ execMacro($macroName, \%attrs, $topicObject) => $string
---++ execMacro($macroName, \%attrs, $topicObject, @macroArgs) => $string
Executes macro defined by its name $macroName.
* =%attrs= is a hash of attributes or a =Foswiki::Attrs= instance.
* =$topicObject= ...
$ =%attrs=: Hash of attributes or a =Foswiki::Attrs= instance.
$ =$topicObject=: ...
=cut

Expand Down Expand Up @@ -735,7 +742,7 @@ sub execMacro {
ASSERT( $this->_macros->{$macroName}->does('Foswiki::Macro'),
"Invalid macro module "
. $this->registered->{$macroName}
. "; must do Foswiki::Macro role" )
. "; must consume Foswiki::Macro role" )
if DEBUG;
}
}
Expand Down

0 comments on commit 6a84c9f

Please sign in to comment.