Tags:
create new tag
, view all tags

Relax Restriction on registerTagHandler

I was looking into creating a Plugin to implement user-defined variables that take parameters (like those in ParameterizedVariables). The solution would seem to be to parse variable definitions in beforeCommonTagsHandler(), so I'd be calling registerTagHandler() from that handler. Unfortunately, registerTagHandler() is documented as callable only from initPlugin(). Can that restriction be lifted (since ParameterizedVariables isn't coming anytime soon)? Am I off base on how to implement this capability?

I thought I'd support syntax like this:

   * DEFCUSTOMVAR VARNAME{= param="name1" param="name2" ...} = Blah $param("name1") blah $param("name2")
-- Contributors: RobStewart - 04 Sep 2008

Discussion

What you intent to do is to discover in the topic text which variables are defined, and then register them into the tag handler?

I suggest to use a different syntax:

   * MACRO MYMACRO= This is a text with $param1 and $param2

So %MYMACRO{param1="apples" param2="oranges"% would be rendered as This is a text with apples and oranges

What do you think?

-- RafaelAlvarez - 05 Sep 2008

So basically a topic defined format="" Setting - Rafael, that sounds like a good simplification.

To extend this to the ResultSets and ExtractAndCentralizeFormattingRefactor - it would be a named alias for %FORMAT{"This is a text with $param1 and $param2" param1="apples" param2="oranges"}%

so how about

   * Alias MYMACRO = %FORMAT{"This is a text with $param1 and $param2"}%

that way we can extent the Alias concept to more than just formatting

ie

   * Alias WEBCHANGES = %SEARCH{".*" web="$web" order="modified" reverse="on"}%

and so on.

Rob and Raf - thankyou for the prompter- this is one of the unformed ideas I had when I made the ResultSets and ExtractAndCentralizeFormattingRefactor feature requests :).

to implement it, I think we could re-use the parameterised INCLUDE mechanism, using anonymous topic sections mashed with the Setting system....

-- SvenDowideit - 05 Sep 2008

@Rafael

With your simplified syntax, I presume you're suggesting that I take whatever keys are defined in the $params dictionary as the parameter names and the corresponding values as defaults. That makes sense.

However, I question using MACRO because it should be named something consistent with my plugin which I was thinking of calling CustomVariablePlugin.

@Sven

I don't want this mechanism to be tied to future TWiki versions, so while I was asking about a change to registerTagHandler(), I figured I can do what is necessary via commonTagsHandler() today. With some future TWiki version, I can switch to registerTagHandler() if the invocation context is changed. I'm also happy to choose a syntax that is forward looking, but it must function today.

Your %FORMAT% idea appears to be tied to your future work and I don't see how my plugin could use it other than to ignoring it when parsing the "Alias MYMACRO" line to get the required format. That would provide forward compatibility.

I don't want to rely upon parameterized %INCLUDE%'s because that is slower and less easily maintained.

All of this brings me back to my original question: can registerTagHandler() be called from beforeCommonTagsHandler() or am I on the wrong track?

-- RobStewart - 05 Sep 2008

Theoretically, it can. From what I understand from the code the only drawback is that any call to TWiki::handlecommonTags and TWiki::Func::expandCommonVariables before your plugin register those dynamic variables, they won't get expanded. But in your case it should work for what you want.

Regarding the syntax, I was thinking along the lines of something that is easily recognizable by users. The syntax of a plugin is important because once it is deployed, is a nigthmare to change once the users start using it.

Also there was a lengthy semantic discussion on Codev about what is a variable and whay is a macro, and would not like to have it again smile

-- RafaelAlvarez - 05 Sep 2008

Your point about the two functions is that the order of plugins may be important, right?

I'm happy for syntax that is "easily recognizable by users," but I'm not sure what you mean WRT my comments on your suggestion. Will the following suit you?

* DEFCUSTOMVAR VARNAME{ param1 = "default1" param2 ...} = Blah $param1 blah $param2

Is it that you're trying to say that I really should use MACRO? Please clarify.

-- RobStewart - 07 Sep 2008

Rob, I wasn't trying to say you should wait - I was hoping more that you might be interested in considering a more general solution - or even coding up a first cut of the twiki5 feature as your plugin smile

Some of where you implement this (now) is going to depend on how fully you are wanting to do this - ie, the same settings inheritance struction as other VARS (TWikiPrefs, WebPrefs etc), in which case you might be better off doing something more sneaky.

ie

   * Set ALIAS_MYMACRO = %ALIAS{"MYMACRO" output="This is a text with $param1 and $param2" param1="somedefault" param2="another default"}%
Then in initPlugin (i think) you can grab all the preferences prefixed with ALIAS (thus getting the right alias, which can be over-ridden neatly), then use the value to register the tag handler you want.

originally I was wondering if you could use the %ALIAS as a handler right now, but that would mean you have to replicate the settings mechanisms - it seems more consistent to just use what's there.

(yes, I think you'll have to break the encapsulation of TWiki::Prefs to get a list of 'set' values, but if you do, we can see about adding that method to TWiki::Func next time around - the plugins api is driven by needs, not rules)

-- SvenDowideit - 07 Sep 2008

You're going over my head. I don't know the TWiki engine at all. I looked at EmptyPlugin.pm and I read a couple of starter topics, including the TWiki::Func API, but that's all I know.

I'd be happy to implement something that will help you with TWiki5, but you'll have to help me along. I do want to support TWiki, Web, and topic settings, but I question using the Set keyword for this purpose. I think a bullet with a different keyword, but with the same structure as that for Set bullets is in order.

In keeping with recommended practice, I was proposing "DEFCUSTOMVAR" to resemble my plugin name. However, if you'd like, we could adopt a more forward looking syntax and I'm happy to implement it any way you see fit with the expectation that the core will catch up. (I think that means I should implement some functionality in a contrib to keep the plugin uncluttered with the sneakiness.)

I don't like your suggested syntax because it will prevent certain kinds of TML/HTML markup in the output or it will make escaping things necessary. I also prefer to define the params and their defaults in the name declaration rather than later as you've done. What do you think of this syntax?

   * Define MACNAME{ param1 = "default1" param2 ... } = Text with ${param1}&$param2

Does initPlugin() have access to the text in order to parse prefs like this? Perhaps there should be a handler for preferences of the general form

   * Tag NAME = VALUE

Then, initPlugin() would be the place to register a preference handler, by tag: registerPrefHandler("Tag", &_TAG). That obviously won't work with current TWiki releases unless there is some means for a contrib to intercept lines as they are read from the preferences topics and from the current topic.

I don't know what you're referring to by breaking the encapsulation of TWiki::Prefs to get a list of set values. As for the plugin API being needs driven, not rules driven, I'm pleased to hear it.

-- RobStewart - 07 Sep 2008

Rob, my concern with DEFCUSTOMVAR is that is is long and "geeky" smile Using a word that is easily recognizable by users (Macro, Alias, Define, Tag) is better.

Regarding the two functions calls, it is not about the ordering of the plugins. It is more about the order of TWiki operations. But I think that you should be safe.

-- RafaelAlvarez - 08 Sep 2008

Rob, it will prevent certain kinds of TML/HTML markup - you're going to have to qualify that - because as I elaborate (and Crawford mentioned previously) in ParameterizedVariables, using $ style variables is going to cause an escaping mess, and add to parsing complexity.

The reason I suggest you use the existing set mechanism, is that otherwise, you will need to duplicate that functionality yourself in your plugin. What I describe above is (I think) the simplest thing that you can do without making changes to the core code.

It would mean that you can use initPlugin to grab the ALIAS_* settings, parse just those that are relevant right now and then register the needed TagHandlers, rather than having to search through the same heirachy of topics, make a tree, evaluate the current stack etc

if you use a sytnax like

   * Set LINKREV{TOPIC="%BASEWEB%.%BASETOPIC%" REV=""} = [[%SCRIPTURL%/view/%TOPIC%?rev=%REV%][%TOPIC% r%REV%]]
and a mechanism like that of the parameterized Includes, you'll probably be there pretty quickly.

-- SvenDowideit - 08 Sep 2008

I'll second Sven's comments. All registered variables are currently able to accept parameters, even those that do not actually use them. The * Set line is the natural place to define acceptable parameters. I had this in mind when I coded the parser, but never carried it through to the natural conclusion.

Some parameters do not have useful default values, so it is necessary to support unvalued parameter names. It is also necessary to support the standard escapes for expansion in the default values.

   * Set LINKREV{topic="%BASEWEB%.%BASETOPIC%" rev format="$percntX$percnt"}%
The toughest challenges in all this (and it's really not that tough) are:

  1. to write a replacement fo $TWiki::regex{setVarRegex} that works with the new syntax.
  2. to work out where to push the parameter values into the scope

-- CrawfordCurrie - 08 Sep 2008

Low hanging fruits? wink

-- FranzJosefGigler - 08 Sep 2008

@Sven

Collapsing complex markup into a string makes things difficult, even impossible. I don't have specific examples in mind ATM.

I understand your concern regarding $ delimited variable names. I have no problem with using %name%, but I do think lower case is a good idea to reduce naming conflicts with normal variables. I also think the parameter variable names should have an implicit prefix of VARNAME_.

As for reusing core code versus duplicating some portion before a better solution appears, I don't mind doing the best thing versus the most expedient.

You mentioned the parameterized includes mechanism. I presume you're referring to the mechanism that injects variable definitions into the included file's context but not that of the including file. I don't know how that works and I don't know how it applies, but I'm happy to learn.

@Crawford

I hadn't considered that all variables take parameters now, even if ignored, but I see your point about using Set.

Do I have to do anything special to support standard escapes?

I presume that $TWiki::regex{setVarRegex} is used to match the Set bullets. I think changing that will be pretty easy as the brace delimited parameter list will be optional and I assume that the capture for the content following the = won't care about its formatting. I can imagine that the variable references in the right hand side will look really odd if there are extant TWiki variables, with the same name, already defined.

I have no idea where or how to push the parameter values into the current scope, so I welcome any ideas.

-- RobStewart - 08 Sep 2008

As always there's no substitute for reading code. Here are some pointers:

  • I would highly recommend starting by writing documentation and unit tests for the syntax you want to support. There is already a unit test module for the basic syntax of TWiki variables, in UnitTestContrib/test/unit/VariablesTests.pm. Individual variables are tested using the Fn_ tests in the same directory. Writing unit tests up front will save you a lot of pain later on.
  • %INCLUDE supports parameters, so by tracing through the %INCLUDE handling (start at sub INCLUDE in TWiki.pm, at # copy params) you should be able to see where the parameters are pushed into a new temporary context that is live for the duration of the include. You should be able to re-use this pattern.
  • You will have to decide when it is appropriate to expand standard escapes. These escapes are expanded by sub expandStandardEscapes and there are various examples of it's use floating around the code.
  • You are going to have to extend the way TWiki variables are stored so that you can also store the parameter specs. TWiki/Prefs.pm contains the bulk of the handling code.
  • You are going to have to extend the mechanisms by which preferences values are retrieved - i.e. getPreferencesValue. At the moment this takes a single parameter - the name of the preference - but you are now talking about passing parameters to this, so you're going to have to design an appropriate API for TWiki::Func. I'd suggest passing named parameters e.g. TWiki::Func::getPreferencesValue("BLAH", topic=>"blah", format=>"blah $blah blah").

-- CrawfordCurrie - 09 Sep 2008

sorry, Collapsing complex markup into a string makes things difficult, even impossible. I don't have specific examples in mind ATM. doesn't resonate with me - I can't decide if i think you are just plain wrong, or if the statement means something frown

nonetheless - it'll all make more sense once you have some code, and can play with the consequenses of your choices smile

-- SvenDowideit - 09 Sep 2008

@Crawford

Wow. I was not expecting this to be so complicated. I guess I'll have to come up to speed on TWiki and learn even more Perl. (I can write some Perl, but there's a great deal I don't know about it. Even passing named parameters, as you illustrated, is new to me.) My experience is with various other languages and only a little Perl.

-- RobStewart - 11 Sep 2008

Rob, sorry, it wasn't my intent to drown you in detail, but there is quite a lot to know before embarking on something this close to the TWiki core. What you want to do is on the face of it fairly simple, but TWiki is quite big and you don't want to make it angry by poking in the wrong places. Don't let the fact that it's perl daunt you; I was at the same stage when I started contributing to the core. My own background is strongly OO (Smalltalk/C++/Java), but IME once you have grasped the basics if Perl the rest is fairly obvious.

-- CrawfordCurrie - 12 Sep 2008

Edit | Attach | Watch | Print version | History: r17 < r16 < r15 < r14 < r13 | Backlinks | Raw View | Raw edit | More topic actions
Topic revision: r17 - 2008-09-12 - CrawfordCurrie
 
  • Learn about TWiki  
  • Download TWiki
This site is powered by the TWiki collaboration platform Powered by Perl Hosted by OICcam.com Ideas, requests, problems regarding TWiki? Send feedback. Ask community in the support forum.
Copyright © 1999-2017 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.