Module:Sequence

From Wikisource
Jump to navigation Jump to search

--[[  

This module is intended to provide access to basic sequence functions.

Most of the functions provided here can be invoked with named parameters, 
unnamed parameters, or a mixture.  If named parameters are used, Mediawiki will 
automatically remove any leading or trailing whitespace from the parameter.  
Depending on the intended use, it may be advantageous to either preserve or
remove such whitespace.

Global options
    ignore_errors: If set to 'true' or 1, any error condition will result in 
        an empty string being returned rather than an error message.  
        
    error_category: If an error occurs, specifies the name of a category to 
        include with the error message.  The default category is  
        [Category:Errors reported by Module Sequence].
        
    no_category: If set to 'true' or 1, no category will be added if an error
        is generated.
        
]]

local seq = {}

--[[
len

This function returns the length of the target sequence.

Usage:
{{#invoke:Sequence|len|target_sequence}}
OR
{{#invoke:Sequence|len|s=target_sequence}}

Parameters
    s: The sequence whose length to report

]]
function seq.len( frame )
    local new_args = seq._getParameters( frame.args, {'s'} );
    local s = mw.text.split(mw.text.trim(new_args['s'], '"'),'", "') or {};
    return #s;
end

--[[
idx

This function returns a single element from the target sequence at index idx.

Usage:
{{#invoke:Sequence|idx|target_sequence|index_value}}
OR
{{#invoke:Sequence|idx|target=target_sequence|idx=index_value}}

Parameters
    target: The sequence to use
    idx: The index for the element to return

The first element has an index value of 1.

A requested index value of zero, or a value greater than the length of the sequence returns an error.
]]
function seq.idx( frame )
    local new_args = seq._getParameters( frame.args, {'target', 'idx'} );
    local target_seq = mw.text.split(mw.text.trim(new_args['target'], '"'),'", "') or {};
    local idx = tonumber( new_args['idx'] ) or 0;

    if (idx == 0 or math.abs(idx) > #target_seq ) then
        return seq._error( 'Sequence index out of range' );
    end

    return target_seq[idx];
end

--[[
some

This function returns a number of elements from the target sequence.
The elements' indices are given as a comma-separated list, and are output
separated by the given separator (default: comma)

Usage:
{{#invoke:Sequence|some|target_sequence|index_list|separator}}
OR
{{#invoke:Sequence|some|target=target_sequence|idxList=index_list|sep=separator}}

Parameters
    target: The sequence to use
    idxList: The index for the element to return
	sep: The character sequence to separate output elements

The first element has an index value of 1.

A requested index value of zero, or a value greater than the length of the sequence returns an error.
]]
function seq.some( frame )
    local new_args = seq._getParameters( frame.args, {'target', 'idxList', 'sep'} );
    local target_seq = mw.text.split(mw.text.trim(new_args['target'], '"'),'", "') or {};
    local idx_list = tostring( new_args['idxList'] ) or 0;
    local separator = tostring( new_args['sep'] ) or ",";

	local idx_seq = mw.text.split(idx_list, ",");
	local count = #idx_seq;
	local target_len = #target_seq;
		
	local idx = tonumber(idx_seq[1]) or 0;
	if (idx == 0 or math.abs(idx) > target_len ) then
        return seq._error( 'Sequence index out of range' );
    end
    local r = target_seq[idx];

	for i=2, count do
		idx = tonumber(idx_seq[i]) or 0;
		if (idx == 0 or math.abs(idx) > target_len ) then
	        return seq._error( 'Sequence index out of range' );
	    end
	    r = r .. separator .. target_seq[idx];
	end
	
    return r;
end

--[[
Helper function that populates the argument list given that user may need to use a mix of
named and unnamed parameters.  This is relevant because named parameters are not
identical to unnamed parameters due to string trimming, and when dealing with strings
we sometimes want to either preserve or remove that whitespace depending on the application.
]]
function seq._getParameters( frame_args, arg_list )
    local new_args = {};
    local index = 1;
    local value;
    
    for i,arg in ipairs( arg_list ) do
        value = frame_args[arg]
        if value == nil then
            value = frame_args[index];
            index = index + 1;
        end
        new_args[arg] = value;
    end
    
    return new_args;
end        

--[[
Helper function to handle error messages.
]]
function seq._error( error_str )
    local frame = mw.getCurrentFrame();
    local error_category = frame.args.error_category or 'Errors reported by Module Sequence';
    local ignore_errors = frame.args.ignore_errors or false;
    local no_category = frame.args.no_category or false;
    
    if seq._getBoolean(ignore_errors) then
        return '';
    end
    
    local error_str = '<strong class="error">Sequence Module Error: ' .. error_str .. '</strong>';
    if error_category ~= '' and not seq._getBoolean( no_category ) then
        error_str = '[[Category:' .. error_category .. ']]' .. error_str;
    end        
    
    return error_str;
end

--[[
Helper Function to interpret boolean strings
]]
function seq._getBoolean( boolean_str )
    local boolean_value;
    
    if type( boolean_str ) == 'string' then
        boolean_str = boolean_str:lower();
        if boolean_str == 'false' or boolean_str == 'no' or boolean_str == '0' 
                or boolean_str == '' then
            boolean_value = false;
        else
            boolean_value = true;
        end    
    elseif type( boolean_str ) == 'boolean' then
        boolean_value = boolean_str;
    else
        error( 'No boolean value found' );
    end    
    return boolean_value
end

return seq