On 1/5/03 12:39 PM, Dave Rolsky wrote:
> On Sat, 4 Jan 2003, John Siracusa wrote:
>> Anyway, I still think it's a good idea to allow for a working $m without an
>> initial component. After all, it's a "request" object, much like $r. The
>> response shouldn't have to be (even partially) determined before I can even
>> construct a working $m, IMO :)
>
> The Apache object always represents a URL call, just like a Mason
> request object always represents a comp call. Making a request object
> without a component just does not make any sense, and it's not going to
> happen. The initial component is part of the call, not the response.
IMO, that's like saying that a particular file in the file system is part of
$r. I understand that $m works differently in Mason, but there's nothing
inherent in the definition of a "request object" that implies a necessary
preexisting binding to a particular component or file or any other part of
the response.
In the specific case of $m, there are many methods that would still make
sense without a preexisting component being processed: request_args(),
abort(), error_*(), fetch_comp(), etc., and of course print(), out(),
scomp(), and comp().
I understand that it's a significant semantics change for Mason 1.x to ever
have a $m withotu a component, I suppose I could write a wrapper around an
interp that gave me most of those abilities. But perhaps in 2.x (or
whatever :) labor could be divided differently. Something like...
---
Mason Request:
* Can ask it for request params, requested URI, etc. (In mod_perl, it'd
have an Apache::Request, in CGI it'd have a CGI object, etc.)
* Used to send (or spool up and then send later) response headers and
output: out(), print(), headers_out(), etc.
* Supports "simple responses" on its own: redirect(), abort(), error pages,
etc.
Mason Interpreter:
* Parses and executes Mason components, much like the 1.x interp.
* Has a resolver-like object used to translate a component path into a
particular file in the comp root(s).
* Handles caching of compiled components and component output.
* Can send its output:
- through a Mason Request object (mod_perl and CGI environments)
- to a filehandle or file
- ???
Mason Apache Handler:
* Creates a Mason Interpreter and gives it a Mason Request object through
which to get its input (request params, POST data, etc.) and send its
output.
* Allows the interp to use its default resolver, resulting in essentially
the same behavior as the current Mason ApacheHandler.
---
The main difference between what I've described above and Mason 1.x is that
in the above setup, components that want to do web-ish stuff must first ask
the interp for its request object, and then call any web-ish methods
(redirect(), header_out(), etc.) on that.
If the interp is not being used in a web context, then the output channel
will likely be a filehandle or somesuch, in which case the components simply
cannot call web-ish methods (since they make no sense outside of a web
environment anyway).
Here's an example of a component that works in both web and non-web contexts
using this new system:
---
<%init>
# $mi = "Mason Interpreter" - global in all components
# $mr = "Mason Request"
if(my $mr = $mi->request) # if we're in a web context
{
$mr->header_out('X-Came-From' => 'MySite');
$mr->redirect('http://blah.com/blee?baz=' . );
# redirect() ends execution of component
}
</%init>
Look <a href="http://blah.com/blee?baz=<% $ARGS{'which_baz'} %>">here</a>
---
It's not really that different from the component-writer's point of view.
But the new division of labor allows customized apache handlers to be
written that can make much more arbitrary decisions about which component
(if any) gets run in response to a web request.
The default Mason ApacheHandler would look something like this:
sub handler()
{
my($r) = shift;
my $mr = Mason::Request->new($r);
my $mi = Mason::Interp->new(request => $r,
comp_root => ...,
data_dir => ...);
# $mi gets the requested URI from $mr, uses its default resolver
# to find the appropriate component in the comp root(s), and
# parses and executes the component (or prints an error or
# "not found" page, or other error handling)
return $mi->run();
}
Making a customized handler is straight-forward:
package MyHandler;
...
sub handler()
{
my($r) = shift;
my $mr = Mason::Request->new($r);
my $mi = Mason::Interp->new(request => $mr,
comp_root => ...,
data_dir => ...);
If(...)
{
return $mi->run('/foo/bar');
}
elsif(...)
{
$r->header_out('Foo' => 'Bar');
$r->send_http_header;
print "...";
return OK;
}
return $mi->run(); # default behavior
}
Something to think about maybe? Well, I think it'd be very cool and useful
anyway... :)
-John
|