Tags:
create new tag
, view all tags

ForEachPluginDev Discussion: Page for developer collaboration, enhancement requests, patches and improved versions on ForEachPlugin contributed by the TWikiCommunity.
• Please let us know what you think of this extension.
• For support, check the existing questions, or ask a new support question in the Support web!
• Please report bugs below

Feedback on ForEachPlugin

Submitted ForEachPlugin. It provides much the same functionality as the $LISTMAP() function in SpreadSheetPlugin, but for some purposes it might be clearer... Hope it's of some use to someone.

I don't intend to extend it to include a WHILE loop since I don't want to implement any conditional testing stuff.

-- MagnusLewisSmith - 29 Sep 2005

Thank you very much Magnus for sharing this Plugin with the TWikiCommunity smile

I made some small changes to the Plugin topic. Please feel free to take that into the next release.

Regarding "All parameters are required, and must appear in the specified order", you can make the code more robust and forgiving by feeding everything within the curly braces into the handler function and by using TWiki::Func::extractNameValuePair to extract the parameters. You can look at the code of the HeadlinesPlugin, which is a good and short example.

Also, how about measuring and documenting the PluginBenchmarks?

-- PeterThoeny - 29 Sep 2005

Wouldn't it be better to integrate the functionality of this plugin within SSP?

-- FranzJosefSilli - 29 Sep 2005

I would like it to remain separate. SpreadSheetPlugin has become a huge "good for anything" blob, and needing to use the %CALC% tag to perform non-table related operations is quite distracting (confusing?)

-- RafaelAlvarez - 29 Sep 2005

I disagree. It is much more confusing to have a slew of different plugins with overlapping functionality and different syntax. The SpreadSheetPlugin is a wonderful collection of algorithmic operations on parts of the topic.

-- ThomasWeigert - 29 Sep 2005

The SpreadSheetPlugin is a Swiss Army knife. It has blades for everything. However if you look at professional craftsmens' tools they are all specialized. The follow the same principle that Rob Pike espouses for software tools: Each does one thing, only one thing and does it well.

I don't imagine for a moment that this means craftsmen of all stripes (even auditors such as myself and airline pilots that I know of) shuldn't and don't carry Swiss Amy knives and Gerber tools and Leathermen. But for a professional job rather than a qucik fix, professionals use specific tools.

That the tools have overlapping functionality is completely beside the point.

  • I can put a screw in with any one of a number of fixed blade screw-drives, changeable blade screwdrivers, my B&D power driver or the screw drver attachment on my drill. It depends on the screw, situation and what tools are to hand.

Sometimes the setup and understanding and situation are better suited to a specific, focused tool than a general purpose one.

I like the idea of this plugin. The important thing is that it, and tools like it, be they ActionTrackerPlugin, HeadlinesPlugin or whatever, should present no load (not even javascript download and start up) in topics where they are not being used.

-- AntonAylward - 04 Dec 2005

Anybody know if this plugin works okay with TWiki v4.0 (Dakar Release)?

-- BehrouzBayat - 27 Jul 2006

The TestedOnTWiki states 01 Sep 2004. It might or might not work on TWiki 4.0. If you get a chance please try and let us know.

-- PeterThoeny - 27 Jul 2006

Will do. I'm not sure how soon I can get twiki 4.0 up and running, but i'll post my results once I know.

-- BehrouzBayat - 28 Jul 2006

Yes it works, I have it already running.

-- ThomasFreudenberg - 03 Aug 2006

Thought I'd weight in on the discussion about using this plugin versus SpreadSheetPlugin. I first tried to implement the capability of this plugin using SSP and spent an hour of so struggling with it before giving up and trying out ForEachPlugin. I got the results I was after using this plugin in about 15 minutes, including installing it. That says something. It's of little help for SSP to be able to do almost anything if it is so very difficult to work with. Here's one thing that I needed which I think SSP can not do but which this plugin can: present output from the loop that covers several lines . I believe any new lines in the formula section of the $LISTMAP expression will breaks it. Can anyone confirm or deny this?

One enhancement I would like for this plugins is that if the in="_list_" statement is empty, then the plugin should return nothing. As it is, it returns the whole tag, unresolved - e.g. %FOREACH{"$var" in ""}% . This breaks any variables this plugin might be embedded in.

-- LynnwoodBrown - 04 Oct 2006

There seems to be some funny order-of-operations interaction between this plugin and SpreadSheetPlugin. I've got code like this:

%FOR{"x" start="1" stop="3" step="1"}% 
$percntCALC{"$SET(total, $GET(total), $x)"}$percnt
Totals: $percntCALC{"$GET(total)"}$percnt<br>
%NEXT{"x"}%
Totals: %CALC{"$GET(total)"}%

The output of this is:

Totals: , 1
Totals: , 1, 2
Totals: , 1, 2, 3
Totals: 

The value of the variable “total” seems to get lost when the loop exits. I presume that this is because the outer CALC is evaluated before the inner ones are? Is there any way to prevent this from happening?

-- AaronSher - 03 Nov 2006

Simpler yet - something like

%FOR{"include_count" start="23" stop="25" step="1"}% | $include_count %NEXT{"include_count"}% |
%CALC{"$SET(include_revs, $LIST(R1:C1..R1:C999))"}%
%CALC{"$GET(include_revs)"}%

generates no output; apparently, the table generated by the FOR doesn't exist at the time that the CALC is evaluated. This makes FOR not very useful for calculations, since the primary use that I can see for it is to generate lists. LISTMAP is good, but it has two major limitations: it can't generate a list from scratch, and it can't create output that doesn't have commas!

-- AaronSher - 03 Nov 2006

Nobody has any input? This seems like a fairly major limitation in the plugin - without this being at least described, the plugin is pretty much useful only for generating lists to be displayed.

-- AaronSher - 20 Nov 2006

It looks like this plugin is not being maintained here. Have you tried to contact the author?

-- ArthurClemens - 20 Nov 2006

Yes, I tried that. I also tried placing an issue in the support web (HowToCombineCalcAndFor). Dead silence on all fronts. I've pretty much given up on this plugin - it doesn't seem to be useful in its current form.

-- AaronSher - 27 Nov 2006

The trouble with the SpreadSheetPlugin is that it has a very difficult syntax, and requires an excessive amount of escaping of quotes, etc. The ForEachPlugin is simpler in concept, and allows the expression to be broken into smaller parts, making it much more convenient to use.

However, there is a defect in the ForEachPlugin because it adds too many newlines between each expression.

The case I am using it for is to lookup records in a Form-based database based on a list which is extracted from another topic.

In the FOREACH clause, it can handle the extraction of the list from the other topic and create a comma-separated list of values suitable for this purpose. In my case, it is a comma-separated list of email addresses extracted using the FORMATLIST expression.

Then in the body of the loop, I have a SEARCH expression to extract the appropriate record(s) that relate to that email address.

Trying to put all this into a single SEARCH with or-ed values never would work, and I'm still not sure why, but it seems to have to do with order of execution. It would be the best solution as it would require a single pass through the data. Using SpreadSheetPlugin was even worse, with a ridiculous amount of escaping of quotes required. Putting the SEARCH into the LISTMAP expression as a quoted string means every other quote must be escaped. What a mess!

Indeed, TWiki functions are very tricky because they require a knowledge of "hidden" order of execution instead of using the more traditional programming style which includes a concept of order based on the order of elements on the page. In TWiki, the apparent order is all at once, with tricks like $percnt and $dollar to get things to wait before being executed.

SpreadSheetPlugin is nearly impossible to use as it has such a horrible syntax, with the notion that everything must be enclosed in quotes -- why? It only serves to make it nearly impossible to use.

-- RaymondLutz - 04 Sep 2007

Doesn't seem to work on TWiki 4.2. Is there any effort on upgrading? I'm not so good with perl but I see that it doesn't seem to be packaged with BuildContrib. No installer script and the subs in the .pm uses commontagshandler. Update: it works now on 4.2 for some reason I dont know. I wonder how a plugin like this could be rewritten without using commonTagsHandler, only standard registerTagHandler....

-- LarsEik - 19 Sep 2008

Yes, I can see these comments are old. Anyway...

I was trying to get this thing working with a with a SEARCH (works well) with a CALC nested in the search (nope). After 2 solid days of trying every combination of escape words, I finally got it to work. I added a handler for dollar signs in the handleForEach subroutine, and I put it first on the plugin list (before SSP). I'm just wondering if this will break anything else. I don't have extensive use of this yet, so I think I am safe. I'll post what I changed shortly.

sub handleForEach
{
    my ( $var, $list, $body ) = @_;
    my $ldebug = $debug;
    &TWiki::Func::writeDebug( "- ${pluginName}::handleForEach(\n var: $var\n list: $list\n body: $body\n )" ) if $ldebug;
    my $ret = "";

    foreach my $item (split /\s*,\s*/, $list) {
        ($ret .= $body) =~ s/\$$var/$item/gs;
        $ret =~ s/^\n//m;
        $ret =~ s/\n$//m;
    }
    &TWiki::Func::writeDebug( "- ${pluginName}::handleForEach() intermediate:\n$ret" ) if $ldebug;
    $ret =~ s/\$percnt/%/g;
    # ADDED THE FOLLOWING LINE SO IT WOULD BEHAVE BETTER WITH SEARCH AND CALC
    $ret =~ s/\$dollar/\$/g;
    &TWiki::Func::writeDebug( "- ${pluginName}::handleForEach() intermediate2:\n$ret" ) if $ldebug;
    $ret = &TWiki::Func::expandCommonVariables($ret);
    &TWiki::Func::writeDebug( "- ${pluginName}::handleForEach() returns:\n$ret" ) if $ldebug;
    return $ret;
}

And my TML is something like below - you have to escape the SEARCH, which worked fine, but the required extra escape of the CALC was not supported. Now it works smile

   * Set SEARCHSTRNG = [C]lass.*value\=.*%URLPARAM{"alClass" default="XYZ"}%;[L]ocation.*value\=.*$triploc

%FOREACH{"triploc" in="%LOCS%"}%

%TABLE{ sort="on" headerrows="1"  tablerules="all" }% 
$percntSEARCH{ "%SEARCHSTRNG%" topic="NewEmpID*"  type="regex" nosearch="on" nototal="on" header="| *PIN* | *Last* | *First* | *Class* | *Location* | *Total* |" format="| [[$topic][$formfield(PIN)]] | $formfield(LastName) | $formfield(FirstName) | $formfield(Class)  | $formfield(Location) | $dollarpercntCALC{%$formfield(Location)TOTAL%}$dollarpercnt |" }$percnt

%NEXT{"triploc"}%

-- AaronLWalker - 2010-05-05

See related Support.SID-00824 and TWikibug:Item6449: IMHO the spec of expanding $percnt is unfortunate because it has unintended side effects. Therefore I think it is better to use a different syntax to escape variable expansion. Same for $dollar, I do not recommend to use it.

To fix this issue we could do one of these two options:

1. Option A: Add new delay="on" parameter to FOREACH

Enhance the plugin to handle delay="on" parameter. Example:

%FOREACH{ "release" in="8, 19" delay="on" }%
%SEARCH{
 "META:FIELD.*?ReleaseNo.*?value=\"$release\""
 topic="Projects20.*"  type="regex" nonoise="on"
 format="[$formfield(ProjectName) $percntCALC{ $IF($EXACT($formfield(DevStartDateDone), Yes), - DONE,) }$percnt $n "
}%
%NEXT{"release"}%

Implementation hint: The beforeCommonTagsHandler() is called before TWiki does any expansion of it's own internal variables. It can be used to escape variables between FORACH and NEXT. The variables can be restored in the commonTagsHandler(). Example:

  • In beforeCommonTagsHandler() replace %SOMETHING with %-ForEachPlugin-delay-SOMETHING.
  • In commonTagsHandler() replace %-ForEachPlugin-delay-SOMETHING with %SOMETHING.

Not sure if the escape interferes with nested FOREACH. If it does we need to make an exception for %FOREACH.

2. Option B: Change escape character to $foreachdelay:

Possibly replace $pernct expansion with $foreachdelay, which is unique to the ForEachPlugin. The plugin would remove $foreachdelay, e.g. not be replaced with another character. Example:

%FOREACH{"release" in="8, 19"}%
%$foreachdelaySEARCH{
 "META:FIELD.*?ReleaseNo.*?value=\"$release\""
 topic="Projects20.*"  type="regex" nonoise="on"
 format="[$formfield(ProjectName) $percntCALC{ $IF($EXACT($formfield(DevStartDateDone), Yes), - DONE,) }$percnt $n "
}$foreachdelay%
%NEXT{"release"}%

The $foreachdelay can also be used to escape any other character such as a dollar sign. Example: $foreachdelaypercnt would resolve to $percnt.

Note: Out of these two options I'd prefer option two, it is much more clean and intuitive! In any case I recommend to retire the expansion of $percnt, and add a {ForEachPlugin}{LegacyExpandPercnt} configure flag for older installations that want to use the old spec.

-- PeterThoeny - 2010-05-08

To handle empty expressions the line in commonTagsHandler should be modified:

#handle empty expressions
#  $_[0] =~ s/&#37;FOREACH{\s*&#34;(.+?)&#34;\s+in=&#34;(.+?)&#34;\s*}&#37;(.*?)&#37;NEXT{\s*&#34;\1&#34;\s*}&#37;/&handleForEach($1, $2, $3)/ges;
   $_[0] =~ s/&#37;FOREACH{\s*&#34;(.*?)&#34;\s+in=&#34;(.*?)&#34;\s*}&#37;(.*?)&#37;NEXT{\s*&#34;\1&#34;\s*}&#37;/&handleForEach($1, $2, $3)/ges;

-- Manfred Meiser - 2014-09-17

Edit | Attach | Watch | Print version | History: r24 < r23 < r22 < r21 < r20 | Backlinks | Raw View | Raw edit | More topic actions
Topic revision: r24 - 2014-09-17 - ManfredMeiser
 
  • 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.