The process of writing a Mojolicious plugin
I have gotten far enough into Mojolicious development to feel rather baffled again. This post is a work in progress, to be edited and filled in as I discover the answers.
According to the Rendering guide,
A skeleton for a full CPAN compatible plugin distribution can be automatically generated.
We are going to create a plugin called StaticText, so let's do:
$ mojo generate plugin StaticText
What that actually does is the following actions inside your current directory, as we can see from its output log:
[mkdir] ./Mojolicious-Plugin-StaticText/lib/Mojolicious/Plugin
[write] ./Mojolicious-Plugin-StaticText/lib/Mojolicious/Plugin/StaticText.pm
[mkdir] ./Mojolicious-Plugin-StaticText/t
[write] ./Mojolicious-Plugin-StaticText/t/basic.t
[exist] ./Mojolicious-Plugin-StaticText
[write] ./Mojolicious-Plugin-StaticText/Makefile.PL
Q: How exactly can I develop this inside an example application? The documentation's standard load procedure:
$self->plugin('Mojolicious::Plugin::StaticText');
fails because it doesn't look in Mojolicious-Plugin-StaticText/lib/Mojolicious/Plugin/ of course.
Q: How do I install my common personal plugins into my individual "apps" ? Presumably I should be able to "git checkout" them directly into... lib/Plugin/ ...? Obviously I'm not going to edit them into the MyApp:: namespace, right?
Q: Should use the Mojolicious::Plugin namespace for plugins that I consider to be eventual candidates for CPAN, or what is best practice for naming my personal plugins that I plan on using across multiple projects?
Q: I see how to pass parameters when loadiing a plugin, but does each plugin get loaded, or registered, just once, or can I have multiple instances of a plugin?
NOTE: Refer also to the Plugins document
Q: Where do I store "instance data" that is computed from the configuration parameters I pass when loading a plugin?
A: Plugins are simply modules, not objects. If we want to save configuration data at load-time, we could save that in an attribute of the application like this: $app->attr('some_attribute_name' => value) which we later access as just "$app->some_attribute_name".
A good example of how configuration parameters are passed, handled, and saved is http://search.cpan.org/~madcat/Mojolicious-Plugin-Database/lib/Mojolicious/Plugin/Database.pm
Behind the curtain: when you call attr, that actually builds and then eval(s) a string which defines a function by the supplied name. That function optionally sets (if called with a value), and always returns the value of the named key in the object upon which you originally called ->attr(). So in the case of doing $app->attr('foo') the function would create and use $attr->{'foo'}.
Q: The Mojolicious::Plugins guide shows the example code
$plugins->register_plugin('MyApp::Plugin::SomeThing', Mojolicious->new);
below the presumably required code:
use Mojolicious::Plugins;
my $plugins = Mojolicious::Plugins->new;
push @{$plugins->namespaces}, 'MyApp::Plugin';
Yet elsewhere, for example in http://mojolicio.us/perldoc/Mojolicious/Plugin/JSONConfig , we see a completely different style that runs with application start:
sub startup {
my $self = shift;
$self->plugin('Mojolicious::Plugin::StaticText');
What exactly is the difference between these two?
Q: In the version with
$plugins->register_plugin('MyApp::Plugin::SomeThing', Mojolicious->new);
what does the Mojolicious->new do? According to the documentation for Mojolicious->new(), that should "Construct a [whole other] new Mojolicious application and call 'startup'… set up logging… the renderer, static file server, default set of plugins…" We can't seriously be loading a whole new "app" nested inside of our current "app" can we? What's going on?
Q: After the name of the plugin, what happens to the remaining arguments to $self->plugin()?
A: The optional second argument must be either a reference (to a scalar, array, hash, subroutine, etc.) or a scalar. If it's just a plain scalar such as 3, like the plugin's register() subroutine will be called with a reference to a hash like this: {3, undef}. In general, you will probably want to pass a reference to a hash that contains your configuration parameters.