As an experiment, more to see if it was possible or not, I just extended %SECTION to support an "if" type and an ELSE clause. This lets you write something like this:
%SECTION{type="if" condition="defined FLUB"}%
FLUB is defined
%ELSESECTION%
FLUB is *not* defined
%ENDSECTION%
Fun, eh? The syntax is rather clumsy, but it shows how easy it is to add something like this. It's basically what the
IfDefinedPlugin does, if I'm not much mistaken, but with syntax consistent with the rest of the core.
The syntax is evaluated
after verbatim and literal sections are protected, just before the
startRenderingHandler, and before any other TWiki variables are evaluated.
This means that any TWiki variables inside the failing side of the condition are
never evaluated. So you can't "build" a
%SECTION{type="if" out of other TWiki variables (though I
have evaluated them inside the
condition value).
This construct
cannot be used to conditionally assign TWiki variables.
Patch (against rev 14684) attached. I did not write any unit tests, and I have absolutely no idea of the effect on performance. It was just an hour long experiment.
--
Contributors: CrawfordCurrie - 01 Sep 2007
Discussion
Why is the syntax of
IfDefinedPlugin inconsistent with the core? It reuses
TML as much as possible
without changing anything, even valuation order is kept as it is.
It uses the same
$percnt,
$nop and stuff known from
FormattedSearch
rather than doing anything fancy. Nothing else. Simple and very flexible.
That said, IF's syntax is inconsistent with any other syntax in the core and thus very hard to remember.
--
MichaelDaum - 01 Sep 2007
IfDefinedPlugin is
forced to be inconsistent because it is done in the common tags handler. This is out of step with the core "structured block" handlers (the code that deal with
TML blocks such as SECTION, and pseudo-HTML blocks like verbatim and literal). Not your fault, it's just the way plugin handlers work. You couldn't have done anything else without violating core encapsulation.
You have never mentioned any concerns about the syntax of IF statements before. Can you be more specific? The IF statement and
type="query" search share a common expression syntax, so if there's a problem, we really need to fix it
now rather than waiting for post-4.2.
--
CrawfordCurrie - 01 Sep 2007
The fact that IFDefinedPlugin is forced to extract blocks on its own (there is no "takeout/putback blocks" API in Func.pm) does not mean that it is inconsistent with
TML. It does so in a very sensible way.
You invented a completely island syntax for the boolean expressions in IF statements. You were
forced to implement a parser of its own, that is outside of the normal
TML parser and you still keep adding features to it. In contrast to this
IfDefinedPlugin just takes an arbitrary
TML expression and checks a regex against it. Therefore it is much leaner. Despite of its approach, IfDefinedPlugin superseeds functionality of IF plus your proposal here. So the approach I took in IfDefinedPlugin can't be
that wrong.
Baseline, IfDefinedPlugin is there to be used. If there is a problem with it we should fix it instead of inventing
the wheel once again.
--
MichaelDaum - 01 Sep 2007
Prior to the introduction of %IF, the only way to evaluate boolean expressions was using
SpreadSheetPlugin.
IfDefinedPlugin acknowledges a dependency on SpreadSheetPlugin to evaluate boolean expressions. To claim it is "leaner" is missing the point somewhat; it is dependent on either SpreadSheetPlugin (or %IF, now) for boolean expression evaluation. When I started coding %IF I looked at the SpreadSheetPlugin expression syntax - it is also an invented, non-TML syntax. I elected not to re-use that syntax for various human interface reasons.
I introduced %IF because it was increasingly the case that the core templates were becoming dependent on SpreadSheetPlugin. Personally I don't believe it is sensible to delegate such an important core concept as an IF statement to a plugin, even when that plugin is bundled with the core. The core should be able to stand on it's own.
My belief is that we need a way to express templates as efficiently as possible, and that means that the inactive side of the condition - 'then' or 'else' - must not be evaluated unconditionally, as it must be in an %IF. We can solve this problem in a couple of ways:
- Accept a core dependency on IfDefinedPlugin
- Adopt a similar approach to IfDefinedPlugin, but implement it in the core
I was aiming to address (2).
If the general opinion is that a block-structured IF statement is not required in the core, and that
IfDefinedPlugin is adequate for all end user requirements, then I'm quite happy to forget this proposal.
--
CrawfordCurrie - 02 Sep 2007
Tell you what, we can go on debating endless who invented what concept and why, which code is leaner in what terms, which syntax is more inconsistent, or wether the core is standing on its own or not. The syntaxes
are already inconsistent (
TML, SpreadSheetPlugin, IfStatement); the core does
not stand on its own (see how it neglects TWikiTables); and so on ...
I'd prefer to find the best solution for conditionals and therefore let's see what we can do. Goals:
- add conditional sections, based on what is there in IF and IfDefinedPlugin
- fix the Func Api to make IfDefinedPlugin more efficitent
First, I'd like to have takeout/putback blocks in the Func Api. Thus IfDefinedPlugin and others can make use of it. Pending proposal for 4.3. No problem.
Second, let's refine your proposed syntax. The syntax of IF is already clumbsy/no beauty. IfDefinedPlugin
gets way with less meta chars and is more intuitive to read. Let me rework you above proposal a bit:
%IFSECTION{"defined FLUB"}%
FLUB is defined
%ELSIFSECTION{"defined FLOP"}%
FLUB is not defined, but FLOP is
%ELSESECTION%
FLUB and FLOP are *not* defined
%ENDSECTION%
What do you think?
Third, how do we deal with whitespaces between blocks?
Fourth, I'd like to evaluate escaped
TML in argument positions (using $percnt and similar, to work around inside-out).
Fifth, IfDefinedPlugin does regex checks ...
--
MichaelDaum - 02 Sep 2007
to simplify Micha's eg further... and to seperate concerns, and reduce needless bundling up to make monster
TML's.
%SECTION{'superSection'}%
%IF{"defined FLUB"}%
FLUB is defined
%ELSIF{"defined FLOP"}%
FLUB is not defined, but FLOP is
%ELSE%
FLUB and FLOP are *not* defined
%ENDIF%
%ENDSECTION%
--
SvenDowideit - 03 Sep 2007
So you are saying that an IF that has no 'then' or 'else' should be treated as a %SECTION{type="if"? Hmmmm. Well, it's certainly do-able (it's just syntax).
I do not propose to support ELSIF - it's not english, and it's not necessary (it's just shorthand for %ELSE% %IF...)
I'm also not going to fix the Func API. While I agreed a fix is needed, I just don't have the energy.
BTW %IF supports the escaped
TML standard in 4.2, though not before.
--
CrawfordCurrie - 03 Sep 2007
on reflection we can't overload %IF to serve double-duty as a section and inline tag. The reason is a user can write:
* Set BLAH = "condition" then
%IF{%BLAH%="Then"}%
and the inside-out-left-right rule will ensure it expands to a valid if. However during section processing no other variables have been expanded (this is essential for late evaluation) so the section processor can't tell if this is a block-level IF or an inline IF. So we have to use Michael's %IFSECTION..%ELSESECTION%...ENDSECTION% (personally I think this is fine; I always disliked ambiguity in keywords).
--
CrawfordCurrie - 06 Sep 2007