jonswar/perl-mason

Stand-alone Mason does not load default plugins?

Opened this issue · 1 comments

Hi Jonathan,

we host a large Mason-driven site (ca. 2,000 more or less static pages). Loosely part of the site as well, there is a page registry to track internal links so we can detect orphan pages and dead links, among other convenience. The regular update process leverages Mason, so code and calls to Mason components inside are resolved properly. In a FastCGI/Plack+Poet environment, everything works fine, but when executed by the update process of the page registry, Perl chokes on the $. notation when executed by the update process of the page registry.

So I compared the list of modules loaded by Mason in the Poet environment (dummy page code: <% join "<br>", sort grep { /Mason\b/ }, keys %INC %>):

Mason.pm
Mason/CodeCache.pm
Mason/Compilation.pm
Mason/Component.pm
Mason/Component/ClassMeta.pm
Mason/Component/Import.pm
Mason/Component/Moose.pm
Mason/DynamicFilter.pm
Mason/Exceptions.pm
Mason/Filters/Standard.pm
Mason/Interp.pm
Mason/Moose.pm
Mason/Plugin.pm
Mason/Plugin/Cache.pm
Mason/Plugin/Cache/Component.pm
Mason/Plugin/Cache/Filters.pm
Mason/Plugin/Cache/Interp.pm
Mason/Plugin/Cache/Request.pm
Mason/Plugin/Defer.pm
Mason/Plugin/Defer/Filters.pm
Mason/Plugin/Defer/Request.pm
Mason/Plugin/DollarDot.pm <-- Glad it's loaded.
Mason/Plugin/DollarDot/Compilation.pm
Mason/Plugin/HTMLFilters.pm
Mason/Plugin/HTMLFilters/Filters.pm
Mason/Plugin/RouterSimple.pm
Mason/Plugin/RouterSimple/Component.pm
Mason/Plugin/RouterSimple/Component/Import.pm
Mason/Plugin/RouterSimple/Interp.pm
Mason/Plugin/RouterSimple/Request.pm
Mason/PluginBundle.pm
Mason/PluginBundle/Default.pm
Mason/PluginManager.pm
Mason/PluginRole.pm
Mason/Request.pm
Mason/Result.pm
Mason/TieHandle.pm
Mason/Types.pm
Mason/Util.pm
Poet/Mason.pm
Poet/Mason/Plugin.pm
Poet/Mason/Plugin/Compilation.pm
Poet/Mason/Plugin/Request.pm
MyWebSite/Mason.pm
MyWebSite/Mason/Compilation.pm
MyWebSite/Mason/Component/Moose.pm
MyWebSite/Mason/Request.pm

... with a list of modules loaded by Mason in the update process of the page registry:

Mason.pm
Mason/CodeCache.pm
Mason/Compilation.pm
Mason/Component.pm
Mason/Component/ClassMeta.pm
Mason/Component/Import.pm
Mason/Component/Moose.pm
Mason/DynamicFilter.pm
Mason/Exceptions.pm
Mason/Filters/Standard.pm
Mason/Interp.pm
Mason/Moose.pm
Mason/PluginManager.pm
Mason/PluginRole.pm
Mason/Request.pm
Mason/Result.pm
Mason/TieHandle.pm
Mason/Types.pm
Mason/Util.pm
MyWebSite/Mason/Component/Moose.pm

This is the relevant code:

use lib qw(/usr/local/my_web_site/lib);
use Mason 2.21; # <-- this is the version we have

sub mason_interp_for {
    my $root = shift;
    ref $root or $root = $db->resultset("Root")->find($root)
        // croak "Unknown root: $root";
    my $dir  = $root->directory;
    my $mason_root = qq{/usr/local/my_web_site/registry};
    return $mas{$dir} //= do {
        my $m = Mason::Interp->new(
            mason_root_class => "Mason",
            base_component_moose_class => "MyWebSite::Mason::Component::Moose",
            data_dir => $mason_root.'/data',
            comp_root => [
                $mason_root.'/mason_comps', $mason_root."/../comps", $dir
            ],
            static_source_touch_file => $mason_root.'/data/touch.file',
            autobase_names => ['PrepareForRegistry.mc'],
            allow_globals => ['$r'],
            top_level_extensions => [ '.html', '.htm' ],
            index_names => [ 'Welcome.html', 'index.mc', 'index.mp' ],
            dhandler_names => [ 'dhandler.mc', 'dhandler.mp' ],
        );
        $m->flush_code_cache();
        $m;
    };
}

sub compiled_mason_component_filehandle {
    my $elem = shift;
    my $mas = mason_interp_for($elem->root);
    my $meta = {};
    my $comp_output;

    eval {
        $mas->run({ out_method => \$comp_output },
            "/".$elem->path,
            elem => $elem,
            ext_meta => \$meta
        );
    };
    if ( my $e = $@ ) {
        my $file = $elem->file;
        throw WebRegistError::File file => $file,
                                   message => "Could not parse file $file: $e"
        ;
    }

    open my $fh, '<:utf8', \$comp_output
        or die "Can't open memory file handle: $!";

    return $meta => $fh;

}

Just guessing, Poet is not that kind of dependency to load no matter whether I use it or not?

So maybe is it a bug? How can I have all that missing stuff loaded? If you need further information to reproduce the problem, just contact me, I would appreciate your help very much.

Kind regards
Florian

I love to announce that I could solve that issue myself at last but that reveals things maybe worth doing in a different way. I got trapped twice:

  • Surprisingly, it is still Poet that provides the list plugins of which the Mason docs say they are default.
  • I just needed to re-read the manual carefully so I learned that the plugins are initialized properly in the Mason class constructor instead of Mason::Interp (this was how it was done in HTML::Mason). A constructor returning an instance of another class than it is defined in can provoke all kinds of spurious errors if not kept in mind.