Extension:LoopFunctions

From MediaWiki.org

Jump to: navigation, search
Manual on MediaWiki Extensions
List of MediaWiki Extensions
LoopFunctions

Release status: beta

Implementation Parser functions
Description provides limited looping functionality in wikitext
Author(s) Carl Fürstenberg
Version 1.0.3 (Dec 17, 2006)
MediaWiki 1.7+
Download see below

This extension will enable limited looping functionality in the wikitext, where a variable ($n$ by default) is replaced by the current iteration number of the loop. The variable can be used in a plain text or link. Also the result of the whole loop can be put in an expression, e.g. to compute a factorial. However, the loop body is evaluated before replacing the variable, so e.g. a computation inside the loop body, depending on the value of the variable, is not possible.

Per standard the number of iterations is limited to 100 iterations per session.

Contents

[edit] Functions

[edit] #for

{{ #for: n | text  }}
{{ #for: n | text | replacement parameter }}

where n is the count of iteration and the text is the text to be repeated. If, after expansion of templates, parser functions, and variables, the text contains the text $n$ or what is defined by the third parameter, that will be replaced by the current iteration, starting with 1.

[edit] Examples

calling the template {{ foo: |n=4 | list1=a | list2=b | list3=c | list4=d }} using the template foo, containing: {{ #for: {{{n}}} | {{{list$n$}}}<br/> }} will result in the text

a<br/>b<br/>c<br/>d<br/>
  • Sum of squares 1^2 through 5^2: {{#expr:{{#for:5|+$n$*$n$}}}} gives 55.
  • Factorial 6 (6!): {{#expr:1{{#for:6|*$n$}}}} gives 720.

Compare, using m:Template:for (talk, backlinks, edit) and m:Template:plus square (talk, backlinks, edit): {{#expr:{{for|call=plus square|pv=1|1|2|3|4|5}}}} gives 55.

For a list of squares it seems that we can only use "for", not "#for".

[edit] Limitation

In the loop body, templates, parser functions, and variables are expanded before replacing the index variable by its values.

Examples:

Parameter of a parser function depending on the index variable:

  • {{#for:3|{{lc:Ab$n$}} }} gives ab1ab2ab3; the result is in this case the same as when the repetition was done first, and then the evaluation of each item.
  • {{#for:3|{{uc:Ab$n$}} }} gives AB$N$AB$N$AB$N$; the result is in this case not the same, because $n$ is changed to $N$, and therefore not treated as index variable.
  • Applying #expr to an expression containing the index variable does not work: expansion of #expr in e.g. {{#expr:2*$n$}} gives the text "Expression error: Unrecognised punctuation character "$"", so this text will be repeated.

Template name depending on the index variable:

  • {{#for:3|{{a$n$}} }} gives:
    • if the template with the literal name Template:a$n$ does not exist: Template:a1 Template:a2 Template:a3 (the loop body is evaluated as Template:a$n$, after which the loop function repeats that, substituting $n$).
    • if the template with the literal name Template:a$n$ does exist: the result of {{a$n$}}{{a$n$}}{{a$n$}}, i.e., the content is repeated unchanged.

[edit] Limitation in combination with m:VariablesExtension

Within the loop a variable can be assigned a value depending on the loop variable, and the value of this variable can be retrieved.

However, it seems that within the loop the variable cannot be assigned a new value depending on its own current value. Instead the value on entering the loop is taken.

[edit] #foreach

{{ #foreach: mask | text  }}
{{ #foreach: mask | text | replacement parameter }}

The mask is a string in the format prefix$n$suffix where $n$ can be changed via the replacement parameter. The function #foreach, called inside a template, will produce the text for $n$ = 1, 2, 3,... as long as prefix$n$suffix is a template parameter defined in the template call. If the text contains the text $n$ or what is defined by the third parameter, that will be replaced by the current value of $n$.

It seems that the whole call of #foreach is ignored if the loop body contains a template call or a parser function call, or if the loop body does not contain {{{$n$}}}.

[edit] Examples

Calling the template {{ foo | foo2_bar=a | foo1_bar=b | a=12 | 6 |foo4_bar=c }} using the template foo, containing: {{ #foreach: foo$n$_bar | foo$n$_bar = {{{foo$n$_bar}}}<br/> }} will result in the expanded wikitext

foo1_bar = b<br/>foo2_bar = a<br/>

and hence the output

foo1_bar = b
foo2_bar = a

Since foo3_bar is not defined, foo4_bar is not listed either; neither are a and 1, the parameter names which exist but do not match the pattern.

Example without prefix or suffix:

The call {{showpars | abc | de | w=fgh | ijk }} of Template:Showpars containing {{ #foreach: $n$ | $n$ = {{{$n$}}}<br/> }} gives:

1 = abc
2 = de
3 = ijk

Content of a template that links to the pages given by the values of the unnamed parameters:

{{#foreach:$n$|[[{{{$n$}}}]]<nowiki> </nowiki>}}

[edit] Installation

Copy the following text to extensions/LoopFunctions/LoopFunctions.php and extensions/LoopFunctions/LoopFunctions.i18n.php. Then, include it from LocalSettings.php:

require_once ( 'extensions/LoopFunctions/LoopFunctions.php' );
<?php
/**
 * Some functions to enable limited looping functionallity, 
 * will also replace the text '$n$' or given parameter in the given text to the current loop count plus one.
 * 
 * @package MediaWiki
 * @subpackage Extensions
 *
 * @link http://www.mediawiki.org/wiki/Extension:LoopFunctions Documentation
 *
 * @author Carl Fürstenberg (AzaToth) <azatoth@gmail.com>
 * @copyright Copyright © 2006 Carl Fürstenberg
 * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
 */
 
if ( !defined( 'MEDIAWIKI' ) ) {
        die( 'This file is a MediaWiki extension, it is not a valid entry point' );
}
 
require_once('LoopFunctions.i18n.php');
 
$wgExtensionFunctions[] = 'wfSetupLoopFunctions';
$wgExtensionCredits['parserhook'][] = array( 
        'version' => '1.0.3',
        'description' => 'Provides limited looping functionallity in the wikitext',
        'name' => 'LoopFunctions', 
        'url' => 'http://www.mediawiki.org/wiki/Extension:LoopFunctions',
        'author' => 'Carl Fürstenberg (AzaToth)' 
);
 
$wgHooks['LanguageGetMagic'][]       = 'wfLoopFunctionsLanguageGetMagic';
 
class ExtLoopFunctions {
        public static $mMaxLoopCount = 100; // Maximum number of loops allowed per session
        private static $mCurrentLoopCount = 0; // number of executed loops this session
 
        public function forHook(&$parser, $nbr_of_loops = 1 , $text = '' , $param = '$n$' ) {
                $return = '';
                $text = trim($text);
                $param = trim($param);
 
                for($i = 0 ; $i < abs ( intval( $nbr_of_loops ) ) ; ++$i ) {
 
                        if( ++self :: $mCurrentLoopCount > self :: $mMaxLoopCount ) {
                                return wfMsg( 'loopfunc_max_loops' );
                        }
 
                        $return .= strtr( $text , array( $param => $i + 1 ) );
 
                }
 
                return $parser->replaceVariables( $return , current($parser->mArgStack) , true);
        }       
 
        public function foreachHook(&$parser, $mask = '' , $text = '' , $param = '$n$' ) {
                $variables = current( $parser->mArgStack );
                $param = trim( $param );
                $text= trim( $text );
                list ( $prefix , $suffix ) = $param == '' ? array( $mask , '' ) : explode ( $param , $mask , 2 );
 
                for($i = 0; array_key_exists( $prefix . ( $i + 1 ) . $suffix , $variables ) ; ++$i ) {
 
                        if( ++self :: $mCurrentLoopCount > self :: $mMaxLoopCount ) {
                                return wfMsg( 'loopfunc_max_loops' );
                        }
 
                        $return .= strtr( $text , array( $param => $i + 1 ) );
 
                }
 
                return $parser->replaceVariables( $return , $variables , true);
        }       
 
}
 
function wfSetupLoopFunctions() {
        global $wgParser, $wgExtLoopFunctions, $wgLoopFunctionsMessages, $wgMessageCache;
 
        $wgExtLoopFunctions = new ExtLoopFunctions();
        $wgParser->setFunctionHook( 'for', array( &$wgExtLoopFunctions, 'forHook' ) );    
        $wgParser->setFunctionHook( 'foreach', array( &$wgExtLoopFunctions, 'foreachHook' ) );    
 
 
        foreach( $wgLoopFunctionsMessages as $key => $value ) {
                $wgMessageCache->addMessages( $value, $key );
        }
}
 
function wfLoopFunctionsLanguageGetMagic( &$magicWords, $langCode ) {
        global $wgLoopFunctionsMagic;
        if(!in_array($langCode,$wgLoopFunctionsMagic)) $langCode = 'en';
        $magicWords = array_merge($magicWords, $wgLoopFunctionsMagic[$langCode]);
        return true;
}
<?php
 
if ( !defined( 'MEDIAWIKI' ) ) {
        die( 'This file is a MediaWiki extension, it is not a valid entry point' );
}
 
$wgLoopFunctionsMessages = array();
$wgLoopFunctionsMagic = array();
 
$wgLoopFunctionsMessages['cs'] = array(
        'loopfunc_max_loops' => "Byl přesažen maximální povolený počet smyček",
);
 
$wgLoopFunctionsMessages['en'] = array(
        'loopfunc_max_loops' => "Maximum number of allowed loops reached",
);
 
$wgLoopFunctionsMagic['en'] = array(
        'for' => array( 0, 'for' ),
        'foreach' => array( 0, 'foreach' ),
);

[edit] See also

Personal tools