Module:Range
Jump to navigation
Jump to search
Template:Template for discussion/dated Returns one function called "iswitch", which takes its inspiration from {{#switch, but is limited to numeric values, and allows for ranges.
usage:
{{#invoke:Range | iswitch | value = 12 | 1 2 3..7 50..70 = one, two, three to seven, or fifty to seventy | 9..40 = between nine and forty (inclusive) | [41..48] = between 41 and 48 (inclusive) | (80..100 = larger (but not equal) than 80, and less or equal than 100 | (120..140) = larger (but not equal) than 120 and smaller than 140 | ..-2e9) = any number smaller (but not equal) than minus two billion | -2e9..0.75 = between minus two billion and three quarters | 1e6.. = equal or larger than 1 million | default = None of the ranges matches the value }}
syntax: {{#invoke:Range | iswitch | value = <Number> | ( <Ranges> = Result | )... [default=Result] }}
- <Number> ::= [-][digits][.][digits][e digits]
- <Ranges> ::= [ <Number> | <Range> ]...
- <Range> ::= [ [ [ | ( ] [<Number>] .. [<Number>] [ ] | ) ]
- Result ::= any string (can be multiline) that does not contain | or }} (if needed, use {{!}}, and Template:T. )
- When a range begins with (, it means the value has to be larger than the left limit. otherwise, it can be equal to the left limit. For convenience, [ can be used to mark "larger or equal", but it's not required (i.e. "1..100" is the same as "[1..100"
- Similarly, when a range ends with ) it means the value has to be strictly less than the right limit.
- A range may begin or end with ".."
- Such that ..100 means "100 or smaller", and 60.. means "60 or larger".
- "..100)" means smaller than 100, and "(60.." means larger than 60
if value matches a ranges, the function will return the "Result" of one of the matching ranges. If more than one range matches, it is unpredictable which of the results will be returned. The function does not test for overlap.
if none of the ranges match, and there is a "default", this value will return. otherwise, the function will return an empty string.
For tests see Module talk:Range/testcases
local function ranges( args )
local value
function inrange( v )
if tonumber( v ) then return tonumber( v ) == value end -- simple number - just compare
local lp, a, b, rp = v:match( '^([([]?)(.-)%.%.(.-)([)%]]?)$' ) -- a range
local na, nb = tonumber( a ), tonumber( b )
if a ~= '' and not na -- both a and b must be either empty or a valid number
or b ~= '' and not nb
or not ( na or nb ) -- at least one of na, nb must be a number
then
error(string.format( 'Bad parameter calling Range:iswitch: "%s" is not a number or valid range', v ), 0 )
return false
end
local llok = not na or na < value or lp ~= '(' and na == value
-- left-limit-ok: no ll or ll < value or ll == value and not open range
local rlok = not nb or value < nb or rp ~= ')' and value == nb
-- right-limit-ok: no rl or value < rl or value == rl and not open range
return llok and rlok
end
function match( s )
if type( s ) == 'number' then return s == value end
local res = false
s:gsub("%S+", function( c ) res = res or inrange( c ) end)
return res
end
value = tonumber( args.value )
if not value then error('Range:iswitch: should have a numeric "value" parameter', 0) end
for k, v in pairs( args ) do
if k ~= 'value' and k~= 'default' and match( k ) then return v end
end
return args['default'] or ''
end
return { iswitch = function( frame ) return ranges( frame.args ) end, }