> Right, its almost as if one would want a pre-processing stage of not the
> output, but of the content. The current model was not built to be easily
> extendable to this as there is only one sub per XMLSubs that gets called,
> but what you would really want is something like:
>
> sub my::sub_pre()
> sub my::sub_post()
Josh- why not make it a simple directive, like a pragma-- then it could be
specified inline by the end-user whenever (and if-ever) they need it one way
or the other.
Perhaps something like:
$Apache::ASP::XMLSubsPostProc = 1
(or whatever)
And that would indicate to the system that it should enter post-processing
mode. That way you would stay compatible with current code but allow the
ability to be turned on/off as/if needed.
However, in thinking it through-- generally-speaking (while maybe not true in
every case, for most cases it would be)-- things that would get substituted a
la <% %> prior to calling the first my:sub are still available to be
substituted afterwards as long as you get back to the original scope-context.
I'm trying to think of a situation where it would be disadvantageous to delay
substitution... nothing springs to mind right off but I don't want to say
never either.
So if you had, say:
<my:sub>
<my:nestedsub><%=$blech%> __TOKEN1__</my:nestedsub>
<%=$foobar%> __TOKEN2__
</my:sub>
You could wait until after the first my:sub had been called to interpret the
rest-- just process everything post. In my thinking __TOKEN1__ and __TOKEN2__
would get resolved by the renderer function on the first pass and
<my:nestedsub>, $blech, and $foobar, would get processed immediately
afterwards-- after the tokens had been substituted.
How would that work out do you think?
> Unfortunately, any parsing of this script is quite likely to thrown lines
> numbers off from the original source.
Yeah well, life sucks don't it ;)
If it really bothered you, you could always make a note in the output that the
line numbering might be off.
> Another mechanism for might be good to use for this is to use ASPish
> global.asa events that can be called every XMLSubs execution, both
> before & after, like:
>
> sub XMLSubs_OnStart {
> my($xml_tag_name, $args, $html_input) = @_;
> }
>
> sub XMLSubs_OnEnd {
> my($xml_tag_name, $args, $html_output) = @_;
> }
This doesn't seem like a very clean solution to me, a kludge at best. If you
don't mind my saying so, I think my solution is better using the rendering
function I put forth. Its also easier and works out-of-the-box with no
additional modification.
Just delay the <% %> substitution until after the initial rendering stage and
let post-processing pick it up-- the only minor hitch is that you need to
make sure you're back in the original scope before doing the substitution.
__TOKENS__ get replaced inside the my:sub function, by the my:sub function--
whether with the render function or directly by the programmer-- and <% %>
get replaced immediately after its return.
> In an OO model, I think we could achieve something like this as in:
>
> my $pgloop = My::Pgloop->new(
> ASP => $asp,
> Attrib => { sth => $sth },
> Content => \$data_within,
> };
> my $pgimage = My::PgImage->new(
> ASP => $asp,
> Attrib => { pg=>"__PG__" sku=>"__SKU__" },
> Parent => $pgloop
> };
> $pgimage->execute(\'');
> $pgloop->execute(\$final_data_output_within);
> This pre/post processing model would allow pgimage to
> work with $self->{Parent}{sth}, or pgloop could populate
> its own data in this way. Output from pgimage could be
> trapped and inlined, passed into the execute() function
> for pgloop.
Hmm- sounds a little complicated. Not to mention you are exposing a lot of the
$asp guts to the programmer/user that way and the goal should be the exact
opposite-- to abstract that away from the programmer and toward the
web-monkey/end-user...?
> > Another useful thing might be a <def> field (define) field that could
> > construct artificial tokens based on expression-manipulation of existing
> > data available in the dataset at time of rendering. That way you could
> > have a cost field and apply a markup value to it and come up with an
> > artificial, but usable price token.
> >
> > <my:sub>
> > <define>PRICE:COST*1.2</define>
> > The cost of this item is __COST__ and it is currently selling for
> > __PRICE__. </my:sub>
> If we have a preprocessing stage like above,
That is really a weak example actually. And after thinking about it awhile, I
think I agree with you that having <define> blocks is a bad idea. While it
might be useful to have that sort of flexibility, in reality it would be a
bad idea to depend on a number hard-coded into the html body to define the
markup value of the price (to use the example)-- and might encourage
programmers (who oughta know better) to do silly things.
In my own project that I'm currently working on-- I have two major issues (at
least as bounded by the context of this discussion and in trying to resolve
it using tools developed herein)-- and they are:
1) Choosing between a Regular-Price and a Sale-Price (which are both retrieved
during the record fetch) based upon truth of the 'on-sale' flag.
2a) Wanting to have a slightly different rendering-- conditional if the item
is on-sale vs. not on-sale.
2b) Conditional blocks of code-- eg. if the item has a full-description, I
want to show it (and the header that says "Full Description" or whatever) or
nothing at all if not.
In thinking through some stuff-- token rendering is less important and so are
format strings than I was making them out to be before-- though the simple
format strings are still quite useful, imo, and eliminate more complicated
coding because.. you can always define my:subs to handle token-rendering,
formatting, and (I think) eliminating the need for explicit token definitions
(defines). So in the earlier example where it went to define a __PRICE__
token based on a __COST__ token times a multiplier, you could instead do
something like:
<my:markup cost="__COST__" mult="1.2"/>
or
<my:markup cost="__COST__" mult="<%=$mult%>"/>
if post-processing were available-- actually this particular example works
either way, doesn't it...
I think you should keep the <fmt>PRICE:%.2f</fmt> stuff available. That is
definately a handy short-cut for oft-used and simple field formatting, and
happens in an easy-to-understand way. And it doesn't get in the way of, or
preclude the more powerful xmlsub method I just illustrated.
So the earlier example could be processed like this instead:
<my:sub>
<fmt>COST:%.2f</fmt>
The cost of this item is __COST__ and it is currently selling for <my:markup
cost="__COST__" mult="1.2"/>.
</my:sub>
or using post-processing:
<my:sub>
<fmt>COST:%.2f</fmt>
The cost of this item is __COST__ and it is currently selling for <my:markup
cost="__COST__" mult="<%=$mult%>"/>.
</my:sub>
This seems like a much easier way to handle it and it fits into the current
framework much easier and with almost no modification to the current setup.
In fact, if you didn't change a thing you could still do 99% of this with the
render function-- you just couldn't deal with the post-processing bit (which
I already pointed out isn't really an issue in this particular example
anyway).
So the only real problem left comes down to handling the
"(blech>blah)?foo:bar" type logic and full-fledged conditional blocks.
> In a pre-process model, the if/else children could be evaluated by the
> parent at parent->new() time, or could look at the parent data at their
> if->new() time. If ASP <% if() { } %> will still be supported, within,
> then that could be evaluated at parent->new() time by simply doing:
>
> $output = $Response->TrapInclude(\$content);
Actually I was thinking something very similar but for another reason-- if you
use delayed processing, like I describe above, conditionals actually get
pretty easy I think. You just build them into the my:sub "$body" text and let
the post-processing pick them up.
I think you could handle the ()?: construct with a my:sub too actually-- do
something like:
<my:price reg="__REG_PRICE__" sale="__SALE_PRICE__" onsale="__ONSALE__"/>
Though it might be prettier if there were a special construct for it:
__(__ONSALE__?__SALE_PRICE__:__REG_PRICE__)__
I think would do it-- and actually, that could simply be handled by the
renderer func, and would internally get translated into:
<%=($$hash{onsale})?$$hash{sale_price}:$$hash{reg_price}%>
Which would work just fine when post-processed. Or, seeing as how you already
have the __( )__ nomenclature to distinguish it, you could even shorten the
construct to:
__(ONSALE?SALE_PRICE:REG_PRICE)__
since its going to be handled special anyway-- and that gets intuitive again.
> where that will execute the content without needing a post processing model
> at all. Hmmm, I kind of like where this is going. :) Of course its
> totally different that what we have today.
Heh- not anymore ;)
All you need to do is make the one adjustment to handle <% %> subs post
instead of pre and I think the render function can handle the inbetween
stuff. The __TOKEN__ format is very comfortable and intuitive to me in this
instance. It seems very obvious that they are serving as placeholders for
yet-to-be-in-scope data. And by delaying the <% %> processing, you allow
substitution to occur _before_ conditional blocks take place.
What is your take on all this?
I think we've just descibed a very functional, useable processing paradigm
that fits with the current "feel" of the asp system, and with the single
exception of moving <% %> substitution to post-processing, you don't have to
make any other radical changes to the Apache::ASP framework or api (at least
I don't think you do).
Your thoughts?
John
--------------------------------------------------------------------------------
Check out http://www.Wizard.Org for great deals on Electronic Parts
*NEW* Computer Parts & Accessories - Drives - LCD - Systems - Linux
--------------------------------------------------------------------------------
** Affordable Online Store w/Merchant Card Processing & Paypal **
Write to us: [EMAIL PROTECTED] -- Get your Store Online Today!
--------------------------------------------------------------------------------
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]