SleepyJay has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to Mason-interpret a dynamically generated script, while keeping all of the Mason variables in tact.

First the easy part. I can configure my server such that a script tag with a source like "/somepath/foo.mjs" will be processed through the normal HTML::Mason::ApacheHandler code and resolve Mason stuff properly. For instance:

"... some script stuff... % print STDERR "Mason is working!\n"; % print STDERR Dumper($m->session); ...more script stuff..."

I get the proper results. Nothing special going on.

The hard part is when my script tag has a source of "/somepath/foo.dynjs". In this case, we have an Apache handler that dynamically generates the output as a Perl string using various mechanisms. Then it serves that back to the client in the usual way. However, if I happen to have a bit of Mason in that output, I cannot seem to figure out how to have Mason interpret it WITH the session in tact, before I send it back.

That is to say, I can take that string and send it through a HTML::Mason::Interp before I serve it to the client. But because that is the "stand-alone" usage, as far as I can tell, the  $m->session part is lost. And, because "/somepath/foo.dynjs" does not actually exist as a file, trying to send the $r through the prepare_request call will error out.

This has to be possible. I'm so close. Please help!

Thanks
jason.

Replies are listed 'Best First'.
Re: Mason Interp Perl string
by Anonymous Monk on Feb 09, 2012 at 20:47 UTC

    This has to be possible. I'm so close. Please help!

    :) That is kinda like asking for help getting string eval to work as you want, without showing minimal code

    What you want to do is give HTML::Mason::Interp a copy of the session

    Or re-use the existing interp instead of creating a new one

      I sort of think your two options would be great, if I knew how to do either (they might just be my question).

      I'm not sure what minimal code I can give you. Hows about:

      package Mason::MyDynHandler; sub handler { my($r) = @_; my $output = "%print STDERR $m->session\n alert("foo");"; my $mi = HTML::Mason::Interp->new( #request_class => 'MasonX::Request::WithApacheSession' ); my $c = $mi->make_component(comp_source => $output); $realOutput = $mi->exec($c); print $realOutput; return OK; }

      In the above example, I have a $r which is an Apache request. If I include the line "request_class => ...", I will be missing an 'ah' (which I assume is some ApacheHandler class, possibly HTML::Mason::ApacheHandler). If I make an HTML::Mason::ApacheHandler and try to prepare_request, it looks for the path in the request '/somepath/foo.dynjs', which doesn't exist. I would love to know how to use the "existing" interp in this context.

      I don't necessarily want to do it this way, I'm just not sure how else to do it (and this doesn't work anyway).

      I am configured something like:

      <FilesMatch "\.dynjs$"> PerlSetVar Filter On SetHandler perl-script PerlHandler Mason::MyDynHandler PerlSetVar MasonRequestClass MasonX::Request::With +ApacheSession PerlSetVar MasonSessionClass Apache::Session::File </FilesMatch>

      I don't know if this clarified anything in my question.

        Try making your handler a HTML::Mason::ApacheHandler subclass, as in
        use parent qw/ HTML::Mason::ApacheHandler /;
Re: Mason Interp Perl string
by SleepyJay (Beadle) on Feb 15, 2012 at 15:21 UTC

    I said I was going to let this go...but I didn't...and boy I wish I had.

    I can sum up my findings here. Consider this starting point...

    package Mason::TestHandler; use strict; use warnings; use HTML::Mason::ApacheHandler; our @ISA = qw(HTML::Mason::ApacheHandler); sub handler { my($r) = @_; # Remember, $r contains a virtual filename (does not exist on disk +). my @fileList = someMagicToGetFiles($r); my $testPath = $fileList[0]; # ... VARIOUS ATTEMPTS GO HERE ... # }

    Then I tried to get it to work a bunch of different ways...

    ... my $ah = HTML::Mason::ApacheHandler->make_ah($r); my $mi = $ah->interp; my $output = $mi->exec($testPath);

    This will fail with error "[error] Mandatory parameter 'ah' missing in call to MasonX::Request::WithApacheSession->new()\n"

    ... $r->filename($testPath); my $ah = HTML::Mason::ApacheHandler->make_ah($r); my $output = $ah->prepare_request($r);

    This will fail with error "[Mason] Cannot resolve file to component: /somepath/realfile.js (is file outside component root?) at /usr/lib/perl5/site_perl/5.8.8/HTML/Mason/ApacheHandler.pm line 852."

    I then tried making the path start with the exact CompRoot listed in my config (different route to same file). That gives me the error "[error] Can't locate object method "param" via package "Apache::Filter" at /usr/lib/perl5/site_perl/5.8.8/HTML/Mason/ApacheHandler.pm line 996.\n"

    I've tried different variations of the same theme, with one of these errors coming up each time. The only way I've gotten the interpreter to work is by directly creating it:

    ... use HTML::Mason::Interp; my $mi = HTML::Mason::Interp->new(data_dir => '/a/good/data/dir/' +, comp_root => '/a/good/comp/root/ +', ); my $c = $mi->make_component(comp_file => $testPath ); my $output = $mi->exec($c);

    Because my $r is valid, I can even snarf the values I need out of it. However, one of the key goals was to have valid session information. So if I add the request_class and session_class to the above, I am still missing ah (see first attempt). This ah error comes up a lot.

    Sigh. So I am completely out of ideas.

      Ok. I got it. Finally. I had given up, but one night on my drive home I got a crazy idea...and it worked.

      I created a Mason file that produces JavaScript, call it loader.mjs, that takes at least the "/somepath/foo.dynjs" as an argument in the query string. This satisfies the Mason handler's desire to have a physical file. The Mason code inside of the loader.mjs file calls the library that resolves the dynjs file, and I can $m->comp that result, and it all just simply works--session intact, etc.

      In retrospect, of course this is the easiest way to do it. And, once of thought of it, it took me hardly 20 minutes to hook all of the pieces together in the correct way (after the hours over several days trying to make it work the other way above). Sigh.

      jason.

        no help from the mason list?