Tags:
archive_me1Add my vote for this tag create new tag
view all tags

Implemented: Parameterized Includes

Summary: Allow topic INCLUDEs to pass parameters to the included topics in a similar manner like parameters get passed to functions in a programming language. This allows topics to control the behaviour of an included topic.

This became spec in Dakar. See VarINCLUDE -- MartinCleaver - 04 Sep 2008

Proposed syntax

Topic including another topic, e.g. "function call": Add any named parameter to the include, like:

  • %INCLUDE{ "OtherTopic" anyname="anyvalue" foo="bar" }%
  • Special characters in the value need to be escaped, use $n() for new line, $quot() for double quote, $lt() for less-then sign, $gt() for greater-than sign, $nop() for a no operation. Example: table="|*Lunch:*|Sushi|$n()|*Dinner:*|Lobster|"

Included topic, e.g. "function": Introduce new %PARAM{ "name" default="value" }% variable with parameter name and default value, like:

  • Do something with %PARAM{"anyname"}% parameter and %PARAM{"foo"}% parameter
  • A default parameter sets the value in case the parameter is unspecified, like %PARAM{ "lunch" default="Sushi" }%
  • The %PARAM{}% variable gets removed silently when directly looking a topic, e.g. if topic is not included

Merge %URLPARAM{"anyname"}% and %PARAM{"name"}%:

  • The existing %URLPARAM{"anyname"}% as documented in TWiki variable gets renamed to %PARAM{"anyname"}%
  • The %URLPARAM{"anyname"}% variable is deprecated but remains implemented for compatibility.
  • The INCLUDE parameter is used in case the encluded topic encounters a URL parameter and an INCLUDE parameter of the same name.

The variable get rendered early, that is, PARAM works without special escape in case it is nested inside other variables. This is a valid example where an included topic includes a web page:

  • %INCLUDE{ "http://www.cia.gov/cia/publications/factbook/geos/%PARAM{ "countrycode" default="np" }%.html" }%

Note: all parameters in the INCLUDE directive are passed to the included topic, including those that are normally actioned by the INCLUDE directive itself. If those named parameters are not utilized by the included topic, then they are simply ignored. It is recommended that parameter names that are not used by the INCLUDE directive itself utilize a leading underscore "_" with formal parameter names to avoid any possible name contention should the native parameters for the INCLUDE directive be extended.

Example

Let's say you like to quote material in your topics, in a box constructed with a table.

This is quoted text.

Instead of needing to provide the html for this, we can include a topic, let's call it "QuoteInclude" which is only the box with a replacable parameter, as follows:

Topic: QuoteInclude

<table bgcolor="#FFFF00" border=2 cellpadding=10><tr><td>
%PARAM{"quotedtext" default="(Nothing to say)"}%
</td></tr></table>

Then, this can be called somewhat like a function call from another topic, like this:

Topic: ExampleUsingQuoting

Here is Bill said in his email:
%INCLUDE{"QuoteInclude" quotedtext="I like pie."}%

Here is what Jane said:
%INCLUDE{"QuoteInclude" quotedtext="I like cake."}%

Here is what Fred said:
%INCLUDE{"QuoteInclude"}%

And here is the result of viewing the topic ExampleUsingQuoting:

Viewing Topic: ExampleUsingQuoting

Here is Bill said in his email:

I like pie.

Here is what Jane said:

I like cake.

Here is what Fred said:

(Nothing to say)

Contributors:
-- RaymondLutz - 20 Nov 2003
-- PeterThoeny - 21 Nov 2003


Discussions and feedback

The proposal is to allow parameters to be passed as an INCLUDE is expanded and substituted in the included file as the expansion is performed. This would only be appropriate (I would think) when the topic included is from the local TWiki site (although as I reflect on this question, it may be perfectly appropriate to include from a more general site of "TWiki Functions" -- more reflection on that later.)

Example

A good example of using this would be as follows.

I tried to do generalize what I was setting up recently at the http://www.globalswdev.org/twiki site at http://www.globalswdev.org/twiki/bin/view/Resources/Region . In this situation, I wanted each region to be able to suck data from the CIA Fact Book site, for each of the countries. The TWiki code (INCLUDES) are virtually the same, except the pages that are accessed are at a slightly different URL, i.e. the country code is say in instead of np. I struggled to find a way to set TWiki variables or some other approach to be able to have one topic that had the INCLUDEs for each part of the information I wanted to suck from their site, with the ending modified.

To illustrate this more concretely, consider the following topic for the India Region, which includes three countries. This is how we have it coded now, as I have not found a solution to this problem yet.

   * *India*
      * CIAFactbook:in
      * *Historical Background:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/in.html" pattern="^.*?Background:.*?<br>\s*(\S.*?\S)\s*<\/td>.*"}%
      * *Economy:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/in.html" pattern="^.*?Economy - overview:<\/div>.*?<br>\s*(\S.*?\S)\s*<\/td>.*"}%
      * *Industries:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/in.html" pattern="^.*?Industries:<\/div>.*?<br>\s*(\S.*?\S)\s*<\/td>.*"}%
      * *Internet Service Providers:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/in.html" pattern="^.*?Internet Service Providers \(ISPs\):.*?<br>\s*(.*?)\s*<\/td>.*"}%
      * *Literacy:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/in.html" pattern="^.*?Literacy:<\/div>.*?<br>\s*(\S.*?\S)\s*<\/table>.*"}%
      * *Languages:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/in.html" pattern="^.*?Languages:<\/div>.*?<br>\s*(\S.*?\S)\s*<\/td>.*"}%

   * *Nepal* 
      * CIAFactbook:np
      * *Historical Background:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/np.html" pattern="^.*?Background:.*?<br>\s*(\S.*?\S)\s*<\/td>.*"}%
      * *Economy:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/np.html" pattern="^.*?Economy - overview:<\/div>.*?<br>\s*(\S.*?\S)\s*<\/td>.*"}%
      * *Industries:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/np.html" pattern="^.*?Industries:<\/div>.*?<br>\s*(\S.*?\S)\s*<\/td>.*"}%
      * *Internet Service Providers:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/np.html" pattern="^.*?Internet Service Providers \(ISPs\):.*?<br>\s*(.*?)\s*<\/td>.*"}%
      * *Literacy:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/np.html" pattern="^.*?Literacy:<\/div>.*?<br>\s*(\S.*?\S)\s*<\/table>.*"}%
      * *Languages:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/np.html" pattern="^.*?Languages:<\/div>.*?<br>\s*(\S.*?\S)\s*<\/td>.*"}%
   
   * *Pakistan* 
      * CIAFactbook:pk
      * *Historical Background:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/pk.html" pattern="^.*?Background:.*?<br>\s*(\S.*?\S)\s*<\/td>.*"}%
      * *Economy:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/pk.html" pattern="^.*?Economy - overview:<\/div>.*?<br>\s*(\S.*?\S)\s*<\/td>.*"}%
      * *Industries:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/pk.html" pattern="^.*?Industries:<\/div>.*?<br>\s*(\S.*?\S)\s*<\/td>.*"}%
      * *Internet Service Providers:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/pk.html" pattern="^.*?Internet Service Providers \(ISPs\):.*?<br>\s*(.*?)\s*<\/td>.*"}%
      * *Literacy:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/pk.html" pattern="^.*?Literacy:<\/div>.*?<br>\s*(\S.*?\S)\s*<\/table>.*"}%
      * *Languages:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/pk.html" pattern="^.*?Languages:<\/div>.*?<br>\s*(\S.*?\S)\s*<\/td>.*"}%

My first thought was this, using the TopicVarsPlugin

   * *India*
&lt;!--
   * Set COUNTRYCODE = in
--&gt;
%INCLUDE {"CountryInfo"}%

   * *Nepal* 
&lt;!--
   * Set COUNTRYCODE = np
--&gt;
%INCLUDE {"CountryInfo"}%
   
   * *Pakistan* 
&lt;!--
   * Set COUNTRYCODE = pk
--&gt;
%INCLUDE {"CountryInfo"}%

With the topic CountryInfo as follows:

      * CIAFactbook:%COUNTRYCODE%
      * *Historical Background:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/%COUNTRYCODE%.html" pattern="^.*?Background:.*?<br>\s*(\S.*?\S)\s*<\/td>.*"}%
      * *Economy:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/%COUNTRYCODE%.html" pattern="^.*?Economy - overview:<\/div>.*?<br>\s*(\S.*?\S)\s*<\/td>.*"}%
      * *Industries:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/%COUNTRYCODE%.html" pattern="^.*?Industries:<\/div>.*?<br>\s*(\S.*?\S)\s*<\/td>.*"}%
      * *Internet Service Providers:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/%COUNTRYCODE%.html" pattern="^.*?Internet Service Providers \(ISPs\):.*?<br>\s*(.*?)\s*<\/td>.*"}%
      * *Literacy:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/%COUNTRYCODE%.html" pattern="^.*?Literacy:<\/div>.*?<br>\s*(\S.*?\S)\s*<\/table>.*"}%
      * *Languages:* <BR>%INCLUDE{"http://www.cia.gov/cia/publications/factbook/geos/%COUNTRYCODE%.html" pattern="^.*?Languages:<\/div>.*?<br>\s*(\S.*?\S)\s*<\/td>.*"}%

The problem is that TWiki Variables are global, and are set according to the last found instance of the Set VARIABLE = value found in the web. In this case, I would get three copies of the pk (Pakistan) information.

Perhaps, the following would be possible (other ideas are welcome). In this case, assume the same topic CountryInfo exists as described above:

   * *India*
%INCLUDE {"CountryInfo" parameter('COUNTRYCODE','in')}%

   * *Nepal* 
%INCLUDE {"CountryInfo" parameter('COUNTRYCODE','np')}%
   
   * *Pakistan* 
%INCLUDE {"CountryInfo" parameter('COUNTRYCODE','pk')}%

With topics acting like subroutines, the concept could be logically extended to have a set of TWiki Function Topics that could be included from anywhere, and would provide a whole topic with parameters passed to it. Right now, you can pass parameters to "Operators" like INCLUDE and SEARCH, but not to entire topics. This inclusion with parameters would provide that functionality and would further leverage third-party implementors who would like to provide standard topics, and sets of topics that perform perhaps sophisticated operations, but the topics really don't exist on the TWiki, but are supplied elsewhere. Hmmmm.

(It may be time to split TWikiVariables up into two groups, TWikiVariables and TWikiOperators. It may also be appropriate to view this as a more formal language definition.)

(MS made some suggestions related to this topic via email.)

-- RaymondLutz - 20 Nov 2003

I since went away and implemented this. (Part of the chaos branch - http://chaos.owiki.org/ParameterisedIncludes - change set here)

-- MS - 20 Nov 2003

Perhaps you could specify the details of the syntax you elected to use. I noted that you are missing (See FIXME in code) the decoding of a single url value. You may want to adopt the following code:

#-------------------------------------------------------------------
sub decode_field { my ($field) = @_;
    $field ||= '';
    $field =~ tr/+/ /;
    $field =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
    $field =~ s/\s*$//;                 # trim trailing spaces
    return $field;
}

I would encourage the development team to generate standard library of such utilities instead of coding obtuse perl with no comments that is instantiated in every place it is needed. Subroutine calls are less expensive.

Also, I noted the implication in your http://chaos.owiki.org/ParameterisedIncludes topic, you indicate that it would not be suitable to use such parameter substitution for http-hooked pages. Why not?

    Raymond,

    Syntax can be found here. You'll note the aim is to replace URLPARAM rather than more syntax. (simpler, more flexible, more othoganal and hence more powerful - as noted below)

    Regarding:

    > Also, I noted the implication in your http://chaos.owiki.org/ParameterisedIncludes topic, you indicate that it would not be suitable > to use such parameter substitution for http-hooked pages. Why not?

    That's not what I intended - I intend it as a complete drop in replacement. Indeed that's where it's most powerful. After all, the same topic that powers the example here: http://chaos.owiki.org/ParameterisedIncludes also powers this remote transclusion example: http://chaos.owiki.org/AnySectionAnyTopic?remotetopic=NamedIncludeSections - this is only possible if you allow the hook to work in an http scenario as well. This just allows it to work in a non-http scenario.

    If there was a dedicated "INCLUDEPARAM" you fail to gain these kinds of benefits getting duplication throughout your application. (ie it discourages code reuse - unlike the example of this syntax at http://chaos.owiki.org/PatchAvailable, which pulls in a parameterised include "function" from a library of "routines" on http://chaos.owiki.org/ClueSkinSections which will be used in an autoloader style fashion when I implement topic aliases )

    The topic contents is just:

    ---+ %INCLUDE{"%PARAM{"requesttopic" default="ParameterisedIncludes"}%" section="title"}%
    %INCLUDE{"%PARAM{"requesttopic" default="ParameterisedIncludes"}%" section="%PARAM{"section" default="synopsis"}%"}%
    

    Which if the twiki here supports INCLUDEs (does it? looks like twiki.org doesn't allow remote includes as of 21/Nov/2003) would be used:
    You type:

    %INCLUDE{"http://chaos.owiki.org/AnySectionAnyTopic?remotetopic=NamedIncludeSections"}%
    
    You get: %INCLUDE{"http://chaos.owiki.org/AnySectionAnyTopic?remotetopic=NamedIncludeSections"}% (Given this fails here, see http://chaos.owiki.org/ParameterisedIncludes for the working example)

    Regarding your code fragment - thanks I'll incorporate that, however it'll probably only get used if there isn't a cgi query available - since the unescaping of URLencoded content is best done by CGI.pm since it's tried & tested, and there' irritating edge cases that can happen in certain scenarios which would need dealing with (normally relating to double encoded things getting passed as parameters).

    -- MS - 21 Nov 2003

-- RaymondLutz - 21 Nov 2003

Raymond, nice idea, it fits nicely the TWikiMission and moves TWiki more towards an application platform smile

Added proposed syntax on top. Feedback appreciated.

A simple example is needed. Raymond, your example is good but somewhat complex. Possibly a silly "hello world" example for illustration purposes only.

-- PeterThoeny - 21 Nov 2003

Problems with proposed spec:

  • How can we pass a more lengthy parameter, i.e. one with embedded newlines, HTML, etc.?
    • Similar to the SEARCH format, e.g. we can define special tokens like $n() for newline. I updated proposed spec -- PeterThoeny - 22 Nov 2003
  • Side issue: </verbatim> does not operate correctly as it does not gobble the following newline, although it is required to be on a separate line. That is why there is an extra blank line in all of the quotation boxes used above.

-- RaymondLutz - 21 Nov 2003

Raymond, thanks for the example. For simplicity I would simply remove the verbatim from the usage example.

Questions on URLPARAM and INCLUDEPARAM duality:

  • URLPARAM and INCLUDEPARAM are similar. Does it make sense to merge them?
  • If yes, what name?
    • Probably best to call it simply PARAM; for backward compatibility, the URLPARAM would get an undocumented feature.
  • In case a URL parameter and an include parameter are present, which one has precedence? For example, there is a URL parameter lunch=Sushi present, the including topic specifies a lunch="Dim Sum" parameter, and the included topic has a %PARAM{"lunch"}% variable.

Question on including a URL:

  • Is there a need to support parameters in included web pages? That is, expand %INCLUDEPARAM{...}% variables if encountered in an included web page. Technically it would be simple to implement.

I think it is worth while to take some time to define a solid spec; hastily implementing something might impose a roadblock in the future.

-- PeterThoeny - 22 Nov 2003

Peter said: For simplicity I would simply remove the verbatim from the usage example.

  • Ergo; for simplicity I just removed the verbatim from the usage example wink -- PeterThoeny - 25 Nov 2003

I had it that way, but I could not include the text of the QuoteInclude topic without expansion. That is, I desired to display the content of the QuoteInclude topic but not render it. Here are some issues that seem to exist that we should try to resolve.

  • Recursive Inclusion: There should be some limitation to accidental recursive inclusion, i.e. one topic including another. Off hand, I can't think of a time that this would be necessary, but perhaps someone else can think of an example. If we can't think of an example, it would be prudent to ignore any time a topic attempts to include itself.
    • This is already covered by the INCLUDE code -- PeterThoeny - 25 Nov 2003
  • Name of PARAM or INCLUDEPARAM: Probably PARAM is more general and would be a good choice, but I really don't care. For backward compatibility, we probably need to continue to support URLPARAM.
    • Updated proposed spec accordingly -- PeterThoeny - 25 Nov 2003
  • Expansion of TWiki operators in arbitrary URLs: This goes a bit further than just assuming that parameters would be expanded. All TWiki Operators (aka variables) would be potentially actioned. This is desired as it will allow people to provide a library of includable topics to provide formatting and functionality.
    • This already happens for regular variables unless the included web page is put into verbatim tags. So it makes sense to do the same with the PARAM -- PeterThoeny - 25 Nov 2003
  • We might need another sort of "verbatim" operation where the content of the page will be displayed without various levels of rendering. You can't just enclose the %INCLUDE in <verbatim> tags as it won't be actioned. This is particularly true in the case of the arbitrary URL question mentioned above.
    • Not sure, but a verbatim in a verbatim should be supported. Updated the proposed spec with $lt() and $lt() escapes, useful to escape verbatim if passed to an include. -- PeterThoeny - 25 Nov 2003
  • Non-literal parameters: In the examples I used above, let's say you wanted to quote an entire email, using the quoting boxes defined by QuoteInclude. There is currently no way to do that. Using arbitrary syntax for discussion, I would like to propose local parameters that have temporal qualities like any other programming language.

%LOCAL{"email" = %BEGIN%
To: Joe Blow
From: Jim Bob
Subject: Did you receive the report?
Hi Joe:
I sent you a report by physical mail. Please let me know when you receive it.
Thanks.
--Jim
%END%}%
%INCLUDE{"QuoteInclude" quotedtext=%PARAM{"email"}%}%

Here, I am also assuming that you can define local variables, that exist only within the current topic, and maintain the value after the time it is defined until it is redefined or the end of the topic is found. In other words, the local variable could be used for different values as the topic is expanded. For example:

%LOCAL{"who"="Jim"}%
The persion was %PARAM{"who"}%.  <-- returns Jim
%LOCAL{"who"="Bob"}%
The persion was %PARAM{"who"}%.  <-- returns Bob

That is a start. I think there are other cases but I am out of time at the moment.

-- RaymondLutz - 24 Nov 2003

The local variable is an interesting idea, best to follow up in LocalTopicVariables. Could (should?) be implemented as a Plugin. See related $set() and $get() of the SpreadSheetPlugin. See also related TopicVarsPlugin.

-- PeterThoeny - 25 Nov 2003

You are right that the local variable question will not stop us from going ahead with providing parameters, as long as we realize that the functionality of INCLUDE with simple (only literal) parameters will serve only so far. Of course, I guess you could force the existance of one-liner variables by including twice, with the variables then called %PARAM{"variablename"}% by the secondary include. The big problem with variables, that can be addressed separately, is that they can only be simple character strings, and not other data types, such as a file or hash.

After this holiday weekend, I was able to reflect on this situation a bit more, and will propose that we back up a bit more and consider defining a TopicObjectModel, because I see other problems with the way variables are being handled now, as well as the concerns about the (I claim inappropriate) nesting of meta tags in the topic object. The method of development for TWiki, due to the inherent nature of splitting topics into small topics, and encouraging plugins seems to result in a development track that is rapid, but does not necessarily follow a larger architectural structure. As there is no real rush, we may want to wait on adding anything to INCLUDE, but I still am a proponent of splitting the INCLUDE code into a separate code module, Include.pm.

-- RaymondLutz - 01 Dec 2003

I think we can go ahead with the implementation, the spec on top looks now solid.

The changes are not that complex, I suggest not to introduce a new module just for that.

-- PeterThoeny - 10 Dec 2003

FYI I did both parameterised includes and local variables in the FormQueryPlugin (see %CALLMARO and %SET). The only gotcha was getting the scoping of locals right.

I thought there was a move to shift more into plugins, not pile more lard wink into the core. Given that I was able to do it in a plugin, should this really be part of the core?

-- CrawfordCurrie - 10 Dec 2003

I agree that this is ready for implementation, with limited support of variables, i.e. literals only. We can extend that later.

The act of splitting the %INCLUDE% code to a isolated module does not have to do with the complexity of the current request, it is a function of moving distinct features into separate modules that can be managed separately, important for design of any system with multiple contributors. If you wish to maximize progression, there will be general support of moves to segment distinct functions into their own module. On the other hand, if there is a (perhaps unstated) desire to maintain control of the code by an individual as opposed to a group, to make it difficult for others to advance, and make it prone to requiring multiple changes in many modules to support it, then being for a more monolithic design will be supported. Since this is your "baby", PeterThoeny, I assume you will have to work to release your progeny to the world. There are other things that I want to do with the INCLUDE functionality, such as using LWP and page caching. It will be a bit more elegant to do so if I can replace an entire module rather than monkey around with the "core".

Supporting more "lard" as plugins vs. "lard" in core is not necessarily a good design decision. Functions that are very useful and are key to many uses of the system should be integrated into the "core", and not as ad-hoc plugin add-ons. Now, INCLUDE is not a plug-in, so I don't support making it one just to extend its functionality slightly. I am interested to see the concept used for variables in FormQueryPlugin, and the fact that a macro functionality is available there is news to me. That is one drawback to tons of lard as plugins in that you are not sure if they are 1) decent 2) useful 3) well documented and 4) in which plugin the functionality lies. I was told that SpreadSheetPlugin was the answer, but I beg to differ. The syntax and documentation of that plugin, is poor. I can spend only so long trying to figure how how to use it, and they don't span topic boundaries.

I assert that more work is needed on the definition of variables, and I have started an analysis of the situation in TopicObjectModel.

-- RaymondLutz - 10 Dec 2003

The discussion about modularisation has ranged far and wide, but the piece I recall making sense related to the incremental shift to an object model for the core. In my dreams I imagined this meant that the core would be lightened, and functionality moved into code/objects peripheral to the core. These peripheral objects/modules may be plugins.

Of course, in this model not all plugins are equal; some are more equal than others. Some plugins may be indistinguishable from the core to the end installer.

Think of it this way; that there is the TWiki core, a light, extremely fast, functional wiki implementation. Only what is absolutely needed is incorporated in the core (and we've survived without parameterised includes for some time now.... someone please point me at the killer app).

Around this core are ranged the "official plugins", shipped in the standard distribution and coded and supported to the same high standard.

Beyond that is what AndreaSterbini characterised as Dante's inferno - the Plugins web.

There's a bit of learning from TikiWiki here. When you install Tiki, you select the features you want to enable. As the feature set you use grows, performance suffers.

This feature enhancement is a lovely opportunity to demonstrate this model, because as I have shown, parameterised includes don't have to be implemented in the core of the core, but can be done using the existing plugins API. Sticking my neck out, I think everything you characterise as "Directives" in TopicObjectModel can be done this way.

-- CrawfordCurrie - 11 Dec 2003

I think you're preaching to the choir here, at least for me. I would be happy to see more modularization, and identifying minimal features as 'core'. But, I'm also a pragmatist, and I am trying to get sites to work. For the applications I usually encounter, the concerns about keeping an absolute minimal set of functions is not important, and in terms of processing speed, there are other ways to keep everything operating fast other than decreasing functionality. For a community project like TWiki, keeping things organized and partitioned cleanly is perhaps more important than worrying about smidget changes in performance. It turns out that INCLUDE is coded directly in the core module, i.e. TWiki.pm. This is wrong mostly because INCLUDE is simply one of the directives and one that many topics will never use. It should not be included in the core for both reasons:

  • INCLUDE is a directive that can be fully encapsulated in its own module (Include.pm), thereby improving code organization.
  • INCLUDE does not need to be loaded for MOST topics, and if dynamically loaded when needed, can improve performance.

I have still to fully study the code of TWiki, but when I have been interested in small code and fast operation, it means interpreting a minimum of code, and dynamically loading routines only when needed. Depending on the mode of operation, this can significantly improve performance as less Perl is interpreted for a given run, i.e. mostly only the routines and actually used. (I can provide the code I use for this if we elect that it is a good idea.)

The concept of "Plugin" will undoubtedly include some overhead to allow an arbitrary interface. For functions that are already part of the "core functionality", they should not be implemented as plugins, in my opinion, because of the fact that a hit in performance will exist. But, segregating the code to other modules is very important in terms of managing the project and allowing dynamic loading if desired. I don't agree that there should be much of any performance hit just because some features are enabled that are rarely used.

Your comment that we've survived without parameterised includes for some time now, well, people used assembly language for years as well and survived, as well as FORTRAN and COBOL. Sorry, I am not happy with status quo if I know it can be easily done and if I don't have it. At present, it means I have to replicate a ton of "directive" twiki-code with minor changes. Whenever that happens, I am inherently lazy and want to find a better way to do it. And I haven't been using TWiki for long. Even with the proposed INCLUDE enhancements, we are a long way from a flexible "macro" capability as the general variables questions still needs some work. But, the changes required to move forward are minimal so I am for making those changes within the existing infrastructure.

Regarding OO core, I don't really think it is too important to rewrite the code to comply with some other syntax that has been blessed to mean object oriented. I claim that the more important work is to work on objectifying the data object, therefore, TopicObjectModel.

-- RaymondLutz - 12 Dec 2003

My thinking is that we already have the plugins interface established, so moving functionality out beyond it should be easier and safer than inventing new interfaces (such as that to Include.pm). All your points about autoloading apply to plugins, and while I admit that the current plugins discovery code leaves something to be desired, it isn't all that inefficient (though I do have suspicions about plugins and mod_perl).

<rant>

Of course, if you propose to implement Include.pm so that it implements a small, tight interface, has the absolute minimum of hooks into the rest of the core, and is published so that plugin authors can use it, then I can't argue with that approach. After all, anyone wanting to experiment with replacement/enhancement of that module can simply subclass (or wholesale replace) it, and plugin authors are not treated as second-class citizens.

I'm not debating the usefulness of parameterized include; I for one would find it useful (I wouldn't have implemented it otherwise). However I am debating the methodology used to implement it. While Peter asserts, and I agree, that the "changes are not too complex", making large numbers of small changes without refactoring is exactly how spaghetti code comes about.

A final point about the plugins interface; it has suffered several revisions over time, and it still isn't right (every tried to modify metadata in a plugin?). One way of helping the interface to develop is to have the core team spend at least some of their time working outside it. I'm sure much of the code duplication that is forced on plugin authors today would disappear. Pure self interest on my part, I hasten to add.

</rant>

-- CrawfordCurrie - 12 Dec 2003

Quite a few Plugins do come from the CoreTeam. However, whilst I've done a lot to make sure the API available to Plugins in Functions, I have at times been lazy and not added to this API. Please feel free to point this out to me.

We have also done quite a bit of re-factoring in the core code, but I accept that more is required. Preferably backed by more tests.

-- JohnTalintyre - 12 Dec 2003

CrawfordCurrie, I agree generally with your points about improving the plugin interface, etc. but don't agree about a couple of things. (I still need to spend the time to perform a detailed code review, but it is something I am planning to do. This is based on my current understanding.)

  1. Core probably could be defined a bit more rigorously. I assume that the Core is anything that is not a plugin. There is another meaning of Core which perhaps another term is needed (Kernel?), and this is the module TWiki.pm, or the piece of the code that is always interpreted. Code that is dynamically loaded and interpreted is brought in only when required, i.e. only when the routines are requested. This is different from Plugins which may or may not be dynamically loaded.
  2. Dynamic loading is different from conditional loading. Plugins, from what I understand are conditionally loaded based on the configuration of the site. Whether they are dynamically interpreted only when actually used is a separate question.
  3. From what I have determined so far, the method of dynamic loading of Plugins and core does not dip to the level of granularity that can be used to really optimize loading and execution. Adding plugins can add quite a bit of overhead if they are continually polled to find out if they have any work to do, and especially if they have algorithms that are slow.
  4. Well partitioned interfaces are important for any and all parts of the code, even between modules in the Core.
  5. Adding and changing Core does not mean spaghetti code. In my mind these are completely different concepts. On the contrary, moving existing core functions to plug-ins will cause a performance hit of some kind, whether they are coded with spaghetti code or using the finest of structured programming and OO techniques.
  6. Moving the INCLUDE code from the "Kernel" to another module, Include.pm will allow dynamic loading if we want to do it, and as you mention, wholescale replacement by those (like me) who want to dramatically improve it and don't want to have to perform many patches to the "Kernel" to do so.

Plug-ins are a cool idea, but do have drawbacks and will not be able to handle all improvements. I am of the opinion that for functions that are part of the baseline definition of TWiki should NOT be part of plugins. As certain plugins become very standard, it is probably wise to integrate these into the core but not into the kernel.

-- RaymondLutz - 12 Dec 2003

(I've numbered instead of bulleting your points so I can refer to them more easily).

  1. Agreed. My approach to defining Core would be to incrementally move everything out of TWiki.pm that is not core. Whatever is left, is Core.
  2. Agreed. As I said above, I acknowledge the performance hit involved in conditional loading of a plugin module.
  3. I'm sure you know far more about dynamic loading than I do; I'll take your word for it.
  4. Of course.
  5. Adding and changing code without structural refactoring does indeed lead to spaghetti code. I once had the misfortune to debug a huge Fortran program that had been successively modified ("enhanced") by a series of graduate students. In each modification, the absolute minimum had been done to the code to add the necessary functionality. Each change on it's own was individually clean, reasonably well done, well documented, and defendable by the author; but the result was spaghetti. You said yourself a couple of times "I need to perform a detailed code review". Yup, that's the only way you can proceed from here, because you're trying to find a single strand of the spaghetti. And once you are finished, you will have added a few more strands to the plate. Please, I beg you, make it significantly easier for the next poor schmuck who comes along to improve on what you have done! Structure comes first. Performance can always follow later.
  6. As I said above, I'm not arguing with Include.pm if it addresses the first paragraph of my <rant> above

Raymond, I'm sorry, I feel as if I'm picking on you. But this same input could have been made to most of the proposed changes for the next release.

-- CrawfordCurrie - 13 Dec 2003

Crawford, we are in violent agreement, except for item 5 where we are in partial agreement.

Adding and changing code DOES NOT necessarily lead to spaghetti code. And, performing structural "refactoring" does not necessarily result in roast beef code (I guess that is the opposite of spaghetti). In fact, it may be very difficult to correctly refactor the code to a different structure, especially if you try to do it to a large system. You mention the Fortran program that was enhanced multiple times, and indeed, I have been around such "ugly" implementations. Yet, the question is, did you refactor it? I would be willing to guess that the answer is "No," simply because such refactoring is basically "very difficult", and very time consuming, especially if you are working with a large system, and many factors must be included in the refactoring process, far too many for a human mind to effectively take into account. Plus, if the system works correctly, it may be better to just put a "wrapper" around it and let it run. "If it ain't broke, don't fix it", or you are making a ton of work for no good reason.

On the other hand, is it possible to make some incremental changes that improve roast beef and reduce spaghetti? I assert, Yes, and that the Include.pm suggested does just that.

I hope you like roast beef.

-- RaymondLutz - 15 Dec 2003

I'm not all that keen on beef. And memories of BSE are still strong.

Yes, I did indeed refactor it. As I recall, the restructuring consisted of breaking it up into parameterised subroutines - this was Fortran, after all!

The "if it ain't broke" argument is an interesting one. It all depends on how you define "broke". There are a number of things that drive refactoring:

  1. to make the code faster
  2. to make the code more testable
  3. to make the code more comprehensible
  4. to make the code more functional
Failure to meet expectations in any of these areas can mean the code is "broke" and trigger refactoring.

Where this discussion started was in the area of "I thought there was an intent to refactor". This understanding comes about from multiple assertions that the core code is incomprehensible, and therefore "broke". If you make changes without acknowledging that, you are simply making it more "broke".

The addition of Include.pm is structural refactoring, and as long as it meets my requirements, viz: "... implement Include.pm so that it implements a small, tight interface, has the absolute minimum of hooks into the rest of the core, and is published so that plugin authors can use it ..." then I'm reasonably happy.

-- CrawfordCurrie - 16 Dec 2003

I'm sure we can go on and on about the merits of "refactoring" vs. incremental changes. The reasons you mention above are sometimes opposite in effect, such as faster vs. comprehensible. With a interpreted language like Perl, you may have a tendency to use implied variables ($_, @_) and horrible compound statements to gain speed, and this certainly does not improve comprehension. On the other hand, Perl CAN help make small, tight routines that are structured and easy to comprehend, unlike FORTRAN, which tends to encourage computed GOTOs and other sins. So in essence the point is that it is a creative balancing act with trade-offs in both directions. You can go overboard with too much comprehension, making the code understandable for beginners but sacrificing speed and functionality, as well as never refactoring and using poor design techniques and winding up with FORTRAN, or potentially worse yet, bad assembly code.

I tend to think that the routines are a bit too large in the current implementation, and there is a lot of repetitive calls (such as to extract parameters one at a time) and there is a bunch of parameter passing that does not need to be done. Moving the INCLUDE code to another module is an attempt to further modularize the "kernel". Since INCLUDE is a part of the standard TWiki Directive set, and yet is not always used, it is a "correct" step in my estimation.

However, I also see that TWiki has a ways to go before it is ready for the call to "freeze" the code. It seems to me that it is maybe about 50% done, with much more to do. Pushing for too much in the way of ivory-tower structured programming and object-oriented requirements can get in the way of "rapid-prototyping", a very powerful design technique. The problem is that if you perfectly refactor to a system that is expanding and growing, you may find that the refactoring assumed a certain structure to the system and that a new requirement transcends that structure. You were probably fortunate in the case of the FORTRAN code because the system was probably not as living and growing as TWiki is.

It is a fact that most programmers tend to want to rewrite a module that they become responsible for so that it complies with their concepts of comprehension and structure. This is true even if the module has just recently received such treatment. Be careful to allow other ways of coding or you can fall into this trap. Call for changes that are actually required, not just to "pretty up the code". Believe me, I am subject to this same tendency, and I have to fight it. I tend to want to go ahead and adopt the "correct" philosophy and sometimes wind up changing too much, and sometimes realizing that the code was a bit more complex than I envisioned. It is also true, that programming is very difficult to get correct, and using a "beautiful" structure is essential to maintaining sanity.

If PeterThoeny or whoever is making the changes to this decide that it is more expedient to implement by making minimal changes to the modules as they stand, that is fine, and does not change the call for eventual modularization of the INCLUDE stuff, which I will continue to suggest. If you are for this sort of refactoring, then we are in agreement. If you are calling for making the changes to INCLUDE as a plug-in, then we are in disagreement on that point. INCLUDE is a standard function and making it a plug-in does not serve to help anything, as it will always be plugged-in. You don't need to make plug-ins unless the stuff is truly optional.

Are we in agreement on this point?

-- RaymondLutz - 16 Dec 2003

I'd suggest that the discussion of core/module/plugin is spun off to a separate topic. (My personal feeling on the debate is implement it, refactor it out to a module then extract into a plugin - ie implement, keep it implemented but nicer, make it optional)

Some comments on the feature as discussed here:

In the spec above either:

  1. Any parameter not understood by INCLUDE gets passed over.
    • This has problems if you have a namespace clash, or if the INCLUDE options get increased. (poor modularisation)
    • This option makes any applications built using this spec fragile to further changes in the INCLUDE spec. (Much like end-user searches being fragile to meta-meta data)
  2. All parameters - including those understood by INCLUDE get passed over. (Problems arise if using a pattern for include and wanting to pass through a pattern, or including a section and wanting to pass through a parameter section.)
    • This makes an application fragile again in the case that it uses a parameter which the spec above enroaches into.
    • This also means that applications actually recieve more values than they might expect. Since neither this version nor the other version (1) are shown with any preference this is another cause for pause.

Having a slightly different spec of: %INCLUDE{ "OtherTopic" parameters="anyname=anyvalue&foo=bar"}% %PARAM{"param" default="" newline="bla"}$ * PARAM falls back to work like URLPARAM * %URLPARAM{"foo"}% & %PARAM{"foo"}% in the same page work independently.

Means that you don't have these issues. (There are likely to be others instead) Furthermore, it means that someone can test their page thus:

They can then be sure that the behaviour they're after works, and then create the appropriate include:

  • %INCLUDE{ "Main.SomePage" parameters="anyname=anyvalue&foo=bar"}%

(It also increases the likelyhood that someone can automate tests for their apps this way.)

Another problem I have with the spec above is this:

  • The INCLUDE parameter is used in case the included topic encounters a URL parameter and an INCLUDE parameter of the same name.

Originally I thought PARAM would replace URLPARAM in all (rather than most) situations - however this strikes me as a mistake in retrospect - and thankfully by not overengineering a spec we don't hit that mistake. In most TWiki applications you would want to replace URLPARAM with PARAM since that allows you to build apps via includes, but fail back for remote users, however in some cases being able to have both:

  • %PARAM{"someparam"}%
  • %URLPARAM{"someparam"}%
    • This might seem odd, but how would you do this with the spec above:

      %PARAM{"%URLPARAM{'someparam'}\%" default="%PARAM{'someparam' default='bar'}\%"}%

      ie allow users to override the specific parameters, whilst allowing application defaults to kick in?

This is analogous with other parts of INCLUDES you have available %TOPIC%, %INCLUDINGTOPIC, %BASETOPIC% - all of which default to %TOPIC% in a non-local including case.

If backslash quoting as in named include sections is in place then much of the $quot $bla duplication in the code is reduced, reducing the mindset the user needs to carry with them and the idea behind using standard URL encoding makes testing of applications significantly easier. (It's not perfect granted)

Opinions offered in the hope they're useful - far from implementing in haste I had been thinking about parameterised includes for a month or two before initially mentioning the idea to Raymond. These might sounds like small differences, but the implications are quite large. If they not considered useful, please ignore - everyone has different needs. If anyone's interested in the patch for an implementation that avoids these issues, I can post it here.

-- MS - 19 Dec 2003

I think you make some good points, Michael. However, I think the use of URL encoding is not that great of a way to handle the problems you mention. Have you ever had to do this in any programming language? No.. it is just too much trouble to force this within a single programming environment where you have the luxury of passing more than just a single string variable.

  • No, I haven't had to do this in a programming language. However most programming languages I use do not sit in a web page, and do not take parameters by URL or by text. TWiki is close in some respects to a declarative language, and one thing that is nice about most declarative languages is the lack of suprise you get.

    Personally I stand by the view that passing things as url encoded resolves enough problems for it to be useful - and makes like easier for the average user testing things out - since they can build a form front end, using a get method until they get something they want - which also simplifies generalised application testing..

    Should it exclusively replace other things? Probably not. However the namespace issues need thinking about and syntactic measures to help prevent namespace clobbering make sense. URL encoding is just one method. Conventions break, often obligatorily so. -- MS - 05 Jan 2004

Instead, I have added a note to the specification above that I hope you will review and see if it doesn't cover the cases you mention.

-- RaymondLutz - 01 Jan 2004

Michael, I'm wondering if we can't support both ways of doing it. Use the programmatically aligned method proposed (with simple argument names that must match the parameter name expansions in the file) OR use a single URL encoded operand, again with argument names matching the usage in the included topic. This SHOULD eliminate this point and allow us to finish this specification. Fair enough?

-- RaymondLutz - 09 Jan 2004

If it came across as an either this or that approach then I think something's been missed. You still hit the namespace issues however even with your spec - eg:

  • %INCLUDE{"SomeTopic" section="FooBar"}% - this would result in a current TWiki in FooBar being passed as a parameter, and if NamedIncludeSections was ever merged in a non-broken fashion, then suddenly this parameter would be captured by the TWiki rather than the application, since the semantics of TWiki & the application could well be very different.

Simpler: If you really want %INCLUDE{"SomeTopic" thing="FooBar" thing2="FooBar"}% do it as %INCLUDE{"SomeTopic" _thing="FooBar" _thing2="FooBar"}% and only pass through _thing, _thing2 as thing and thing2 - the leading underscore creates you an implicit namespace.

-- MS - 12 Jan 2004

Raymond,

Whilst the params method I suggested is useful, yours definitely is as well. Mine might be easier for user testing, however in certain programmer friendly scenarios your approach is definitely easier. I stand by the namespace issues detailed above, and suggest that the syntax for your parameters to be passed through be the leading underscore approach. This could be suggested to indicate that the namespace for those parameters is private to the application.

Specific use for this:

  • %INCLUDE{"%\FORMFIELD{'SomeField'}\%" section="%\FORMFIELD{'SomeOtherField'}\%" _user="%\FORMFIELD{'FirstName'}\%" _email="%\FORMFIELD{'EmailAddress'}\%"}%

In the page specified in the field SomeField in the section specified in SomeOtherField , the values of %PARAM{"user"}%, %PARAM{"email"}% would take the values specified in the form fields on the source topic.

Example relies upon NamedIncludeSections and FormattedTWikiFormDataInTopicText . (The latter needs to be modified to remove the rendering step) Clearly neither feature is in TWiki, but the examples hold - since there's other ways of achieving similar goals.

-- MS - 19 Jan 2004

I need this for work - So i'll probaly integrate it when it works for me

-- SvenDowideit - 12 May 2004

See MacrosPlugin for an implementation of parameterized includes.

-- CrawfordCurrie - 08 Jul 2004

I guess if I implement something I can dictate the syntax. And since I wrote MacrosPlugin I guess I have more experience with this sort of thing. So I'm going to implement this, and see what reaction we get. It's been sitting in the queue for far too long.

My preferred approach is to treat param values (both URLPARAMs and include parameters) equally, and treat them as implicit * Set operations. Of course, a mechanism is required to provide a default, but because default values are the exception rather than the rule, here's what I'm going to do:

In IncludedTopic

:
%UNLESS{"param" default="the default value"}%%param%
In IncludingTopic
%INCLUDE{"topic" param="Sausages"}%
%INCLUDE{"topic"}% -- in this case param will default to "the default value"
Big note %UNLESS does not mean the same as unless in perl, it means the same as #IFNDEF in cpp. Setting a null (or zero) value is not the same as not setting a value. The empty string is a valid value, and will not trigger UNLESS.

To rationalise the URLPARAM syntax,

  • %urlparam% is synonymous with %URLPARAM{"urlparam"}%
  • %UNLESS{"urlparam" default="Chips"}%%urlparam% is synonymous with %URLPARAM{"urlparam" default="Chips"}%
The %param% syntax is already supported by the CommentPlugin and the MacrosPlugin. The concept of using the parameters to the %INCLUDE tag as values in the included topic is already supported by the MacrosPlugin.

Further,

   %UNLESS{"EDITBOXWIDTH" default="125"}%
can be used to provide a default value for a variable that would otherwise be * Set.

Obviously existing parameters to INCLUDE cannot be used as parameter names: pattern, rev and warn are therefore reserved names.

The CommentPlugin already supports a shorter syntax for parameter default values:

   cols="%cols|3%"
which specifies the default value "3" for the cols parameters. However I don't like this, so I'm not going to implement it.

Support for this syntax would permit the retirement of the MacrosPlugin.

It may be possible to easily support this same syntax in the context of TWiki Templates:

%TMPL:DEF{"sausage"}%
%UNLESS{"message" default="mistake"}%Oops, you made a %message%
%TMPL:END%

%TMPL:P("sausage" message="mistake"}%
%TMPL:P{"sausage" message="bit of a mess"}%

The scoping rules are very simple: the closest enclosing definition is the only definition visible, and parameters always override automatic variables. So if you were to say:

%INCLUDE{"OtherTopic" INCLUDINGTOPIC="Battenburg" DATE="Fruitcake"}%
then INCLUDINGTOPIC would be Battenburg (parameter overrides automatic variable INCLUDINGTOPIC) and DATE would be Fruitcake (parameter overrides static definition).

Of course you'd be rather silly to do this, but it's better to have rules.

Note that

%UNLESS{"MAINWEB" default="Main"}%
will never fire, because %MAINWEB% always has an value, provided by the system

Note also that parameter seetings will be appended to included URLs, so

%INCLUDE{"http://a.url.com//fleegle?param=floon" param="snot"}%
will expand to the url: http://a.url.com//fleegle?param=floon&param=snot. The interpretation of this URL is up to HTTP.

If you really object to this spec, shout and we can talk about it.

-- CrawfordCurrie - 26 Oct 2004

i like smile

-- SvenDowideit - 26 Oct 2004

I like. In fact, I coded a very similiar thing in the TWikiReleaseTrackerPlugin. This allows overriding by a cgi parameter, then a parameter passed to a plugin, then a preference.

sub getParam {
 my ( $inlineParamString, $paramName ) = @_;

 my $ans = untaint( $cgiQuery->param($paramName) );

 if ( $ans eq "" ) {
  $ans = TWiki::Func::extractNameValuePair( $inlineParamString, $paramName );

 }

 if ( $ans eq "" ) {
  $ans = TWiki::Prefs::getPreferencesValue("\U$pluginName\E_\U$paramName\E");
 }

 return $ans;
}
-- MartinCleaver - 26 Oct 2004

I like the Idea of parametrized includes. There is another feature to consider: ParameterizedVariables to include text of a (user defined) TWikiVariable with parameters.

-- StefanSteinegger - 04 Nov 2004

BTW: What about ParameterizedLinks? (This would all result in a complete TWiki parameterization :-).

-- StefanSteinegger - 09 Nov 2004

In the interests of consistency with ParameterizedVariables, here's a revised spec suitable for inclusion in documentation. The revision supports the idea of formal declaration of parameters, which I think is a good idea (thanks StefanSteinegger!). Note that the use of STARTINCLUDE is quite deliberate; I am anticipated NamedIncludeSections using the _DEFAULT parameter to %STARTINCLUDE to name the section at some point in the future.

Note also that this spec, when combined with ParameterizedVariables, is much cleaner than the current %TMPL mechanism and could be a drop-in replacement for that syntax as well.

Using %INCLUDEd topics as macros

An %INCLUDEd topic can also be used to define a macro. A macro is a piece of text with placeholders. These placeholders are filled in with text you supply when the topic is included.

For example, you might write in the included topic:

My uncle's name is %name%, his age is %age%, and he's usually %mood%
and then in the including topic:
%INCLUDE{"MyUncle" name="Fred" age="75" mood="introspective"}%
The named placeholders will be substituted when the including topic is viewed, so the %INCLUDE will expand to
My uncle's name is Fred, his age is 75, and he's usually introspective
In order to use named placeholders you have to declare them in the included topic. You do this using the %STARTINCLUDE% TWiki tag in the included topic.
%STARTINCLUDE{name="Aloysius" age="19" mood="bouyant"}%
My uncle's name is %name%, his age is %age%, and he's usually %mood%
%ENDINCLUDE%
The %STARTINCLUDE statement declares the names of the placeholders name, age and mood that can be set from the including topic, and their default values. If values for these placeholders are not given in the %INCLUDE statement, then the default values will be used i.e. =Aloysius for name, 19 for age, and buoyant for mood. For example:
%INCLUDE{"MyUncle" name="Solomon"}%
will expand to
<My uncle's name is Solomon, his age is 19, and he's usually buoyant.
Note the use of lower case names for parameters to the include. This isn't compulsory, but it's a good idea to avoid conflicts with TWikiVariables.

See also: Using variables as macros for another way to define macros, more suitable for smaller amounts of text.

-- CrawfordCurrie - 09 Nov 2004

I need this sometime soon, so I'm proposing the above spec for Dakar.

-- CrawfordCurrie - 15 Feb 2005

OK, the most basic implementation is in (i.e. PARAM="xxx" results in %PARAM% being defined in the inncluded topic) - Developbranch, r3661

-- CrawfordCurrie - 19 Feb 2005

Crawford, I think you should at least expand four parameters as this is what TWiki allows in other places (parameters passed through URL). I don't know what is special about four, but let's be consistent at least....

By the way, in my own installation I have patched lib/TWiki/UI/View.pm as follows to take in parameters also, as I often want to call pages with some parameters substituted...

Index: lib/TWiki/UI/View.pm
===================================================================
RCS file: /e/www/CVS/twiki-cairo/lib/TWiki/UI/View.pm,v
retrieving revision 1.1
diff -c -r1.1 View.pm
*** lib/TWiki/UI/View.pm   7 Sep 2004 17:16:58 -0000   1.1
--- lib/TWiki/UI/View.pm   19 Feb 2005 22:38:45 -0000
***************
*** 153,158 ****
--- 153,179 ----
    TWiki::UI::writeDebugTimes( "view - get rev info" );
  
    if( ! $viewRaw ) {
+     # Substitute for parameters that have been passed in.
+     # For performance reasons, do not remove parameter references 
+     # when no parameter was passed, as with
+     #    $param = $query->param( 'param1' ) || "";
+     #    $text =~ s/%PARAM1%/$param/go;
+     # etc.
+ 
+     my $param;
+     if ( defined ($param = $query->param( 'param1' )) ) {
+       $text =~ s/%PARAM1%/$param/go;
+     }
+     if ( defined ($param = $query->param( 'param2' )) ) {
+       $text =~ s/%PARAM2%/$param/go;
+     }
+     if ( defined ($param = $query->param( 'param3' )) ) {
+       $text =~ s/%PARAM3%/$param/go;
+     }
+     if ( defined ($param = $query->param( 'param4' )) ) {
+       $text =~ s/%PARAM4%/$param/go;
+     }
+ 
      $text = &TWiki::handleCommonTags( $text, $topic );
      TWiki::UI::writeDebugTimes( "view - handleCommonTags done" );
      $text = &TWiki::Render::getRenderedVersion( $text );

Note that this text would leave the %PARAMx% string in the topic if no parameter was passed, i.e., the assumption is that the user passes all arguments (I need to test performance to see whether this really matters).

-- ThomasWeigert - 19 Feb 2005

Sorry, I was clearer in the documentation:

INCLUDE{"page"} -- include other topics or web pages

  • Syntax: %INCLUDE{"page" ...}%
  • Supported parameters:
    Parameter: Description: Default:
    "SomeTopic" The name of a topic located in the current web, i.e. %INCLUDE{"WebNotify"}%  
    "Web.Topic" A topic in another web, i.e. %INCLUDE{"TWiki06x01.SiteMap"}%  
    "http://..." A full qualified URL, i.e. %INCLUDE{"http://twiki.org/"}%
    Note if the URL resolves to an attachment file on the server this will automatically translate to a server-side include.
     
    pattern="..." A RegularExpression pattern to include a subset of a topic or page none
    rev="1.2" Include a previous topic revision; N/A for URLs top revision
    warn="off" Warn if topic include fails: Fail silently (if off); output default warning (if set to on); else, output specific text (use $topic for topic name) %INCLUDE- WARNING% preferences setting
Any other parameters will be defined as variables within the scope of the included topic. For example,
%INCLUDE{"AnotherTopic" PONE="val 1" PTWO="val 2"}%
will result in %PONE% and %PTWO% being defined within the included topic.
Thus you can have any number of parameters.

Note also that Dakar supports as many parameters to oops scripts as you want; it is not restricted to %PARAM1%..%PARAM4%. It implements %PARAM1%..%PARAMn%. AFAIK that was the only place a 4 param restriction applied.

The spec discussed above (but not yet implemeneted) would further allow the declaration of default values using the STARTINCLUDE tag:

-- CrawfordCurrie - 20 Feb 2005

Just as a footnote. This became spec in Dakar. See VarINCLUDE

-- MartinCleaver - 04 Sep 2008

Edit | Attach | Watch | Print version | History: r47 < r46 < r45 < r44 < r43 | Backlinks | Raw View | Raw edit | More topic actions
Topic revision: r47 - 2008-09-04 - MartinCleaver
 
  • 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-2024 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.