Saturday, 15 November 2014

A matter of time

Strehler 1.3.0 is released. This means that all the problems with Dancer2 0.15x are solved. More than that, requirement about Dancer2 moved up from Dancer2 0.11 to Dancer 0.15002.

In the previous episodes we saw that Dancer2 App, from version 0.15, try to find their configuration file in a directory near the one they are installed, ignoring where is the script that uses them. This was very bad for Strehler becase Strehler apps like Strehler::Admin are installed using CPAN so they are in the local repository, a place where no configuration file can be stored.

Only available solution (for now) is overriding thi behaviour setting environment variable DANCER_CONFDIR to the path where our config.yml actually is. Can we do it inside a script so that we can use this solution in any context, like CPAN tests? The answer is yes, if you know the right things about perl.

First of all, any perl script can access environment variables through the %ENV hash,  a read/write variable always available. So, first step should be to write in your code:

$ENV{DANCER_CONFDIR} = /the/directory/I/want

Now you can think that, including my app, all will work, so you're thinking about something like this:

$ENV{DANCER_CONFDIR} = /the/directory/I/want
use Strehler::Admin

Don't run too fast, this code WILL NOT work.

There's a lot of interesting concepts about perl interpreter behind this problem. Concepts, I hope, one day you'll be curious about. For now it's enough to say that "use" directive will run before DANCER_CONFDIR assignment even though you write it in the end of your file.

 Modules must be loaded before any other piece of code because consistency of any piece of code can be verified only with all the module loaded. Perl interpreter does it without asking nothing, ignoring that you necessary need to do something before.

Can you change this behaviour? Yes, two ways to do it:

  • BEGIN directive will run all the code inside its block before any other code, including use.
   $ENV{DANCER_CONFDIR} = /the/directory/I/want
use Strehler::Admin;

  • require directive instead of use load the module only when someone ask for it,with no precedence on anything.

$ENV{DANCER_CONFDIR} = /the/directory/I/want
require Strehler::Admin;

You can see an example of this here.

Here are described many ways to configure DANCER_CONFDIR.

Why don't I want to consider this as the definitive solution for the problem? Because I think it's still a dirty way to do things because force you to use an environment variable and disable the original App behaviour that allow each of them to have a separated config file, something that could come useful in some situations.

No comments:

Post a Comment