Writing plugins for Dancer2
Plugins provide you with additional keywords to decouple predefined behavior to make it easier on you so you won't need to implement the same thing over and over again.
Let me show you how simple it is to write a plugin of your own.
(This explains the current API to plugins. Refer to Dancer2::Plugin for up-to-date documentation.)
A plugin that does nothing (so far)
All you need to do is use Dancer2::Plugin and that will provide you with all the keywords you need to write the plugin.
package Dancer2::Plugin::Kitteh; use Dancer2::Plugin; # we do nothing, just like most cats do register_plugin; 1;
Introducing keywords
You can introduce new keywords the application will receive when it
uses your plugin using the register
keyword:
register meow => sub { my ( $dsl ) = plugin_args(@_); my $app = $dsl->app; };
This is how we introduce the meow
keyword to the user.
We use plugin_args
to make sure we get the plugin arguments. This
is for compatibility.
The keyword receives an object which represents the DSL object the app is connected to. You can use it in order to access the Dancer2 core application connected to the user's scope.
We can also control whether a keyword is app-global, meaning it can be called from anywhere in an app or only from a route, which means during a request:
register meow => sub { debug 'Meow!'; }, { is_global => 0 };
Route decorators
Some plugins generate routes from other routes, which makes them look a little bit like route decorators. Take Dancer2::Plugin::Auth::Tiny for example:
get '/private' => needs login => sub { ... };
The way it works is by taking the route sub as a parameter and creating its own route which calls it. We can do the same.
package Dancer2::Plugin::OnTuesday; # ABSTRACT: Make sure a route only works on Tuesday use Dancer2::Plugin; register on_tuesday => sub { my ( $dsl, $route_sub, @args ) = plugin_args(@_); my $day = (localtime)[6]; $day == 2 or return pass; return $route_sub->( $dsl, @args ); }; register_plugin;
Now we can use this plugin as such:
package MyApp; use Dancer2; use Dancer2::Plugin::OnTuesday; get '/' => on_tuesday => sub { ... }; # every other day get '/' => sub { ... };
Reading the configuration
While a user can change the configuration using both the configuration file
and the set
keyword, we need a single source for all configuration
options for our plugin. This is handled automatically using the
plugin_setting
keyword:
register meow => sub { my $dsl = shift; my $vol = plugin_setting->{'volume'} || 3; };
Extra tricks
There are a few additional tricks available which weren't covered here, such as running code on import, registering additional hooks, and executing hooks. They are all documented in Dancer2::Plugin.
Conclusion
The plugin infrastructure in the upgrade from Dancer 1 to Dancer 2 has been problematic. We've tried various methods to allow plugins to coexist, then to specify how they work, and finally to provide a proper shim layer to enable working with both smealessly.
Unfortunately all of these methods had problems and we resulted in separating the plugins. This does not mean that writing a plugin for Dancer 2 is difficult. In fact it's fairly simple.
We're working on making them even more comfortable and remove any lingering problems, but as you can see they are already easy to write.
Author
This article has been written by Sawyer X for the Perl Dancer Advent Calendar 2014.
Copyright
No copyright retained. Enjoy.
2014 // Sawyer X <xsawyerx@cpan.org>