NAME
    POEx::Role::SessionInstantiation - A Moose::Role for plain old Perl
    objects in a POE context

SYOPSIS
        package My::Class;
        use 5.010;
        use MooseX::Declare;

        # using the role instantly makes it a POE::Session upon instantiation
        class My::Class with POEx::Role::SessionInstantiation
        {
            # declared methods are all exposed as events to POE
            sub foo
            {
                my ($self, @args) = @_;

                # This event is not only added through POE but also added as a 
                # method to each instance that happens to have 'foo' fired

                # Access to POE information is done through the 'poe' accessor
                $self->poe->kernel->state
                (
                    'added_event',
                    sub
                    {
                        say 'added_event has fired'
                    }
                );

                # Some sugar to access the kernel's yield method
                # This will push the 'bar' method into POE's event queue
                $self->yield('bar');
            }

            sub bar
            {
                my ($self, @args) = @_;

                # $self is also safe to pass as a session reference
                # Or you can pass along $self->ID()
                $self->post($self, 'baz')
            }

            sub baz
            {
                my ($self, @args) = @_;

                # call also works too
                $self->call($self, 'added_event';
            }
        }

        1;

        # Constructing the session takes all the normal options
        my $session = My::Class->new({ options => { trace => 1 } });

        # Still need to call ->run();
        POE::Kernel->run();

DESCRIPTION
    POEx::Role::SessionInstantiation provides a nearly seamless integration
    for non-POE objects into a POE environment. It does this by handling the
    POE stuff behind the scenes including allowing per instances method
    changes, session registration to the Kernel, and providing some defaults
    like setting an alias if supplied via the attribute or constructor
    argument, or defining a _default that warns if your object receives an
    event that it does not have.

    This role exposes your class' methods as POE events.

ATTRIBUTES
    heap is: rw, isa: Any, default: {}, lazy: yes
        A traditional POE::Session provides a set aside storage space for
        the session context and that space is provided via argument to event
        handlers. With this Role, your object gains its own heap storage via
        this attribute.

    options is: rw, isa: HashRef, default: {}, lazy: yes
        In following the POE::Session API, sessions can take options that do
        various things related to tracing and debugging. By default, tracing
        => 1, will turn on tracing of POE event firing to your object. debug
        => 1, currently does nothing but more object level tracing maybe
        enabled in future versions.

    args is: rw, isa: ArrayRef, default: [], lazy: yes
        POE::Session's constructor provides a mechanism for passing
        arguments that will end up as arguments to the _start event handler.
        This is the exact same thing.

    alias is: rw, isa: Str, clearer: clear_alias, trigger: registers alias
        This attribute controls your object's alias to POE. POE allows for
        more than one alias to be assigned to any given session, but this
        attribute only assumes a single alias will not attempt to keep track
        of all the aliases. Last alias set will be what is returned. Calling
        the clearer will remove the last alias set from POE and unset it.
        You must be inside a valid POE context for the trigger to actually
        fire (ie, inside a event handler that has been invoked from POE).
        While this can be set at construction time, it won't be until _start
        that it will actually register with POE. If you override _start,
        don't forget to set this attribute again (
        $self->alias($self->alias); ) or else your alias will never get
        registered with POE.

    ID is: ro, isa: Int
        This attribute will return what your POE assigned Session ID is.
        Must only be accessed after your object has been fully built (ie.
        after any BUILD methods). This ID can be used, in addition to a
        reference to yourself, and your defined alias, by other Sessions for
        addressing events sent through POE to your object.

    poe is: ro, isa: Object
        The poe attribute provides runtime context for your object methods.
        It contains an anonymous object with it's own attributes and
        methods. Runtime context is built for each individual event handler
        invocation and then torn down to avoid context crosstalk. It is
        important to only access this attribute from within a POE invoked
        event handler.

        POE ATTRIBUTES

        sender is: rw, isa: POE::Kernel | POE::Session |
        ->does(SessionInstant.)
            The sender of the current event can be access from here.
            Semantically the same as $_[+SENDER].

        state is: rw, isa: Str
            The state fired. This should match the current method name
            (unless of course within the _default event handler, then it
            will be the event name that was invoked but did not exist in
            your object instance.

        [qw/file line from/] is: rw, isa: Maybe[Str]
            These attributes provide tracing information from within POE.
            From is actually not used in POE::Session as far as I can tell,
            but it is available just in case.

        kernel is: rw, isa: POE::Kernel
            This is actually the POE::Kernel singleton provided as a little
            sugar instead of requiring use of $poe_kernel, etc. To make sure
            you are currently within a POE context, check this attribute for
            definedness.

        POE PRIVATE METHODS

        clear()
            This will clear the all of the current context information.

        restore($poe)
            This will take another anonymous poe object and restore state.

        clone()
            This will clone the current anonymous poe object and return it.

METHODS
    [qw/post yield call/]
        These are provided as sugar for the respective POE::Kernel methods.

    _start
        Provides a default _start event handler that will be invoked from
        POE once the Session is registered with POE. The default method only
        takes the alias attribute and sets it again to activate the trigger.
        If this is overridden, don't forget to set the alias again so the
        trigger can execute.

    _stop
        Provides a default _stop event handler that will be invoked from POE
        once the Session's refcount from within POE has reached zero (no
        pending events, no event sources, etc). The default method merely
        clears out the alias.

    _default
        Provides a _default event handler to catch any POE event invocations
        that your instance does not actually have. Will 'warn' about the
        nonexistent state. A big difference from POE::Session is that the
        state and arguments are not rebundled upon invocation of this event
        handler. Instead the attempted state will be available in the poe
        attribute and the arguments will be pass normally as an array.

METHOD MODIFIERS
    after 'BUILD
        All of the magic for turning the constructed object into a Session
        happens in this method. If a BUILD is not provided, a stub exists to
        make sure this advice is executed.

NOTES
    Like all dangerous substances, this Role needs a big fat warning. It
    should be noted thoroughly that this Role performs some pretty heinous
    magic to accomplish a polished and consistent transformation of your
    class into a Session.

    PER INSTANCE METHOD CHANGES
        This Role enables your /objects/ to have method changes. You read
        that right. POE allows Sessions to have runtime event handler
        modification. It is sort of required to support wheels and whatever.
        Anyhow, to support that functionality class level changes are
        executed via Moose::Meta::Class to add/change/remove methods as
        events are added, changed, and removed via POE. But how is that
        possible, you ask, to make class level changes without affecting all
        of the other instances? An anonymous clone of the composed class is
        created and the object is reblessed into that new clone that has
        changes for each change to the events that occurs. This segregates
        changes so that they only affect the individual object involved.

        This functionality should likely be broken out into its own evil
        module, but that is a job for another day.

    BREAKING POE ENCAPSULATION
        POE internally tracks Sessions by their stringified reference. So
        how do make changes to references, such as reblessing them into
        different classes, and not break POE? You do some scary crap.
        Stringification is overloaded (via overload pragma) to return the
        original string from the instance before changes are made to it and
        it is reblessed. The original string is stored in the orig
        attribute. POE also does reference comparisons as well to check if
        the current session is the same as the one it just got and so != and
        == are also overloaded to do string comparisons of references. But
        what about the reference that is already stored by POE? The
        reference is overwritten in one spot (where POE stores its Sessions)
        and is done every time an event change takes place.

    OVERLOAD PRAGMA IN A ROLE? WTF?
        Moose does the right thing, mostly, when it comes to the overload
        pragma in a Role. The methods defined are composed appropriate, but
        the magic doesn't make it through the composition. So the magic must
        be enabled manually. This includes messing with the symbol table of
        the composed class. This happens inside the after 'BUILD' advice,
        and also during event handler changes from POE (the anonymous
        classes need to have the magic enabled each time). So what is the
        moral to this? If you need to overload "", !=, or == in your
        composed class things will likely break. You have been warned.

    So please heed the warnings and don't blame me if this summons the
    terrasque into your datacenter and you left your +5 gear at home.

AUTHOR
    Copyright 2009 Nicholas Perez. Released and distributed under the GPL.

