[ANN] Conditional Tags Extension


#1

Hello all. I’m finally releasing an extension that I’ve mentioned over
the last year on the list. I think that it has a lot of power and
potential but I could use some input from the Radiant clan.

The Conditional Tags Extension
(http://github.com/SwankInnovations/radiant-conditional-tags-extension/tree/master)
creates <r:if> and <r:unless> tags that allow for flexible (and
customizable) conditions. Start with the README there – it covers what
I’m thinking and a lot of what this thing can do.

I want this extension to be very easy to use for users (read:
non-developers) and also helpful to developers (I wrote it so that your
extensions can plug into the conditionals framework to easily add your
own values). Please help me make this one as useful as possible.

Thanks,
Chris


#2

<Mr. Burns> Eeeeeeexcellent </Mr. Burns>

While I can see the advantage of a small set of standard <if_xxx> tags
to make things easier for normal users the flexibility provided by
these tags will come in useful for the more development-minded.

Jeff

Quoting Chris P. removed_email_address@domain.invalid:


#3

Ok, upon first use I am running into a few problems (Naturally since I
said this would be useful for development-minded people and have
therefore excluded myself as murphy’s law dictates).

I am trying to use the page status as the condition and have:

<r:if condition=“status equals ‘Published’”>…</r:if>

However this results in an error on the page of:

‘if’ tag error: unable to interpret element “status” in condition

I have also tried with a “'status_id equals ‘100’” just to be sure but
that results in the same error message.

Any pointers on what I am doing wrong would be much appreciated.

Jeffrey J.

Quoting removed_email_address@domain.invalid:


#4

Chris,

I love the idea you’ve got going here. I haven’t had a chance to try
it but I have a few thoughts:

While the proliferation of tags can be bad for users, Radiant lacks
any mechanism for ensuring dependancies are installed making using
this extension within my own potentially destabilizes my extension.
This is a sufficiently fundamental thing that I’d be happier to see it
rolled into the core than distributed as an extension.
The examples in the readme all refer to things that are properties of
the page. It would be useful to better explain how something other
than the property of a page can be referred to.

As an aside, I think that there is a place for purpose specific
conditional tags. Personally I’m not convinced that

<r: if cond=“content[‘body’] exists?”> blah </r:if>

is more readable than

<r:if_content />

to someone who isn’t already a developer of some sort who understands
what a conditional is.

For example, I use Radiant for websites for a website that is managed
by a bunch of grey haired folk who think about authoring for the web
as a page was a piece of paper they put in their typewriter
(figuratively, fortunately). Radiant is a great tool for these sorts
of people, who legitimately need a good website but shouldn’t have to
pay me to $100/hr to type in their content. I’ve shown them how to
create pages and write using Textile (which is nearly perfect for
this… unless I can ben one of the WYSIWIG plug-ins to my will). Tags
are not for them (fortunately). If these folk ever write any sort of
tag, after I pick myself off the floor I’ll have to go ask them what
they’re doing and try to do it “properly”.

There are other classes of user between them and extension authors
(notably people who are not developers by trade but are hacking with
radiant to get things done) for whom purpose specific tags, while
limiting, can be a great aid to doing useful and interesting things. I
think that there is a place for these tags and I’d love it if there
was an easy way to use this to create both if_ and unless_ tags.
Something like:

conditional_tags “my_tag” do |tag|
#return a boolean
false
end

which would then create if_my_tag and unless_my_tag tags. For the if_
tag, the contents of the tag is executed when block returns true, and
the reverse happens for the unless_ tag.

This syntax combined with your generic tags would probably provide the
right level of excellence for all classes of user.

Now all we need is to simplify looping, another common tag type that
could be simplified for extension authors.

A


#5

Adam,

Thank you so much for your feedback. I like your thinking. I do have
some questions and comments for you and the rest of the gang. See
below…

While the proliferation of tags can be bad for users, Radiant lacks
any mechanism for ensuring dependancies are installed making using
this extension within my own potentially destabilizes my extension.
This is a sufficiently fundamental thing that I’d be happier to see it
rolled into the core than distributed as an extension.

If I can get this thing refined and enough users dig it, I’d love to see
it or some similar concept core. But I’m not sure I understand how my
extension could destabilize your extension. I certainly wouldn’t want
that. Can you explain what you mean?

what a conditional is.
I agree… with a couple of caveats.

* I'm sure I'd say the same about:

  <r:if_content part="part name, other part name" find="any">

  vs,

  <r:if cond="content includes_any ['part name', 'other part name']>

* <if_content part="my part"> isn't clear -- specifically that it
  test for *existence* (as opposed to whether the part has any
  content -- whether it's blank).

  Worse still is the inconsitency of meaning across tags.  For
  instance, based on <r:if_content>, you'd think
  <r:if_ancestor_or_self > means: "if an ancestor of the page exists
  or if this page exists" (which is nutty) but it means: "if *this
  contextual page is* the actual page or one of the actual page's
  parents"  Ok then, so <r:if_parent> must mean "if this contextual
  page is a parent of the actual page."  Nope.  Now have your
  clients guess what <r:if_url> does.

tag, the contents of the tag is executed when block returns true, and
the reverse happens for the unless_ tag.

This is interesting. I’ll have to think about this. Essentially what
you’re going for here is the removal of the attributes (something I
agree with). I bet my extension would be more comfortable if only you
could write:

<r:if content exists?>

I’m just concerned that the lack of descriptivity (word?) – <r:if_xxx>
is too limiting. So instead, we end up cranking out <r:if_yyy> and
<r:if_zzz> or tacking on attributes for special cases.

This syntax combined with your generic tags would probably provide the
right level of excellence for all classes of user.

Now all we need is to simplify looping, another common tag type that
could be simplified for extension authors.

True – but I think far less necessary.

-Chris


#6

That’s an easy one. It’s because I didn’t implement an evaluator for
"status. Doh!

I am working on a v0.2 right now and will add that. I think I’ll
implement “status” and have it return a string (“published”, “draft”,
etc.)

So to be more clear to everyone, in v0.1 I’ve implemented the following
symbolic elements:

* title
* breadcrumb
* slug
* url -
* author
* content:
      o content  ->  an array of page part names
      o content['part name']  -> returns the contents of the part
        (or nil if it doesn't exist)
      o content[] -> returns the body part
* content.count -> the number of page parts
* mode -> returns "dev" or "live" depeding on the site mode

One of the places I could use help from everyone is finding holes (like
“status”) so that I can put them into the extension. I would also
welcome criticism about my naming (for instance, I’ve wondered about
using “parts” instead of “content”).

-Chris


#7

Adam van den Hoven wrote:

standard way, no best practice to ensure at some point that the
requirements are met and gracefully allow the user to remedy that. Its
a Radiant problem.

Why not test for your extension’s dependencies on load? For instance,
my soon-to-be-announced variables extension has the following line in
the activate method for the extension:

raise "The Variables Extension requires that the Conditional Tags

extension be loaded first" unless defined?(ConditionalTags)

-Chris


#8

On 23-Oct-08, at 9:46 PM, Chris P. wrote:

The problem isn’t with your extension. The problem is that there is
extension be loaded first" unless defined?(ConditionalTags)
Sure that works… except that it is entirely too late IMHO. It
should be raised when you install the extension (say in the update or
migrate tasks) since that is when you are dealing with extensions. If
you were to do that for a live site running passenger then suddenly
your production site is down. You could argue that there are better
ways (I’m not convinced that capistrano is reasonable approach for
someone who isn’t a dedicated Ruby coder) but it is a reasonable way
(especially for a savvy non-coder), which is why I wrote documentation
for just that sort of approach.


#9

On 23-Oct-08, at 3:35 PM, Chris P. wrote:

This is a sufficiently fundamental thing that I’d be happier to see
it rolled into the core than distributed as an extension.

If I can get this thing refined and enough users dig it, I’d love to
see it or some similar concept core. But I’m not sure I understand
how my extension could destabilize your extension. I certainly
wouldn’t want that. Can you explain what you mean?

What I mean is:

  1. I decide to use your tag instead of creating my own special purpose
    if_ and unless tags. I document it in my README
  2. Like some existing extensions do, I inject a page or a snippet or a
    layout into the database that uses my extension and yours
  3. A user installs my extension because my announcement was so mind
    blowingly awesome but doesn’t really read the README
  4. The user’s site blows up because your extension is missing

The problem isn’t with your extension. The problem is that there is no
standard way, no best practice to ensure at some point that the
requirements are met and gracefully allow the user to remedy that. Its
a Radiant problem.

<r:if cond="content includes_any ['part name', 'other part name']>

I think that this is just at the cusp of where one leaves off and the
other starts.

  • <if_content part=“my part”> isn’t clear – specifically that it
    test for existence (as opposed to whether the part has any
    content – whether it’s blank).

This is true. But that’s a problem with the definition of either
naming (if_content_exists) or of the definition of existence. I don’t
think its an argument against the value special purpose conditional
tags as a rule.

Worse still is the inconsitency of meaning across tags.  For
instance, based on <r:if_content>, you'd think
<r:if_ancestor_or_self > means: "if an ancestor of the page exists
or if this page exists" (which is nutty) but it means: "if *this
contextual page is* the actual page or one of the actual page's
parents"  Ok then, so <r:if_parent> must mean "if this contextual
page is a parent of the actual page."  Nope.  Now have your
clients guess what <r:if_url> does.

This isn’t caused because having special purpose conditional tags is a
a bad idea. This happened because people forget the second cardinal
rule after DRY: Use intention revealing names. These have been
shorthanded.

if_ tag, the contents of the tag is executed when block returns
I’m just concerned that the lack of descriptivity (word?) –
<r:if_xxx> is too limiting. So instead, we end up cranking out
<r:if_yyy> and <r:if_zzz> or tacking on attributes for special cases.

Sorry. I was being far too brief in my example. I didn’t have my
references up (Ruby is my play time/side job language; for work I’m in
the Java world) so I was going from memory.

The conditional_tags would probably be an extension to Radius, rather
than Radiant. The tag method, takes (again from memory) a “name” and a
block that is the behaviour of the tag. I’m suggesting that this is a
similar function except that it creates two tag definitions (this is
going to require some magic to get the description right for the help)
and the block only defines a portion of of the behaviour. To do
something useful you would have something like:

conditional_tags “widget” do |tag|
tag.locals.widgets.key?(tag.attr[‘name’] || ‘foo’])
end

I suppose that it may also need a second string argument so that you
can create a widgets:each:if_widget.

This syntax combined with your generic tags would probably provide
the right level of excellence for all classes of user.

Now all we need is to simplify looping, another common tag type
that could be simplified for extension authors.

True – but I think far less necessary.

Unless, like me, you are creating an extension that introduces a new
model in which case you are likely to need:

each
first
last
count
has_next?
index

So less necessary but more time saving. :wink:


#10

Adam van den Hoven wrote:

Sure that works… except that it is entirely too late IMHO. It
should be raised when you install the extension (say in the update or
migrate tasks) since that is when you are dealing with extensions. If
you were to do that for a live site running passenger then suddenly
your production site is down. You could argue that there are better
ways (I’m not convinced that capistrano is reasonable approach for
someone who isn’t a dedicated Ruby coder) but it is a reasonable way
(especially for a savvy non-coder), which is why I wrote documentation
for just that sort of approach.

I see. Generally true but it works just fine for this extension as all
its behavior is runtime (no migrations, etc.).

-Chris


#11

happens for the unless_ tag.

This is interesting. I’ll have to think about this. Essentially what
you’re going for here is the removal of the attributes (something I agree
with). I bet my extension would be more comfortable if only you could
write:

<r:if content exists?>

This would not be valid XML.
Attributes must have a value.
http://www.w3.org/TR/xml/#attdecls

Manuel


#12

Manuel Meurer wrote:

happens for the unless_ tag.
Attributes must have a value.
http://www.w3.org/TR/xml/#attdecls

Manuel


Radiant mailing list
Post: removed_email_address@domain.invalid
Search: http://radiantcms.org/mailing-list/search/
Site: http://lists.radiantcms.org/mailman/listinfo/radiant

Radius isn’t really xml – it just eerily looks like xml. For
example, Radius will allow all kinds of characters in the tag that XML
doesn’t permit.

And that’s fine. We aren’t really marking up the document structurally
we’re just borrowing a familiar notation for a templating language.

I see no reason we couldn’t create, say, a php-radius tag extension that
parsed: <? snippet name="my snippet" ?> as a snippet tag. Or maybe ERB’s
<%%>

I really wasn’t proposing changing radius there (though I am intrigued
by the above). Instead I was looking at how the pattern of xml can make
radius tags less comprehensible. Round peg, square hole in some cases.

Another example would be creating if, else if, else structures. I don’t
see how you could use an xml-like notation to pull that off. Lucky for
us, if-then is plenty sufficient for 99.99% of all the needs for Radiant
users.

-Chris


#13

Sorry. I didn’t want to come across so preachy. I agree with you. It
bugs me too.

If, however, I ask myself whether it would bother a non-techy – someone
who not only doesn’t know xml but who’s never even heard of it – then
I’d bet nearly all would prefer something like:
<r:if x = 0> to <r:if cond=“x = 0”>

But the technical part of me still struggles with it anyway.

-Chris


#14

Ok, you’re right.
For me, <r:if content exists?> would not feel right, though.

Manuel

On Sat, Oct 25, 2008 at 8:35 PM, Chris P.


#15

Chris P. wrote:

This is interesting. I’ll have to think about this. Essentially what
you’re going for here is the removal of the attributes (something I
agree with). I bet my extension would be more comfortable if only you
could write:

<r:if content exists?>

I haven’t thought this through, but what about separating the condition,
and
having it swallow the tag output?

<r:if matches=“radiant is cool”>
<r:content />
<r:then>
This page is highly accurate!
<r:else>
Warning: This page contains factual errors.
</r:if>

I dunno if Radius can deal with “intermediary” tags like that; if not,
you
could do <r:if><r:then></r:then></r:if>, but that might get ugly. And
I’m
not sure if the whole “containing tag” concept is too painful for
non-techies. But ISTM that an “if” that can test any tag’s output is
mighty
powerful…

Jay