Dancer2

 view release on metacpan or  search on metacpan

lib/Dancer2/Plugin.pm  view on Meta::CPAN

    return;

}

# plugin has been called within a D2 app. Modify
# the app and export keywords
sub _exporter_app {
    my( $class, $caller, $global ) = @_;

    $exported_app->{$caller} = 1;

    # The check for ->dsl->app is to handle plugins as well.
    # Otherwise you can only import from a plugin to an app,
    # but with this, you can import to anything
    # that has a DSL with an app, which translates to "also plugins"
    my $app = eval("${caller}::app()") || eval { $caller->dsl->app } ## no critic qw(BuiltinFunctions::ProhibitStringyEval)
        or return; ## no critic

    return unless $app->can('with_plugin');

    my $plugin = $app->with_plugin( '+' . $class );
    $global->{'plugin'} = $plugin;

    return unless $class->can('keywords');

    # Add our hooks to the app, so they're recognized
    # this is for compatibility so you can call execute_hook()
    # without the fully qualified plugin name.
    # The reason we need to do this here instead of when adding a
    # hook is because we need to register in the app, and only now it
    # exists.
    # This adds a caveat that two plugins cannot register
    # the same hook name, but that will be deprecated anyway.
    {;
        foreach my $hook ( @{ $plugin->ClassHooks } ) {
            my $full_name = 'plugin.' . lc($class) . ".$hook";
            $full_name =~ s/Dancer2::Plugin:://i;
            $full_name =~ s/::/_/g;

            # this adds it to the plugin
            $plugin->hook_aliases->{$hook} = $full_name;

            # this adds it to the app
            $plugin->app->hook_aliases->{$hook} = $full_name;

            # copy the hooks from the plugin to the app
            # this is in case they were created at import time
            # rather than after
            @{ $plugin->app->hooks }{ keys %{ $plugin->hooks } } =
                values %{ $plugin->hooks };
        }
    }

    {
        # get the reference
        my ($plugin_addr) = "$plugin" =~ $REF_ADDR_REGEX;

        $instances{$plugin_addr}{'config'} = sub { $plugin->config };
        $instances{$plugin_addr}{'app'}    = $plugin->app;

        Scalar::Util::weaken( $instances{$plugin_addr}{'app'} );

        ## no critic
        no strict 'refs';

        # we used a forward declaration
        # so the compiled form "plugin_setting;" can be overridden
        # with this implementation,
        # which works on runtime ("plugin_setting()")
        # we can't use can() here because the forward declaration will
        # create a CODE stub
        no warnings 'redefine';
        *{"${class}::plugin_setting"} = sub {
            my ($plugin_addr) = "$CUR_PLUGIN" =~ $REF_ADDR_REGEX;

            $plugin_addr
                or Carp::croak('Can\'t find originating plugin');

            # we need to do this because plugins might call "set"
            # in order to change plugin configuration but it doesn't
            # change the plugin object, it changes the app object
            # so we merge them.
            my $name = ref $CUR_PLUGIN;
            $name =~ s/^Dancer2::Plugin:://g;

            my $plugin_inst       = $instances{$plugin_addr};
            my $plugin_config     = $plugin_inst->{'config'}->();
            my $app_plugin_config = $plugin_inst->{'app'}->config->{'plugins'}{$name};

            return { %{ $plugin_config || {} }, %{ $app_plugin_config || {} } };
        };

        # FIXME:
        # why doesn't this work? it's like it's already defined somewhere
        # but i'm not sure where. seems like AUTOLOAD runs it.
        #$class->can('execute_hook') or
            *{"${class}::execute_hook"}   = sub {
                # this can also be called by App.pm itself
                # if the plugin is a
                # "candidate" for a hook
                # See: App.pm "execute_hook" method, "around" modifier
                if ( $_[0]->isa('Dancer2::Plugin') ) {
                    # this means it's probably our hook, we need to verify it
                    my ( $plugin_self, $hook_name, @args ) = @_;

                    my $plugin_class = lc $class;
                    $plugin_class =~ s/^dancer2::plugin:://;
                    $plugin_class =~ s{::}{_}g;

                    # you're either calling it with the full qualifier or not
                    # if not, use the execute_plugin_hook instead
                    if ( $plugin->hooks->{"plugin.$plugin_class.$hook_name"} ) {
                        Carp::carp("Please use fully qualified hook name or "
                                 . "the method execute_plugin_hook");
                        $hook_name = "plugin.$plugin_class.$hook_name";
                    }

                    $hook_name =~ /^plugin\.$plugin_class/
                        or Carp::croak('Unknown plugin called through other plugin');

                    # now we can't really use the app to execute it because



( run in 0.535 second using v1.01-cache-2.11-cpan-39bf76dae61 )