1Dancer2::Plugin(3)    User Contributed Perl Documentation   Dancer2::Plugin(3)
2
3
4

NAME

6       Dancer2::Plugin - base class for Dancer2 plugins
7

VERSION

9       version 0.300004
10

SYNOPSIS

12       The plugin itself:
13
14           package Dancer2::Plugin::Polite;
15
16           use strict;
17           use warnings;
18
19           use Dancer2::Plugin;
20
21           has smiley => (
22               is => 'ro',
23               default => sub {
24                   $_[0]->config->{smiley} || ':-)'
25               }
26           );
27
28           plugin_keywords 'add_smileys';
29
30           sub BUILD {
31               my $plugin = shift;
32
33               $plugin->app->add_hook( Dancer2::Core::Hook->new(
34                   name => 'after',
35                   code => sub { $_[0]->content( $_[0]->content . " ... please?" ) }
36               ));
37
38               $plugin->app->add_route(
39                   method => 'get',
40                   regexp => '/goodbye',
41                   code   => sub {
42                       my $app = shift;
43                       'farewell, ' . $app->request->params->{name};
44                   },
45               );
46
47           }
48
49           sub add_smileys {
50               my( $plugin, $text ) = @_;
51
52               $text =~ s/ (?<= \. ) / $plugin->smiley /xeg;
53
54               return $text;
55           }
56
57           1;
58
59       then to load into the app:
60
61           package MyApp;
62
63           use strict;
64           use warnings;
65
66           use Dancer2;
67
68           BEGIN { # would usually be in config.yml
69               set plugins => {
70                   Polite => {
71                       smiley => '8-D',
72                   },
73               };
74           }
75
76           use Dancer2::Plugin::Polite;
77
78           get '/' => sub {
79               add_smileys( 'make me a sandwich.' );
80           };
81
82           1;
83

DESCRIPTION

85   Writing the plugin
86       "use Dancer2::Plugin"
87
88       The plugin must begin with
89
90           use Dancer2::Plugin;
91
92       which will turn the package into a Moo class that inherits from
93       Dancer2::Plugin. The base class provides the plugin with two
94       attributes: "app", which is populated with the Dancer2 app object for
95       which the plugin is being initialized for, and "config" which holds the
96       plugin section of the application configuration.
97
98       Modifying the app at building time
99
100       If the plugin needs to tinker with the application -- add routes or
101       hooks, for example -- it can do so within its "BUILD()" function.
102
103           sub BUILD {
104               my $plugin = shift;
105
106               $plugin->app->add_route( ... );
107           }
108
109       Adding keywords
110
111       Via "plugin_keywords"
112
113       Keywords that the plugin wishes to export to the Dancer2 app can be
114       defined via the "plugin_keywords" keyword:
115
116           plugin_keywords qw/
117               add_smileys
118               add_sad_kitten
119           /;
120
121       Each of the keyword will resolve to the class method of the same name.
122       When invoked as keyword, it'll be passed the plugin object as its first
123       argument.
124
125           sub add_smileys {
126               my( $plugin, $text ) = @_;
127
128               return join ' ', $text, $plugin->smiley;
129           }
130
131           # and then in the app
132
133           get '/' => sub {
134               add_smileys( "Hi there!" );
135           };
136
137       You can also pass the functions directly to "plugin_keywords".
138
139           plugin_keywords
140               add_smileys => sub {
141                   my( $plugin, $text ) = @_;
142
143                   $text =~ s/ (?<= \. ) / $plugin->smiley /xeg;
144
145                   return $text;
146               },
147               add_sad_kitten => sub { ... };
148
149       Or a mix of both styles. We're easy that way:
150
151           plugin_keywords
152               add_smileys => sub {
153                   my( $plugin, $text ) = @_;
154
155                   $text =~ s/ (?<= \. ) / $plugin->smiley /xeg;
156
157                   return $text;
158               },
159               'add_sad_kitten';
160
161           sub add_sad_kitten {
162               ...;
163           }
164
165       If you want several keywords to be synonyms calling the same function,
166       you can list them in an arrayref. The first function of the list is
167       taken to be the "real" method to link to the keywords.
168
169           plugin_keywords [qw/ add_smileys add_happy_face /];
170
171           sub add_smileys { ... }
172
173       Calls to "plugin_keywords" are cumulative.
174
175       Via the ":PluginKeyword" function attribute
176
177       For perl 5.12 and higher, keywords can also be defined by adding the
178       ":PluginKeyword" attribute to the function you wish to export.
179
180       For Perl 5.10, the export triggered by the sub attribute comes too late
181       in the game, and the keywords won't be exported in the application
182       namespace.
183
184           sub foo :PluginKeyword { ... }
185
186           sub bar :PluginKeyword( baz quux ) { ... }
187
188           # equivalent to
189
190           sub foo { ... }
191           sub bar { ... }
192
193           plugin_keywords 'foo', [ qw/ baz quux / ] => \&bar;
194
195       For an attribute
196
197       You can also turn an attribute of the plugin into a keyword.
198
199           has foo => (
200               is => 'ro',
201               plugin_keyword => 1,  # keyword will be 'foo'
202           );
203
204           has bar => (
205               is => 'ro',
206               plugin_keyword => 'quux',  # keyword will be 'quux'
207           );
208
209           has baz => (
210               is => 'ro',
211               plugin_keyword => [ 'baz', 'bazz' ],  # keywords will be 'baz' and 'bazz'
212           );
213
214       Accessing the plugin configuration
215
216       The plugin configuration is available via the "config()" method.
217
218           sub BUILD {
219               my $plugin = shift;
220
221               if ( $plugin->config->{feeling_polite} ) {
222                   $plugin->app->add_hook( Dancer2::Core::Hook->new(
223                       name => 'after',
224                       code => sub { $_[0]->content( $_[0]->content . " ... please?" ) }
225                   ));
226               }
227           }
228
229       Getting default values from config file
230
231       Since initializing a plugin with either a default or a value passed via
232       the configuration file, like
233
234           has smiley => (
235               is => 'ro',
236               default => sub {
237                   $_[0]->config->{smiley} || ':-)'
238               }
239           );
240
241       "Dancer2::Plugin" allows for a "from_config" key in the attribute
242       definition.  Its value is the plugin configuration key that will be
243       used to initialize the attribute.
244
245       If it's given the value 1, the name of the attribute will be taken as
246       the configuration key.
247
248       Nested hash keys can also be referred to using a dot notation.
249
250       If the plugin configuration has no value for the given key, the
251       attribute default, if specified, will be honored.
252
253       If the key is given a coderef as value, it's considered to be a
254       "default" value combo:
255
256           has foo => (
257               is => 'ro',
258               from_config => sub { 'my default' },
259           );
260
261
262           # equivalent to
263           has foo => (
264               is => 'ro',
265               from_config => 'foo',
266               default => sub { 'my default' },
267           );
268
269       For example:
270
271           # in config.yml
272
273           plugins:
274               Polite:
275                   smiley: ':-)'
276                   greeting:
277                       casual: Hi!
278                       formal: How do you do?
279
280
281           # in the plugin
282
283           has smiley => (             # will be ':-)'
284               is          => 'ro',
285               from_config => 1,
286               default     => sub { ':-(' },
287           );
288
289           has casual_greeting => (    # will be 'Hi!'
290               is          => 'ro',
291               from_config => 'greeting.casual',
292           );
293
294           has apology => (            # will be 'sorry'
295               is          => 'ro',
296               from_config => 'apology',
297               default     => sub { 'sorry' },
298           )
299
300           has closing => (            # will be 'See ya!'
301               is => 'ro',
302               from_config => sub { 'See ya!' },
303           );
304
305       Config becomes immutable
306
307       The plugin's "config" attribute is loaded lazily on the first call to
308       "config". After this first call "config" becomes immutable so you
309       cannot do the following in a test:
310
311           use Dancer2;
312           use Dancer2::Plugin::FooBar;
313
314           set plugins => {
315               FooBar => {
316                   wibble => 1,  # this is OK
317               },
318           };
319
320           flibble(45);          # plugin keyword called which causes config read
321
322           set plugins => {
323               FooBar => {
324                   wibble => 0,  # this will NOT change plugin config
325               },
326           };
327
328       Accessing the parent Dancer app
329
330       If the plugin is instantiated within a Dancer app, it'll be accessible
331       via the method "app()".
332
333           sub BUILD {
334               my $plugin = shift;
335
336               $plugin->app->add_route( ... );
337           }
338
339       To use Dancer's DSL in your plugin:
340
341           $self->dsl->debug( “Hi! I’m logging from your plugin!” );
342
343       See "DSL KEYWORDS" in Dancer2::Manual for a full list of Dancer2 DSL.
344
345   Using the plugin within the app
346       A plugin is loaded via
347
348           use Dancer2::Plugin::Polite;
349
350       The plugin will assume that it's loading within a Dancer module and
351       will automatically register itself against its "app()" and export its
352       keywords to the local namespace. If you don't want this to happen,
353       specify that you don't want anything imported via empty parentheses
354       when "use"ing the module:
355
356           use Dancer2::Plugin::Polite ();
357
358   Plugins using plugins
359       It's easy to use plugins from within a plugin:
360
361           package Dancer2::Plugin::SourPuss;
362
363           use Dancer2::Plugin;
364           use Dancer2::Plugin::Polite;
365
366           sub my_keyword { my $smiley = smiley(); }
367
368           1;
369
370       This does not export "smiley()" into your application - it is only
371       available from within your plugin. However, from the example above, you
372       can wrap DSL from other plugins and make it available from your plugin.
373
374   Utilizing other plugins
375       You can use the "find_plugin" to locate other plugins loaded by the
376       user, in order to use them, or their information, directly:
377
378           # MyApp.pm
379           use Dancer2;
380           use Dancer2::Plugin::Foo;
381           use Dancer2::Plugin::Bar;
382
383           # Dancer2::Plugin::Bar;
384           ...
385
386           sub my_keyword {
387               my $self = shift;
388               my $foo  = $self->find_plugin('Dancer2::Plugin::Foo')
389                   or $self->dsl->send_error('Could not find Foo');
390
391               return $foo->foo_keyword(...);
392           }
393
394   Hooks
395       New plugin hooks are declared via "plugin_hooks".
396
397           plugin_hooks 'my_hook', 'my_other_hook';
398
399       Hooks are prefixed with "plugin.plugin_name". So the plugin "my_hook"
400       coming from the plugin "Dancer2::Plugin::MyPlugin" will have the hook
401       name "plugin.myplugin.my_hook".
402
403       Hooks are executed within the plugin by calling them via the associated
404       app.
405
406           $plugin->execute_plugin_hook( 'my_hook' );
407
408       You can also call any other hook if you provide the full name using the
409       "execute_hook" method:
410
411           $plugin->app->execute_hook( 'core.app.route_exception' );
412
413       Or using their alias:
414
415           $plugin->app->execute_hook( 'on_route_exception' );
416
417       Note: If your plugin consumes a plugin that declares any hooks, those
418       hooks are added to your application, even though DSL is not.
419
420   Writing Test Gotchas
421       Constructor for Dancer2::Plugin::Foo has been inlined and cannot be
422       updated
423
424       You'll usually get this one because you are defining both the plugin
425       and app in your test file, and the runtime creation of Moo's attributes
426       happens after the compile-time import voodoo dance.
427
428       To get around this nightmare, wrap your plugin definition in a "BEGIN"
429       block.
430
431           BEGIN {
432               package Dancer2::Plugin::Foo;
433
434               use Dancer2::Plugin;
435
436                   has bar => (
437                       is => 'ro',
438                       from_config => 1,
439                   );
440
441                   plugin_keywords qw/ bar /;
442
443           }
444
445           {
446               package MyApp;
447
448               use Dancer2;
449               use Dancer2::Plugin::Foo;
450
451               bar();
452           }
453
454       You cannot overwrite a locally defined method (bar) with a reader
455
456       If you set an object attribute of your plugin to be a keyword as well,
457       you need to call "plugin_keywords" after the attribute definition.
458
459           package Dancer2::Plugin::Foo;
460
461           use Dancer2::Plugin;
462
463           has bar => (
464               is => 'ro',
465           );
466
467           plugin_keywords 'bar';
468

AUTHOR

470       Dancer Core Developers
471
473       This software is copyright (c) 2020 by Alexis Sukrieh.
474
475       This is free software; you can redistribute it and/or modify it under
476       the same terms as the Perl 5 programming language system itself.
477
478
479
480perl v5.32.0                      2020-07-28                Dancer2::Plugin(3)
Impressum