Jump to content
 







Main menu
   


Navigation  



Main page
Contents
Current events
Random article
About Wikipedia
Contact us
Donate
 




Contribute  



Help
Learn to edit
Community portal
Recent changes
Upload file
 








Search  

































Create account

Log in
 









Create account
 Log in
 




Pages for logged out editors learn more  



Contributions
Talk
 

















Module:Val: Difference between revisions






Аԥсшәа
العربية

Azərbaycanca
تۆرکجه
Basa Bali

Беларуская (тарашкевіца)

Буряад
Català
Čeština
الدارجة
Euskara
فارسی
Gaeilge
Galego

Hausa
Հայերեն
ि
Ilokano
Bahasa Indonesia
Italiano
Jawa

Lietuvių
Ligure
ि
Македонски


 / Mìng-dĕ̤ng-nḡ
Мокшень

Na Vosa Vakaviti


Oʻzbekcha / ўзбекча

Português
Română
Scots
Shqip
Simple English
Slovenščina
کوردی
Српски / srpski
Suomi
Svenska
ி
Taqbaylit
 
Tetun

Türkçe
Українська
اردو
Vèneto
Tiếng Vit


 

Edit links
 









Module
Talk
 

















Read
View source
View history
 








Tools
   


Actions  



Read
View source
View history
 




General  



What links here
Related changes
Upload file
Special pages
Permanent link
Page information
Get shortened URL
Download QR code
Wikidata item
 




Print/export  



Download as PDF
Printable version
 
















Appearance
   

 





Help

Permanently protected module

From Wikipedia, the free encyclopedia
 


Browse history interactively
 Previous edit
Content deleted Content added
m Changed protection level for "Module:Val": Highly visible module: match template ([Edit=Require template editor access] (indefinite) [Move=Require template editor access] (indefinite))
use i18n from Module:Val/sandbox added by User:Moroboshi
 
(One intermediate revision by the same user not shown)
Line 2: Line 2:

-- Format options include scientific and uncertainty notations.

-- Format options include scientific and uncertainty notations.



local data_module -- name of module defining units

local numdot = '.' -- decimal mark (use ',' for Italian)

local numsep = ',' -- group separator (use ' ' for Italian)

local mtext = {

-- Message and other text that should be localized.

['mt-bad-exponent'] = 'exponent parameter (<b>e</b>)',

['mt-parameter'] = 'parameter ',

['mt-not-number'] = 'is not a valid number',

['mt-cannot-range'] = 'cannot use a range if the first parameter includes "e"',

['mt-need-range'] = 'needs a range in parameter 2',

['mt-should-range'] = 'should be a range',

['mt-cannot-with-e'] = 'cannot be used if the first parameter includes "e"',

['mt-not-range'] = 'does not accept a range',

['mt-cannot-e'] = 'cannot use e notation',

['mt-too-many-parameter'] = 'too many parameters',

['mt-need-number'] = 'need a number after the last parameter because it is a range.',

['mt-ignore-parameter4'] = 'Val parameter 4 ignored',

['mt-val-not-supported'] = 'Val parameter "%s=%s" is not supported',

['mt-invalid-scale'] = 'Unit "%s" has invalid scale "%s"',

['mt-both-u-ul'] = 'unit (<b>u</b>) and unit with link (<b>ul</b>) are both specified, only one is allowed.',

['mt-both-up-upl'] = 'unit per (<b>up</b>) and unit per with link (<b>upl</b>) are both specified, only one is allowed.',

}


local data_module = 'Module:Val/units'

local convert_module = 'Module:Convert'



local function valerror(msg, nocat, iswarning)

local function valerror(msg, nocat, iswarning)

Line 58: Line 81:

-- Input like 1e3 is regarded as invalid for all except argument 1

-- Input like 1e3 is regarded as invalid for all except argument 1

-- which accepts e notation as an alternative to the 'e' argument.

-- which accepts e notation as an alternative to the 'e' argument.

-- Input commas are removed so 1,234 is the same as 1234.

-- Input group separators are removed.

local which = index

local which = index

local function fail(msg)

local function fail(msg)

local description

local description

if which == 'e' then

if which == 'e' then

description = 'exponent parameter (<b>e</b>)'

description = mtext['mt-bad-exponent']

else

else

description = 'parameter ' .. which

description = mtext['mt-parameter'] .. which

end

end

return description .. ' ' .. (msg or 'isnot a valid number') .. '.'

return description .. ' ' .. (msg or mtext['mt-not-number']) .. '.'

end

end

local result = {}

local result = {}

Line 75: Line 98:

if index == 2 then

if index == 2 then

if numbers[1] and numbers[1].exp then

if numbers[1] and numbers[1].exp then

return fail('cannot use a range if the first parameter includes "e"')

return fail(mtext['mt-cannot-range'])

end

end

numbers.has_ranges = true

numbers.has_ranges = true

else

else

if not numbers.has_ranges then

if not numbers.has_ranges then

return fail('needs a range in parameter 2')

return fail(mtext['mt-need-range'])

end

end

end

end

Line 90: Line 113:

return nil

return nil

end

end

return fail('does not accept a range')

return fail(mtext['mt-not-range'])

end

end

if numbers.has_ranges and type(index) == 'number' and (index % 2 == 0) then

if numbers.has_ranges and type(index) == 'number' and (index % 2 == 0) then

return fail('should be a range')

return fail(mtext['mt-should-range'])

end

end

if index == 'e' then

if index == 'e' then

Line 99: Line 122:

if e then

if e then

if arg then

if arg then

return fail('cannot be used if the first parameter includes "e"')

return fail(mtext['mt-cannot-with-e'])

end

end

arg = e

arg = e

Line 106: Line 129:

end

end

if arg and arg ~= '' then

if arg and arg ~= '' then

arg = arg:gsub(',', '')

arg = arg:gsub(numsep, '')

if numdot ~= '.' then

arg = arg:gsub(numdot, '.')

end

if arg:sub(1, 1) == '(' and arg:sub(-1) == ')' then

if arg:sub(1, 1) == '(' and arg:sub(-1) == ')' then

result.parens = true

result.parens = true

Line 117: Line 143:

result.exp = b

result.exp = b

else

else

return fail('cannot use e notation')

return fail(mtext['mt-cannot-e'])

end

end

end

end

Line 171: Line 197:

end

end

if index > 19 then

if index > 19 then

return 'too many parameters'

return mtext['mt-too-many-parameter']

end

end

end

end

if numbers.has_ranges and (#numbers % 2 == 0) then

if numbers.has_ranges and (#numbers % 2 == 0) then

return 'needanumber after the last parameter because it is a range.'

return mtext['mt-need-number']

end

end

end

end

Line 205: Line 231:

end

end

end

end

error('Unit "' .. ucode .. '" has invalid scale "' .. text .. '"')

error(string.format(mtext['mt-invalid-scale'], ucode, text))

end

end



Line 265: Line 291:


local function convert_lookup(ucode, value, scaled_top, want_link, si, options)

local function convert_lookup(ucode, value, scaled_top, want_link, si, options)

local lookup = require('Module:Convert')._unit

local lookup = require(convert_module)._unit

return lookup(ucode, {

return lookup(ucode, {

value = value,

value = value,

Line 433: Line 459:

return false

return false

end

end

local lookup = require('Module:Convert')._unit

local lookup = require(convert_module)._unit

local function show_convert(ucode, unit)

local function show_convert(ucode, unit)

-- If a built-in unit defines a scale or sets the SI flag, any unit defined in

-- If a built-in unit defines a scale or sets the SI flag, any unit defined in

Line 513: Line 539:

local delimit_groups = require('Module:Gapnum').groups

local delimit_groups = require('Module:Gapnum').groups

local function delimit(sign, numstr, fmt)

local function delimit(sign, numstr, fmt)

-- Return sign and numstr (unsigned digits or '.' only) after formatting.

-- Return sign and numstr (unsigned digits or numdot only) after formatting.

-- Four-digit integers are not formatted with gaps.

-- Four-digit integers are not formatted with gaps.

fmt = (fmt or ''):lower()

fmt = (fmt or ''):lower()

Line 524: Line 550:

local result

local result

if fmt == 'commas' then

if fmt == 'commas' then

result = sign .. table.concat(ipart, ',')

result = sign .. table.concat(ipart, numsep)

if dpart then

if dpart then

result = result .. '.' .. table.concat(dpart)

result = result .. numdot .. table.concat(dpart)

end

end

else

else

Line 536: Line 562:

end

end

if dpart then

if dpart then

table.insert(groups, '.' .. (table.remove(dpart, 1) or ''))

table.insert(groups, numdot .. (table.remove(dpart, 1) or ''))

for _, v in ipairs(dpart) do

for _, v in ipairs(dpart) do

table.insert(groups, '<span style="margin-left:.25em;">' .. v .. '</span>')

table.insert(groups, '<span style="margin-left:.25em;">' .. v .. '</span>')

Line 623: Line 649:


local function _main(values, unit_spec, options)

local function _main(values, unit_spec, options)

data_module = 'Module:Val/units' .. (options.sandbox and '/sandbox' or '')

if options.sandbox then

data_module = data_module .. '/sandbox'

convert_module = convert_module .. '/sandbox'

end

local action = options.action

local action = options.action

if action then

if action then

Line 744: Line 773:

for k, v in pairs(args) do

for k, v in pairs(args) do

if type(k) == 'string' and not whitelist[k] then

if type(k) == 'string' and not whitelist[k] then

local warning = 'Val parameter "' ..k .. '=' ..v .. '" is not supported'

local warning = string.format(mtext['mt-val-not-supported'],k,v)

return valerror(warning, nocat, true)

return valerror(warning, nocat, true)

end

end

end

end

if not has_ranges and args[4] then

if not has_ranges and args[4] then

return valerror('Val parameter 4 ignored', nocat, true)

return valerror(mtext['mt-ignore-parameter4'], nocat, true)

end

end

end

end

Line 755: Line 784:

local function main(frame)

local function main(frame)

local getArgs = require('Module:Arguments').getArgs

local getArgs = require('Module:Arguments').getArgs

local args = getArgs(frame, {wrappers = { 'Template:Val', 'Template:Val/sandboxlua' }})

local args = getArgs(frame, {wrappers = { 'Template:Val' }})

local nocat = args.nocategory

local nocat = args.nocategory

local numbers = {} -- table of number tables, perhaps with range text

local numbers = {} -- table of number tables, perhaps with range text

Line 763: Line 792:

end

end

if args.u and args.ul then

if args.u and args.ul then

return valerror('unit (<b>u</b>) and unit with link (<b>ul</b>) are both specified, only one is allowed.', nocat)

return valerror(mtext['mt-both-u-ul'], nocat)

end

end

if args.up and args.upl then

if args.up and args.upl then

return valerror('unit per (<b>up</b>) and unit per with link (<b>upl</b>) are both specified, only one is allowed.', nocat)

return valerror(mtext['mt-both-up-upl'], nocat)

end

end

local values

local values


Latest revision as of 03:19, 30 June 2022

This module implements {{Val}}.

The following modules are developed:

Use {{val/sandbox}} for testing, for example:

-- For Template:Val, output a number and optional unit.
-- Format options include scientific and uncertainty notations.

local numdot = '.'  -- decimal mark (use ',' for Italian)
local numsep = ','  -- group separator (use ' ' for Italian)
local mtext = {
 -- Message and other text that should be localized.
 ['mt-bad-exponent'] =       'exponent parameter (<b>e</b>)',
 ['mt-parameter'] =          'parameter ',
 ['mt-not-number'] =         'is not a valid number',
 ['mt-cannot-range'] =       'cannot use a range if the first parameter includes "e"',
 ['mt-need-range'] =         'needs a range in parameter 2',
 ['mt-should-range'] =       'should be a range',
 ['mt-cannot-with-e'] =      'cannot be used if the first parameter includes "e"',
 ['mt-not-range'] =          'does not accept a range',
 ['mt-cannot-e'] =           'cannot use e notation',
 ['mt-too-many-parameter'] = 'too many parameters',
 ['mt-need-number'] =        'need a number after the last parameter because it is a range.',
 ['mt-ignore-parameter4'] =  'Val parameter 4 ignored',
 ['mt-val-not-supported'] =  'Val parameter "%s=%s" is not supported',
 ['mt-invalid-scale'] =      'Unit "%s" has invalid scale "%s"',
 ['mt-both-u-ul'] =          'unit (<b>u</b>) and unit with link (<b>ul</b>) are both specified, only one is allowed.',
 ['mt-both-up-upl'] =        'unit per (<b>up</b>) and unit per with link (<b>upl</b>) are both specified, only one is allowed.',
}

local data_module = 'Module:Val/units'
local convert_module = 'Module:Convert'

local function valerror(msg, nocat, iswarning)
 -- Return formatted message text for an error or warning.
 -- Can append "#FormattingError" to URL of a page with a problem to find it.
 local anchor = '<span id="FormattingError"></span>'
 local body, category
 if nocat or mw.title.getCurrentTitle():inNamespaces(1, 2, 3, 5) then
  -- No category in Talk, User, User_talk, or Wikipedia_talk.
  category = ''
 else
  category = '[[Category:Pages with incorrect formatting templates use]]'
 end
 iswarning = false  -- problems are infrequent so try showing large error so editor will notice
 if iswarning then
  body = '<sup class="noprint Inline-Template" style="white-space:nowrap;">' ..
   '[[Template:Val|<span title="' ..
   msg:gsub('"', '&quot;') ..
   '">warning</span>]]</sup>'
 else
  body = '<strong class="error">' ..
   'Error in &#123;&#123;[[Template:val|val]]&#125;&#125;: ' ..
   msg ..
   '</strong>'
 end
 return anchor .. body .. category
end

local range_types = {
 -- No need for '&nbsp;' because nowrap applies to all output.
 [","]   = ", ",
 ["by"]  = " by ",
 ["-"]   = "–",
 ["–"]   = "–",
 ["and"] = " and ",
 ["or"]  = " or " ,
 ["to"]  = " to " ,
 ["x"]   = " × ",
 ["×"]   = " × ",
 ["/"]   = "/",
}
local range_repeat_unit = {
 -- WP:UNIT wants unit repeated when a "multiply" range is used.
 ["x"]   = true,
 ["×"]   = true,
}

local function extract_item(index, numbers, arg)
 -- Extract an item from arg and store the result in numbers[index].
 -- If no argument or if argument is valid, return nil (no error);
 -- otherwise, return an error message.
 -- The stored result is:
 -- * a table for a number (empty if there was no specified number); or
 -- * a string for range text
 -- Input like 1e3 is regarded as invalid for all except argument 1
 -- which accepts e notation as an alternative to the 'e' argument.
 -- Input group separators are removed.
 local which = index
 local function fail(msg)
  local description
  if which == 'e' then
   description = mtext['mt-bad-exponent']
  else
   description = mtext['mt-parameter'] .. which
  end
  return description .. ' ' .. (msg or mtext['mt-not-number']) .. '.'
 end
 local result = {}
 local range = range_types[arg]
 if range then
  if type(index) == 'number' and (index % 2 == 0) then
   if index == 2 then
    if numbers[1] and numbers[1].exp then
     return fail(mtext['mt-cannot-range'])
    end
    numbers.has_ranges = true
   else
    if not numbers.has_ranges then
     return fail(mtext['mt-need-range'])
    end
   end
   numbers[index] = range
   if range_repeat_unit[arg] then
    -- Any "repeat" range forces unit (if any) to be repeated for all items.
    numbers.isrepeat = true
   end
   return nil
  end
  return fail(mtext['mt-not-range'])
 end
 if numbers.has_ranges and type(index) == 'number' and (index % 2 == 0) then
  return fail(mtext['mt-should-range'])
 end
 if index == 'e' then
  local e = numbers[1] and numbers[1].exp
  if e then
   if arg then
    return fail(mtext['mt-cannot-with-e'])
   end
   arg = e
   which = 1
  end
 end
 if arg and arg ~= '' then
  arg = arg:gsub(numsep, '')
  if numdot ~= '.' then
   arg = arg:gsub(numdot, '.')
  end
  if arg:sub(1, 1) == '(' and arg:sub(-1) == ')' then
   result.parens = true
   arg = arg:sub(2, -2)
  end
  local a, b = arg:match('^(.+)[Ee](.+)$')
  if a then
   if index == 1 then
    arg = a
    result.exp = b
   else
    return fail(mtext['mt-cannot-e'])
   end
  end
  local isnegative, propersign, prefix
  local minus = '−'
  prefix, arg = arg:match('^(.-)([%d.]+)$')
  local value = tonumber(arg)
  if not value then
   return fail()
  end
  if arg:sub(1, 1) == '.' then
   arg = '0' .. arg
  end
  if prefix == '' then
   -- Ignore.
  elseif prefix == '±' then
   -- Display for first number, ignore for others.
   if index == 1 then
    propersign = '±'
   end
  elseif prefix == '+' then
   propersign = '+'
  elseif prefix == '-' or prefix == minus then
   propersign = minus
   isnegative = true
  else
   return fail()
  end
  result.clean = arg
  result.sign = propersign or ''
  result.value = isnegative and -value or value
 end
 numbers[index] = result
 return nil  -- no error
end

local function get_args(numbers, args)
 -- Extract arguments and store the results in numbers.
 -- Return nothing (no error) if ok; otherwise, return an error message.
 for index = 1, 99 do
  local which = index
  local arg = args[which]  -- has been trimmed
  if not arg then
   which = 'e'
   arg = args[which]
  end
  local msg = extract_item(which, numbers, arg)
  if msg then
   return msg
  end
  if which == 'e' then
   break
  end
  if index > 19 then
   return mtext['mt-too-many-parameter']
  end
 end
 if numbers.has_ranges and (#numbers % 2 == 0) then
  return mtext['mt-need-number']
 end
end

local function get_scale(text, ucode)
 -- Return the value of text as a number, or throw an error.
 -- This supports extremely basic expressions of the form:
 --   a / b
 --   a ^ b
 -- where a and b are numbers or 'pi'.
 local n = tonumber(text)
 if n then
  return n
 end
 n = text:gsub('pi', math.pi)
 for _, op in ipairs({ '/', '^' }) do
  local a, b = n:match('^(.-)' .. op .. '(.*)$')
  if a then
   a = tonumber(a)
   b = tonumber(b)
   if a and b then
    if op == '/' then
     return a / b
    elseif op == '^' then
     return a ^ b
    end
   end
   break
  end
 end
 error(string.format(mtext['mt-invalid-scale'], ucode, text))
end

local function get_builtin_unit(ucode, definitions)
 -- Return table of information for the specified built-in unit, or nil if not known.
 -- Each defined unit code must be followed by two spaces (not tab characters).
 local _, pos = definitions:find('\n' .. ucode .. '  ', 1, true)
 if pos then
  local endline = definitions:find('%s*\n', pos)
  if endline then
   local result = {}
   local n = 0
   local text = definitions:sub(pos + 1, endline - 1):gsub('%s%s+', '\t')
   for item in (text .. '\t'):gmatch('(%S.-)\t') do
    if item == 'ALIAS' then
     result.alias = true
    elseif item == 'ANGLE' then
     result.isangle = true
     result.nospace = true
    elseif item == 'NOSPACE' then
     result.nospace = true
    elseif item == 'SI' then
     result.si = true
    else
     n = n + 1
     if n == 1 then
      local link, symbol = item:match('^%[%[([^|]+)|(.+)%]%]$')
      if link then
       result.symbol = symbol
       result.link = link
       n = 2
      else
       result.symbol = item
      end
     elseif n == 2 then
      result.link = item
     elseif n == 3 then
      result.scale_text = item
      result.scale = get_scale(item, ucode)
     else
      result.more_ignored = item
      break
     end
    end
   end
   if result.si then
    local s = result.symbol
    if ucode == 'mc' .. s or ucode == 'mu' .. s then
     result.ucode = 'µ' .. s  -- unit code for convert should be this
    end
   end
   if n >= 2 or (n >= 1 and result.alias) then
    return result
   end
   -- Ignore invalid definition, treating it as a comment.
  end
 end
end

local function convert_lookup(ucode, value, scaled_top, want_link, si, options)
 local lookup = require(convert_module)._unit
 return lookup(ucode, {
   value = value,
   scaled_top = scaled_top,
   link = want_link,
   si = si,
   sort = options.sortable,
  })
end

local function get_unit(ucode, value, scaled_top, options)
 local want_link = options.want_link
 if scaled_top then
  want_link = options.want_per_link
 end
 local data = mw.loadData(data_module)
 local result = options.want_longscale and
  get_builtin_unit(ucode, data.builtin_units_long_scale) or
  get_builtin_unit(ucode, data.builtin_units)
 local si, use_convert
 if result then
  if result.alias then
   ucode = result.symbol
   use_convert = true
  end
  if result.scale then
   -- Setting si means convert will use the unit as given, and the sort key
   -- will be calculated from the value without any extra scaling that may
   -- occur if convert found the unit code. For example, if val defines the
   -- unit 'year' with a scale and if si were not set, convert would also apply
   -- its own scale because convert knows that a year is 31,557,600 seconds.
   si = { result.symbol, result.link }
   value = value * result.scale
  end
  if result.si then
   ucode = result.ucode or ucode
   si = { result.symbol, result.link }
   use_convert = true
  end
 else
  result = {}
  use_convert = true
 end
 local convert_unit = convert_lookup(ucode, value, scaled_top, want_link, si, options)
 result.sortkey = convert_unit.sortspan
 if use_convert then
  result.text = convert_unit.text
  result.scaled_top = convert_unit.scaled_value
 else
  if want_link then
   result.text = '[[' .. result.link .. '|' .. result.symbol .. ']]'
  else
   result.text = result.symbol
  end
  result.scaled_top = value
 end
 return result
end

local function makeunit(value, options)
 -- Return table of information for the requested unit and options, or
 -- return nil if no unit.
 options = options or {}
 local unit
 local ucode = options.u
 local percode = options.per
 if ucode then
  unit = get_unit(ucode, value, nil, options)
 elseif percode then
  unit = { nospace = true, scaled_top = value }
 else
  return nil
 end
 local text = unit.text or ''
 local sortkey = unit.sortkey
 if percode then
  local function bracketed(code, text)
   return code:find('[*./]') and '(' .. text .. ')' or text
  end
  local perunit = get_unit(percode, 1, unit.scaled_top, options)
  text = (ucode and bracketed(ucode, text) or '') ..
    '/' .. bracketed(percode, perunit.text)
  sortkey = perunit.sortkey
 end
 if not (unit.nospace or options.nospace) then
  text = '&nbsp;' .. text
 end
 return { text = text, isangle = unit.isangle, sortkey = sortkey }
end

local function list_units(mode)
 -- Return wikitext to list the built-in units.
 -- A unit code should not contain wikimarkup so don't bother escaping.
 local data = mw.loadData(data_module)
 local definitions = data.builtin_units .. data.builtin_units_long_scale
 local last_was_blank = true
 local n = 0
 local result = {}
 local function add(line)
  if line == '' then
   last_was_blank = true
  else
   if last_was_blank and n > 0 then
    n = n + 1
    result[n] = ''
   end
   last_was_blank = false
   n = n + 1
   result[n] = line
  end
 end
 local si_prefixes = {
  -- These are the prefixes recognized by convert; u is accepted for micro.
  y = 'y',
  z = 'z',
  a = 'a',
  f = 'f',
  p = 'p',
  n = 'n',
  u = 'µ',
  ['µ'] = 'µ',
  m = 'm',
  c = 'c',
  d = 'd',
  da = 'da',
  h = 'h',
  k = 'k',
  M = 'M',
  G = 'G',
  T = 'T',
  P = 'P',
  E = 'E',
  Z = 'Z',
  Y = 'Y',
 }
 local function is_valid(ucode, unit)
  if unit and not unit.more_ignored then
   assert(type(unit.symbol) == 'string' and unit.symbol ~= '')
   if unit.alias then
    if unit.link or unit.scale_text or unit.si then
     return false
    end
   end
   if unit.si then
    if unit.scale_text then
     return false
    end
    ucode = unit.ucode or ucode
    local base = unit.symbol
    if ucode == base then
     unit.display = base
     return true
    end
    local plen = #ucode - #base
    if plen > 0 then
     local prefix = si_prefixes[ucode:sub(1, plen)]
     if prefix and ucode:sub(plen + 1) == base then
      unit.display = prefix .. base
      return true
     end
    end
   else
    unit.display = unit.symbol
    return true
   end
  end
  return false
 end
 local lookup = require(convert_module)._unit
 local function show_convert(ucode, unit)
  -- If a built-in unit defines a scale or sets the SI flag, any unit defined in
  -- convert is not used (the scale or SI prefix's scale is used for a sort key).
  -- If there is no scale or SI flag, and the unit is not defined in convert,
  -- the sort key may not be correct; this allows such units to be identified.
  if not (unit.si or unit.scale_text) then
   if mode == 'convert' then
    unit.show = not lookup(unit.alias and unit.symbol or ucode).unknown
    unit.show_text = 'CONVERT'
   elseif mode == 'unknown' then
    unit.show = lookup(unit.alias and unit.symbol or ucode).unknown
    unit.show_text = 'UNKNOWN'
   elseif not unit.alias then
    -- Show convert's scale in square brackets ('[1]' for an unknown unit).
    -- Don't show scale for an alias because it's misleading for temperature
    -- and an alias is probably not useful for anything else.
    local scale = lookup(ucode, {value=1, sort='on'}).scaled_value
    if type(scale) == 'number' then
     scale = string.format('%.5g', scale):gsub('e%+?(%-?)0*(%d+)', 'e%1%2')
    else
     scale = '?'
    end
    unit.show = true
    unit.show_text = '[' .. scale .. ']'
   end
  end
 end
 for line in definitions:gmatch('([^\n]*)\n') do
  local pos, _ = line:find('  ', 1, true)
  if pos then
   local ucode = line:sub(1, pos - 1)
   local unit = get_builtin_unit(ucode, '\n' .. line .. '\n')
   if is_valid(ucode, unit) then
    show_convert(ucode, unit)
    local flags, text
    if unit.alias then
     text = unit.symbol
    else
     text = '[[' .. unit.link .. '|' .. unit.display .. ']]'
    end
    if unit.isangle then
     unit.nospace = nil  -- don't show redundant flag
    end
    for _, f in ipairs({
      { 'alias', 'ALIAS' },
      { 'isangle', 'ANGLE' },
      { 'nospace', 'NOSPACE' },
      { 'si', 'SI' },
      { 'scale_text', unit.scale_text },
      { 'show', unit.show_text },
     }) do
     if unit[f[1]] then
      local t = f[2]
      if t:match('^%u+$') then
       t = '<small>' .. t .. '</small>'
      end
      if flags then
       flags = flags .. ' ' .. t
      else
       flags = t
      end
     end
    end
    if flags then
     text = text .. ' • ' .. flags
    end
    add(ucode .. ' = ' .. text .. '<br />')
   else
    add(line .. ' ◆ <b>invalid definition</b><br />')
   end
  else
   add(line)
  end
 end
 return table.concat(result, '\n')
end

local delimit_groups = require('Module:Gapnum').groups
local function delimit(sign, numstr, fmt)
 -- Return sign and numstr (unsigned digits or numdot only) after formatting.
 -- Four-digit integers are not formatted with gaps.
 fmt = (fmt or ''):lower()
 if fmt == 'none' or (fmt == '' and #numstr == 4 and numstr:match('^%d+$')) then
  return sign .. numstr
 end
 -- Group number by integer and decimal parts.
 -- If there is no decimal part, delimit_groups returns only one table.
 local ipart, dpart = delimit_groups(numstr)
 local result
 if fmt == 'commas' then
  result = sign .. table.concat(ipart, numsep)
  if dpart then
   result = result .. numdot .. table.concat(dpart)
  end
 else
  -- Delimit with a small gap by default.
  local groups = {}
  groups[1] = table.remove(ipart, 1)
  for _, v in ipairs(ipart) do
   table.insert(groups, '<span style="margin-left:.25em;">' .. v .. '</span>')
  end
  if dpart then
   table.insert(groups, numdot .. (table.remove(dpart, 1) or ''))
   for _, v in ipairs(dpart) do
    table.insert(groups, '<span style="margin-left:.25em;">' .. v .. '</span>')
   end
  end
  result = sign .. table.concat(groups)
 end
 return result
end

local function sup_sub(sup, sub, align)
 -- Return the same result as Module:Su except val defaults to align=right.
 if align == 'l' or align == 'left' then
  align = 'left'
 elseif align == 'c' or align == 'center' then
  align = 'center'
 else
  align = 'right'
 end
 return '<span style="display:inline-block;margin-bottom:-0.3em;vertical-align:-0.4em;line-height:1.2em;font-size:85%;text-align:' ..
  align .. ';">' .. sup .. '<br />' .. sub .. '</span>'
end

local function range_text(items, unit_table, options)
 local fmt = options.fmt
 local nend = items.nend or ''
 if items.isrepeat or unit_table.isangle then
  nend = nend .. unit_table.text
 end
 local text = ''
 for i = 1, #items do
  if i % 2 == 0 then
   text = text .. items[i]
  else
   text = text .. delimit(items[i].sign, items[i].clean, fmt) .. nend
  end
 end
 return text
end

local function uncertainty_text(uncertainty, unit_table, options)
 local angle, text, need_parens
 if unit_table.isangle then
  angle = unit_table.text
 end
 local upper = uncertainty.upper or {}
 local lower = uncertainty.lower or {}
 local uncU = upper.clean
 if uncU then
  local fmt = options.fmt
  local uncL = lower.clean
  if uncL then
   uncU = delimit('+', uncU, fmt) .. (upper.errend or '')
   uncL = delimit('−', uncL, fmt) .. (lower.errend or '')
   if angle then
    uncU = uncU .. angle
    uncL = uncL .. angle
   end
   text = (angle or '') ..
    '<span style="margin-left:0.3em;">' ..
    sup_sub(uncU, uncL, options.align) ..
    '</span>'
  else
   if upper.parens then
    text = '(' .. uncU .. ')'  -- old template did not delimit
   else
    text = (angle or '') ..
     '<span style="margin-left:0.3em;margin-right:0.15em;">±</span>' ..
     delimit('', uncU, fmt)
    need_parens = true
   end
   if uncertainty.errend then
    text = text .. uncertainty.errend
   end
   if angle then
    text = text .. angle
   end
  end
 else
  if angle then
   text = angle
  end
 end
 return text, need_parens
end

local function _main(values, unit_spec, options)
 if options.sandbox then
  data_module = data_module .. '/sandbox'
  convert_module = convert_module .. '/sandbox'
 end
 local action = options.action
 if action then
  if action == 'list' then
   -- Kludge: am using the align parameter (a=xxx) for type of list.
   return list_units(options.align)
  end
  return valerror('invalid action "' .. action .. '".', options.nocat)
 end
 local number = values.number or (values.numbers and values.numbers[1]) or {}
 local e_10 = options.e or {}
 local novalue = (number.value == nil and e_10.clean == nil)
 local fmt = options.fmt
 local want_sort = true
 local sortable = options.sortable
 if sortable == 'off' or (sortable == nil and novalue) then
  want_sort = false
 elseif sortable == 'debug' then
  -- Same as sortable = 'on' but the sort key is displayed.
 else
  sortable = 'on'
 end
 local sort_value = 1
 if want_sort then
  sort_value = number.value or 1
  if e_10.value and sort_value ~= 0 then
   -- The 'if' avoids {{val|0|e=1234}} giving an invalid sort_value due to overflow.
   sort_value = sort_value * 10^e_10.value
  end
 end
 local unit_table = makeunit(sort_value, {
      u = unit_spec.u,
      want_link = unit_spec.want_link,
      per = unit_spec.per,
      want_per_link = unit_spec.want_per_link,
      nospace = novalue,
      want_longscale = unit_spec.want_longscale,
      sortable = sortable,
     })
 local sortkey
 if unit_table then
  if want_sort then
   sortkey = unit_table.sortkey
  end
 else
  unit_table = { text = '' }
  if want_sort then
   sortkey = convert_lookup('dummy', sort_value, nil, nil, nil, { sortable = sortable }).sortspan
  end
 end
 local final_unit = unit_table.isangle and '' or unit_table.text
 local e_text, n_text, need_parens
 local uncertainty = values.uncertainty
 if uncertainty then
  if number.clean then
   n_text = delimit(number.sign, number.clean, fmt) .. (number.nend or '')
   local text
   text, need_parens = uncertainty_text(uncertainty, unit_table, options)
   if text then
    n_text = n_text .. text
   end
  else
   n_text = ''
  end
 else
  if values.numbers.isrepeat then
   final_unit = ''
  end
  n_text = range_text(values.numbers, unit_table, options)
  need_parens = true
 end
 if e_10.clean then
  if need_parens then
   n_text = '(' .. n_text .. ')'
  end
  e_text = '10<sup>' .. delimit(e_10.sign, e_10.clean, fmt) .. '</sup>'
  if number.clean then
   e_text = '<span style="margin-left:0.25em;margin-right:0.15em;">×</span>' .. e_text
  end
 else
  e_text = ''
 end
 local result =
  (sortkey or '') ..
  (options.prefix or '') ..
  n_text ..
  e_text ..
  final_unit ..
  (options.suffix or '')
 if result ~= '' then
  result = '<span class="nowrap">' .. result .. '</span>'
 end
 return result .. (options.warning or '')
end

local function check_parameters(args, has_ranges, nocat)
 -- Return warning text for the first problem parameter found, or nothing if ok.
 local whitelist = {
  a = true,
  action = true,
  debug = true,
  e = true,
  ['end'] = true,
  errend = true,
  ['+errend'] = true,
  ['-errend'] = true,
  fmt = true,
  ['long scale'] = true,
  long_scale = true,
  longscale = true,
  nocategory = true,
  p = true,
  s = true,
  sortable = true,
  u = true,
  ul = true,
  up = true,
  upl = true,
 }
 for k, v in pairs(args) do
  if type(k) == 'string' and not whitelist[k] then
   local warning = string.format(mtext['mt-val-not-supported'], k, v)
   return valerror(warning, nocat, true)
  end
 end
 if not has_ranges and args[4] then
  return valerror(mtext['mt-ignore-parameter4'], nocat, true)
 end
end

local function main(frame)
 local getArgs = require('Module:Arguments').getArgs
 local args = getArgs(frame, {wrappers = { 'Template:Val' }})
 local nocat = args.nocategory
 local numbers = {}  -- table of number tables, perhaps with range text
 local msg = get_args(numbers, args)
 if msg then
  return valerror(msg, nocat)
 end
 if args.u and args.ul then
  return valerror(mtext['mt-both-u-ul'], nocat)
 end
 if args.up and args.upl then
  return valerror(mtext['mt-both-up-upl'], nocat)
 end
 local values
 if numbers.has_ranges then
  -- Multiple values with range separators but no uncertainty.
  numbers.nend = args['end']
  values = {
   numbers = numbers,
  }
 else
  -- A single value with optional uncertainty.
  local function setfield(i, dst, src)
   local v = args[src]
   if v then
    if numbers[i] then
     numbers[i][dst] = v
    else
     numbers[i] = { [dst] = v }
    end
   end
  end
  setfield(1, 'nend', 'end')
  setfield(2, 'errend', '+errend')
  setfield(3, 'errend', '-errend')
  values = {
   number = numbers[1],
   uncertainty = {
    upper = numbers[2],
    lower = numbers[3],
    errend = args.errend,
   }
  }
 end
 local unit_spec = {
   u = args.ul or args.u,
   want_link = args.ul ~= nil,
   per = args.upl or args.up,
   want_per_link = args.upl ~= nil,
   want_longscale = (args.longscale or args.long_scale or args['long scale']) == 'on',
  }
 local options = {
   action = args.action,
   align = args.a,
   e = numbers.e,
   fmt = args.fmt,
   nocat = nocat,
   prefix = args.p,
   sandbox = string.find(frame:getTitle(), 'sandbox', 1, true) ~= nil,
   sortable = args.sortable or (args.debug == 'yes' and 'debug' or nil),
   suffix = args.s,
   warning = check_parameters(args, numbers.has_ranges, nocat),
  }
 return _main(values, unit_spec, options)
end

return { main = main, _main = _main }

Retrieved from "https://en.wikipedia.org/w/index.php?title=Module:Val&oldid=1095746275"

Hidden category: 
Wikipedia template-protected modules
 



This page was last edited on 30 June 2022, at 03:19 (UTC).

Text is available under the Creative Commons Attribution-ShareAlike License 4.0; additional terms may apply. By using this site, you agree to the Terms of Use and Privacy Policy. Wikipedia® is a registered trademark of the Wikimedia Foundation, Inc., a non-profit organization.



Privacy policy

About Wikipedia

Disclaimers

Contact Wikipedia

Code of Conduct

Developers

Statistics

Cookie statement

Mobile view



Wikimedia Foundation
Powered by MediaWiki