=begin pod

=head2 Basics

All work is done through a plugin manager. It is generally recommended to have a single instance of plugin manager per
application. The application, in turn, is supposed to delegate it's object creation functionality to the manager. I.e.,
where usually we create an instance with this line of code:

    my $foo = Foo.new( attr => 'a value' );

it is now recommended to have this:

    my $foo = $plugin-manager.create( Foo, attr => 'a value' );

Alternatively, if one needs a class to work with but still capable of supporting plugins, he can do the following:

    my \foo-class = $plugin-manager.class( Foo );

What happens under the hood is that the manager takes your class, considers what plugins are requesting to modify its
behavior, and then creates a new class for you which will delegate some of its functionality to the plugins. This is
somewhat simplified description of what is happening but it is only intended to explain why the delegation is necessary.

All the above also means that the creation of a plugin manager object is one of the first thing an application must do
before anything else. Typically, the code would look like this:

class MyApp {
    has OO::Plugin::Manager $!plugin-manager;

    submethod TWEAK {
        $!plugin-manager .= new( base => 'MyApp' );
        $!plugin-manager.load-plugins;
        $!plugin-manager.initialize( app => self );
    }
}

Of these three steps invocation of the C<load-plugins> method is optional. This is where automatic pre-loading of
plugins from external modules is happening. Refer to corresponding section below to find out more about this process.

By invocing C<initialize> we actually make the manager ready to do its job. The point for having all these stages is to
allow an application to perfom some extra additional steps before plugins are activated. Those are:

=item disabling unwanted plugins
=item defining plugin priorities and, possibly, desired order of the plugins

Future versions of the framework may have some additional functionality and this more things could be done before we
start using the manager.

B<NOTE> I<Though plugin disabling and changes to the ordering are not prohibited after the manager is initialized,
they're not recommended due to possible unwanted side effect. Moreover, ordering is only done while manager is
initializing.>

A thing in the above code which worth mentioning here is the parameters to the C<initialize> method call. The method
itself doesn't take any. Whatever it receives is getting passed to the constructors of newly created plugin objects
(this subject will be covered later). In my code what happens is that application object informs its plugins about
itself allowing direct interaction between plugins and the application. By providing special API an application could
get even more from its plugins that what is covered by the manager. Consider the following sample plugin:

    plugin MyPlugin {
        has MyApp:D $.app is required;

        submethod TWEAK (|) {
            $.app.register-macro( "some_macro", self.^find_method('my-macro') );
        }

        method my-macro ( $param ) { "$param is now expanded" }
    }

Whatever other extensible subsystem is provided by application is then left up to the application and its plugins, the
manager is not involved and thus leaves more space for developer's imagination.

=head2 Pre-loading Plugins And Naming.

When the manager is created it's C<base> attribute can be defined. This attribute defines a namespace prefix to be used
when looking for plugins in external modules. For the example above the manager will try to load all modules with names
starting with I<MyApp::Plugin::> or I<MyApp::Plugins::>. Upon loading all classes contained in these modules and defined
using C<plugin> keyword will register themselves with the framework. This allows a single module to define more than one
plugin:

    unit module MyApp::Plugins::MySet;

    plugin Plugin1 {
        ...
    }

    plugin Plugin2 {
        ...
    }

As a result of compiling this module the framework will know about two new plugins C<Plugin1> and C<Plugin2>. Yet, it
must be noted that though we're referring to them here with their short names, the framework will know them by their
fully qualified names (FQN): C<MyApp::Plugins::MySet::Plugin1> and C<MyApp::Plugins::MySet::Plugin2>. This is to prevent
name clashes when accidentally plugins from different packages are given same names.

=head2 Ordering And Priorities

It is possible for a two more plugins to be handling same method, class, or callback. In this case it becomes very
important to define the order in which their respective handlers are used. When ordering plugins the manager takes into
consideration a couple of plugin attributes such as:

=item user-defined priority
=item user-defined ordering
=item plugin-declared dependencies

Priorities could be of three different levels: I<first>, I<normal>, and I<last>. Their names suggest that user wants
a plugin to be one of the first in the list, one of the last, or in the middle. The latter is the default.

Within each priority a user can define in what particular order he wants the plugins. For example, lets say we have
plugins I<P1>, I<P2>, I<P3>, and I<P4> – all assigned with I<first> priority. Additionally, the user specifies that he
wants I<P2> to go after I<P3>. In this case the manager will attempt to arrange plugins in a way, that I<P3> will go
first, then followed by I<P2>, then by I<P1> and I<P4> in no particular order. Then these four will be followed by
plugins with lower priorities.

To simplify user's life we don't want to make it his responsibility to find out if a I<Plugin1> only works if it
follows, say, I<Plugin2>. The framework lets a plugin define these kinds of relations. More than that, it is also
possible to specify wether the relation is desirable or it is demanded. Consider the followin code:

    plugin Plugin1 after Plugin2 before Plugin3 demands Plugin4, Plugin5 {
        ...
    }

Though rather unlikely to be met in real life, this code demonstrates what can be specified for a plugin. Here traits
C<after> and C<before> (B<note> that C<before> is just a reverse of C<after>. I.e. C<Plugin1 before Plugin2> is the same
as C<Plugin2 after Plugin1>) define desirable relations. In other words, no fatalities would happen if these relations
are broken. By 'broken' we mean that either I<Plugin2> or I<Plugin3> are missing; or together with I<Plugin1> and,
possibly with some other plugins too, they form a circular dependency (see below about sorting).

On the  other hand, C<demand> means that if it can't be fulfilled then the only way to resolve the situation is to
disable this plugin.

=head3 Sorting

The manager will do its best to conform all the ordering parameters. But due to the complexity of the matter the only
rule which can be taken for granted is:

=item I<a demanded plugin will preceed the one which demands it>
=item I<if a couple of plugins demanding each other form a cyclic dependency graph then all nodes of the graph will be
disabled>
=item I<if a plugin demands a disabled or missing plugin it will be disabled too>

All other relations, including user-defined, are considered voluntary. Though they're prioritized in the following order
(from more prioritized down to less):

=item C<after>/C<before> relations
=item user order within priority
=item user-specified priority

For example, if a I<Plugin1> is of lowest I<last> priority but is demanded by or must go before I<Plugin2> which is of
I<first> priority – then I<Plugin1> will go before I<Plugin2> in the order no matter of their priorities.

As it was stated above, C<after> and C<before> doesn't impose strict requirements. For that matter if such dependencies
form a cycle then manager has the right to break it at any link. For example, we have:

    A -> B -> C -> D -> A

where arrow stands for C<after>. The resulting order could be any of:

    A, D, C, B
    B, A, D, C,
    C, B, A, D
    D, C, B, A

It would only depend on what plugin is chosen first by the sorting algorithm to start building the sequence. With regard
to the priorities, cicles might produce pretty surprising result: a plugin with higher priority will go last in the
order! Say, specifying that I<D> has the I<first> priority while leaving all others at I<normal> will result in the
third sequence of the above example.

Also, because demanded relations are unbreakable, then when a cycle is formed of all C<demand>s execpt for a single link
the manager will predictably break that link, making it's left side element the first. For example, if C<<A -> B>> is
the desired one whereas all the reast are demanding, then the final order will be:

    A, D, C, B

=head3 How Ordering Is Used?

This will be covered in the section below.

=head2 Writing A Plugin

A plugin is an instance of a class inheriting from a C<Plugin> class defined in L<OO::Plugin::Class> module. To reduce
the boilerplate and provide better readability of the code special class declarator C<plugin> is provided:

    plugin MyPlugin {
        ...
    }

It is accompanied with three additional traits: C<after>, C<before>, and C<demand>, each of them taking a list of plugin
names:

    plugin MyPlugin after Plugin1, Plugin2, MyApp::Plugin::Plugin3 {
        ...
    }

As you can see, the names could be in both short and FQN forms. Their validity is not checked at the compile time
because the order of loading of plugin modules cannot be pre-determined. Besides, since C<after> and C<before> are not
strict missing a plugin cannot be considered a error. For this reason, all the checks are preformed at run-time.

=head3 Method Handling

A plugin can request to handle a public method call in an application class. This is not just call interception as one
might expect but something bigger than that. Method handling allows a wide variety of tricks from simply monitoring
method calls to completely substitute a method with own code (which is in fact the interception as I see it). It is also
possible to mangle with the original method parameters and return value.

The method call process is split in three stages: I<before> the call, I<around> it, and I<after>. Every stage has
certain specific and its own purpose. We'll get to this later. For now what matters is that the manger considers each
stage as a separate queue of routines to be executed. I call it U<execution chain>. In a way, the original method is
also considered as a member of the I<around> chain, though a special one. The order of the routines is defined by the
order of the plugins they belong to. For example:

    plugin Plugin1 {
        method around-bar1 ( $msg ) is plug-around(:MyClass<bar>) { ... }
    }

    plugin Plugin2 before Plugin1 {
        method around-bar2 ( $msg ) is plug-around(:MyClass<bar>) { ... }
    }

C<around-bar2> will gain control before C<around-bar1> due to C<before> trait defining the plugin order.

B<NOTE> I'm not detailing the code itself in hope that it is self-explainable. Will carry on on syntax later anyway.

A special packet of information is passed to every method handler as the first method parameter. It is called I<message>
and it is an object of C<MethodHandlerMsg> class. The object is presistent across one method call handling session and
is being passed to each and every handler method. In addition to some technical information about the call, it contains
two special attributes: C<shared> and C<private>. Those are read/write accessible and can be used by plugins to pass
information between different handlers and stages.

=item C<shared> is a hash which is kept unchanged by the manager and therefore allows for some data exchange between
method handlers from different plugins within the current handling session.

=item C<private> is somewhat similar to C<shared> except that it is a unique value being kept for each plugin
separately. It only allows a plugin to store a value across stages of the same handling session. C<private> is
a scalar and its content is solely defined by what a plugin code stores in it.

For example:

    plugin Plugin1 {
        method before-bar ( $msg ) is plug-before(:MyClass<bar>) {
            $msg.private = "info from 'before'";
        }

        method after-bar ( $msg ) is plug-after(:MyClass<bar>) {
            say $msg.private; # "info from 'before'"
        }
    }

=head4 Method Return Value

Method handlers plugged into I<around> or I<after> stages can override the return value of a method. To do so they must
set C<rc> attribute or the message packet using C<set-rc> method:

    plugin Plugin1 {
        method around-bar ( $msg ) is plug-around(:MyClass<bar>) {
            $msg.set-rc("my return");
        }
    }

For the I<around> stage this action would a have a side-effect of preventing the original method from being executed.

The handlers of I<after> stage can use the C<rc> attribute of the message packet to inspect the return value (wherever
it was set previously). They're also allowed to change it.

The I<before> stage handlers are not allowed to set the return value. If they attempt to then a warning would be issued
by the manager.

B<NOTE> The return value is not checked agains the original method's signature constraint if there is one.

=head4 Chain Control

A method handler is capable of controlling the execution chain up to some extent. It can request the manager to either
stop processing the chain right away or restart it from the beginning. Those actions are similar to C<last> and C<redo>
commands available for controling the loops. Correspondingly, the framework provides C<plug-last> and C<plug-redo> for
the convinience of a plugin writer. Behind the scenes special exceptions C<CX::Plugin::Last> and C<CX::Plugin::Redo> are
utilized.

With C<plug-last> I<around> and I<after> handlers can supply a single parameter to set the return value on the message
packet.

C<plug-redo> must be used with care as it may cause an infinite loop. Next versions of this framework might impose a
limit on the number of C<redo>s emitted by a single plugin.

=head4 Parametrized Handlers

The message object received by a handler has an attribute C<params> which is a C<Capture> of the orginal method
parameters. Having a handler which is only deals with the message packet has an advantage of making it capable of
handling multiple original methods in the most simple way. For example, the following code would record all calls of all
methods of C<MyClass>:

    plugin Recorder {
        method bind-them-all ( $msg ) is plug-before( 'MyClass' ) {
            say $msg.method, " with ", $msg.params;
        }
    }

But this isn't really handy when one actually needs to have access to the parameters. Of course, there are a couple of
ways to destructure a C<Capture> object, but that adds to the complexity of the code - something I always want to avoid.
For this reason, there is a simpler solution. If the plugin manager sees more than one parameter in the handler
signature it passes the orignal method parameters next to the message packet object:

    class MyClass {
        method bar ( Int:D $i ) {
            return -$i
        }
    }

    plugin Plugin1 {
        method before-bar ( $msg, Int:D $i ) is plug-before(:MyClass<bar>) {
            say "bar() with Int: $i";
        }
    }

    OO::Plugin::Manager.new.create( MyClass ).bar( 42 ); # bar() with Int: 42

B<NOTE> For speeding up operations parameters are not checked against handler signature by the plugin manager code.

B<NOTE> The framework checks for the handler signature validity by inspecting its first parameter. It has to be a scalar
(i.e. has C<$> sigil) and be of type C<Any>. It would better bet C<MethodHandlerMsg> but due to a bug in Perl6 this is
not possible for now because it causes an internal error.

Same rule apply to multi-dispatch method handlers where the C<plug-> traits are to be applied to the C<proto>:

    plugin Plugin1 {
        proto method around-bar ( $msg ) is plug-around(:MyClass<bar>) {*}
        multi method around-bar ( $msg ) { ... }

        proto method before-bar ( $msg, | ) is plug-before(:MyClass<bar>) {*}
        multi method before-bar ( $msg, Int:D $i ) { ... }
    }

B<NOTE> Currently it is possible to apply the trait to one of a C<multi> variants within multi-dispatch. Doing so is
highly discouraged and will be a error at some point in the future!

=head4 Performance Matters

It must be noted that method handling while being very powerful and flexible tool is pretty costly performance-wise.
For speed-sensitive applications consider using L<#Class Overriding>.

=head3 Class Overriding

This is a very straightforward method of providing extended or altered functionality for your core. Whenever necessary a
plugin can declare a so called C<plug-class> which will inherit from a core class:

    use OO::Plugin;
    use OO::Plugin::Manager;

    class MyClass {
        method foo ( Str $s ) {
            S:g/\s/_/ given $s
        }
    }

    plugin Plugin1 {
        plug-class MyPlug for MyClass {
            method foo ( Str $s ) {
                callwith( "my prefix for $s" );
            }
        }
    }

    my $mgr = OO::Plugin::Manager.new.initialize;
    my $inst = $mgr.create( MyClass );
    say $inst.foo("1 2 3");                             # my_prefix_for_1_2_3
    say $inst.^mro;                                     # ((MyClass_4jN3Lv) (MyPlug_YHNAfr) (MyClass) (Any) (Mu))

I<Note> that the output of the last line is a sample. The last six chars following the underscore char are random.

Let me explain the magic behind this code. Actually, C<plug-class> doesn't declare a class. It declares a role
(I<they're certain limitations in Rakudo making this the only possible way>). For each C<plug-class> defined for the
requested core class (C<MyClass> in the example) the manager generates an empty class and apply the C<plug-class> role
to it. Then it sets a parent for the new class (not necessarily it is the core class as more than one plugin is defining
a C<plug-class> for it). Eventually, a new class is generated which inherits from the newly created inheritance chain.

This result of the alogirth can be observed in the output of C<.^mro>. Say, if we add another plugin to the above code:

    plugin Plugin2 before Plugin1 {
        plug-class MyPlug2 for MyClass {
            ...
        }
    }

The resulting chain would then look like this:

    ((MyClass_4jN3Lv) (MyPlug2_NjJk1a) (MyPlug_YHNAfr) (MyClass) (Any) (Mu))

Note that C<Plugin2> is declaring to go I<before> C<Plugin1> - so goes C<MyPlug2> before C<MyPlug> in the MRO. This is
how plugin ordering works for class overriding.

As C<plug-class> is a role in nature, so all of the role limitations apply. For example, a role cannot have C<our>
declarations. Most of those limitations could be overcome by using C<plugin>'s body:

    plugin Plugin1 {
        out $plug-class-variable;

        plug-class MyPlug for MyClass {
            method foo {
                say $plug-class-variable;
            }
        }
    }

A C<plug-class> doesn't have direct access to the plugin object of his respective C<plugin> though. But the object can
be obtained with the plugin manager API.

=head3 Callbacks

U<Callback> is a way of calling a special method of a plugin and getting a return value from it. A callback is defined
by a string name and can further be detailed with method signature.

Callback is the most simple and straightforward way of direct interaction between application code and plugins: a plugin
defines a multi-method C<on-callback>:

    plugin Plugin1 {
        multi method on-callback ( 'my-callback', $msg, Str $p1, Int $p2 ) {
            ...
            return "The Universe";
        }
    }

Then application issue a call:

    my $mgr = OO::Plugin::Manager.new;
    ...
    say $mgr.callback( 'my-callback', "the answer", 42 ); # The Universe

and it gets dispatched to matching C<on-callback> methods of all plugins. This also implies that for any given callback
the term U<execution chain> defined in L<#Method Handling> applies too, as well as the methods to control the chain
using C<plug-last> or C<plug-redo> routines.

Similarly to method handling, a callback receives a message object of C<PluginMessage> type. (I<Actually,
C<PluginMessage> is the base class of C<MethodHandlerMsg>>) And same way, as for method handling, a callback can specify
its return value using C<set-rc> method of the object or by returning the value. In the latter case the value must be
defined and not already set in any other manner (like by a previous callback in the chain) or it will be dropped by the
manager. If a callback needs to return a type then this can only be done with C<set-rc> or C<plug-last>.

If a callback doesn't use C<plug-last> to indicate the termination of the execution chain, then any next callback from a
later-located plugin can override it with own value using C<set-rc> method of the message object.

=head3 Events

Similarly to callbacks, U<event> is a way of calling a special method of a plugin. Events are different in a way that
they're handled asynchronously and are designed for mostly one-way communication: from application to plugins. Event is
handled by a multi-method too:

    plugin Plugin1 {
        multi method on-event ( 'my-event', Str $p1, Int $p2 ) {
            ...
        }
    }

Contrary to other handler methods, it doesn't receive any special message object, as it is clear from the example.

On the application side, sending of an event is as simple as:

    my $mgr = OO::Plugin::Manager.new;
    ...
    my $promise = $mgr.event( 'my-event;, "the answer", 42 );

The returned C<Promise> will be kept when all event handlers are completed.

If there is more than one event handler with the same signature matching the passed parameters, then they will be
executed in parallel. The number of simultaneously running handlers is limited by C<event-workers> attribute of the
plugin manager. Setting it to 1 will cause the handlers to be called one after another but still in a separate thread,
so the main application code may proceed as usual.

Clearly, the plugin ordering doesn't apply to event handling; this neither execution chain is used. Therefore it is
guaranteed that for every event all its matching handlers will be called.

To allow the handlers complete without interruption it is highly recommended for an application to call method C<finish>
on the plugin manager object before exiting the application:

    $mgr.finish;

=head4 Nuances

=item Events are dispatched by a special method in its own thread. To reduce resource consumption, it is not getting
started until an event is sent by the application. It will also shutdown if no event is been sent over a timeout period.
The timeout is defined by C<ev-dispatcher-timeout> attribute of the manager.

=item It is still possible to obtain return value of a particular event handler. The C<Promise> returned by the C<event>
method is kept with an array of C<Promise>s of each event handler. Those are being kept with two-element arrays where
the first element is a plugin object, and the second is event handler return value.

=begin item
If an event handler throws and exception it is silently consumed by the dispatcher. But the exception can be
fetched from the second element of event handler's C<Promise> where it will be stored instead of the return value.
=end item

I< B<NOTE> Other methods of reporting errors back to the user code are considered. Any feedback is welcome!>

=head2 Plugin META

Any plugin has some meta-data attached to it. The format is as simple as it can be: it's a hash of meta-keys with
values. There is no predefined set of keys. Any application can use any keys for its own purpose. Though a couple of
keys are reserved for the plugin manager itself. Those are:

=begin item
C<version>

Plugin version. Must be a C<Version> object.
=end item

=begin item
C<name>

Plugin short name as the developer wants it to be. This allows to override short name obtained from plugin's module
name. Both name can later be used to get FQN of the plugin.
=end item

=begin item
C<after>, C<before>

Desirable ordering relations.
=end item

=begin item
C<demand>

Demanding C<after> ordering relation.
=end item

The meta is registered from within plugin's body block either with C<plugin-meta> routine, or with C<our %meta>
hash:

    plugin Plugin1 {
        our %meta = key1 => "value1",
                    key2 => "value2",
                    key3 => 42,
                    ;

        plugin-meta key1 => "value 1",
                    key4 => "value 4",
                    demand => <Plugin2 Plugin3>,
                    ;
    }

For the same key C<key1> the value from C<plugin-meta> will take precedence. Generally speaking, the precedence of sources for the meta are:

=item plugin declaration
=item C<plugin-meta>
=item C<%meta>

Keys declared in higher priority override keys from lower priority source.

C<after>, C<before>, and C<demand> are keys which are taken special care. Those can be declared in the plugin declarion
with traits of the same names. So, for the code:

    plugin Plugin1 after Plugin2 {
        our %meta = demand => <Plugin5>,
                    before => <Plugin6>,

        plugin-meta after  => <Plugin3>,
                    before => <Plugin3>,
                    ;
    }

The final meta will be:

    after  => <Plugin2>, # from the declaration
    before => <Plugin3>, # from plugin-meta
    demand => <Plugin5>, # from %meta

B<NOTE> Though the values above are strings, in real life ordering meta keys are C<Set>s of plugin names.

Another meta key taken from plugin declaration is C<version>:

    plugin Plugin1:ver<0.1.0> {
        ...
    }

unless there is manually defined C<version> key declared by the programmer.

=end pod
