Модуль:Валюта
Перейти к навигации
Перейти к поиску
Служебный модуль для шаблонов {{Измеряется деньгами}}, {{Загрузить курсы валют}} и {{Количество людей}}.
Тест
- По одной:
- 0,013495276653171 долларов, USD, доллар, доллара, ,
- Префикс:
- $ 0,013495276653171
- Кратные 1000:
- 1,3495276653171E-5 тыс долларов, тыс USD, тыс. долларов, тыс. USD, тысяч долларов, тысяч USD, тысячи долларов, тысячи USD, тысяча долларов, тысяча USD
- Кратные 1000000:
- 1,3495276653171E-8 млн долларов, млн USD, млн. долларов, млн. USD, миллионов долларов, миллионов USD, миллиона долларов, миллиона USD, миллион долларов, миллион USD
- Кратные 1000000000:
- 1,3495276653171E-11 млрд долларов, млрд USD, млрд. долларов, млрд. USD, миллиардов долларов, миллиардов USD, миллиарда долларов, миллиарда USD, миллиард долларов, миллиард USD
- Кратные 1000000000000:
- 1,3495276653171E-14 трлн долларов, трлн USD, трлн. долларов, трлн. USD, триллионов долларов, триллионов USD, триллиона долларов, триллиона USD, триллион долларов, триллион USD
- По одной:
--[[
Пересчёт валют, задание единиц измерения для валют, загрузка курсов валют:
--]]
-- Dependencies:
local append = require 'Module:Array'.table_append
local ask = mw.smw.ask
local gsub, match, split = mw.ustring.gsub, mw.ustring.match, mw.text.split
-- Predeclaration:
local data
-- Utility functions:
local concat = table.concat
local function glue (...)
local ret = {}
for _, val in ipairs {...} do
ret [#ret + 1] = type (val) == 'table' and concat (val, ', ') or val
end
return concat (ret, ', ')
end -- local function glue (...)
local lc, sub = mw.ustring.lower, mw.ustring.sub
local function lcfirst (str)
return lc (sub (str, 1, 1)) .. sub (str, 2, -1)
end -- local lcfirst (str)
local function formatNumeralError (message, ...)
if select('#', ... ) > 0 then
message = string.format(message, ...)
end
return "<span class=\"error\">" .. message .. "</span>"
end
--[[
НАЗНАЧЕНИЕ: Эта функция объявляет валюту.
ПАРАМЕТРЫ: names -- массив символов и названий валюты,
rate -- курс валюты к рублю.
ВЫВОД: нет.
ВОЗВРАТ: 0, сообщение об ошибке - Ошибка из-за неверного аргумента
строка - Объявление единиц измерения для валюты
ПРИМЕЧАНИЕ: Все проверки аргумента уже проведены.
--]]
local function implementCurrency (rate, plurals, singulars, duals, prefixes, abbr, maximum)
local lang = mw.getContentLanguage ()
local declarations = {}
if #singulars > 0 then
declarations [#declarations + 1] = '*** По одной:'
declarations [#declarations + 1] = '**** [[' .. data.prop .. '::' .. lang:formatNum (1 / rate) .. ' ' .. glue (plurals, singulars, duals, abbr) .. ']]'
end
if #prefixes > 0 then
declarations [#declarations + 1] = '*** Префикс:'
declarations [#declarations + 1] = '**** [[' .. data.prop .. '::' .. glue (prefixes) .. ' ' .. lang:formatNum (1 / rate) .. ']]'
end
if #plurals > 0 then
for _, settings in ipairs (data.mils) do
if not maximum or settings.ratio <= maximum then
local units = {}
for __, numeral in ipairs (settings.numerals) do
for ___, name in ipairs (append (plurals, abbr)) do
units [#units + 1] = numeral .. ' ' .. name
end
end
declarations [#declarations + 1] = '*** Кратные ' .. tostring (settings.ratio) .. ':'
declarations [#declarations + 1] = '**** [[' .. data.prop .. '::' .. lang:formatNum (1 / rate / settings.ratio) .. ' ' .. glue (units) .. ']]'
end -- if not max or settings.ratio <= maximum
end -- for _, settings in ipairs (data.mils)
end -- if #plurals > 0
return declarations
end -- local function implementCurrency (rate, plurals, singulars, duals, prefixes, abbr, max)
-- Загрузка аргументов и вызов реализации:
local function declareCurrency (args)
local rate = 1
local singulars, prefixes, plurals, duals, abbrs = {}, {}, {}, {}, {}
local maximum
-- Загрузка и проверка аргументов:
local params = data.API.params
local change = false
-- Guarantee order:
for arg, value in pairs (args) do
local split = split (value, '%s,' )
local param = params [arg]
if param == 'prefix' then
prefixes = append (prefixes, split)
elseif param == 'singular' then
singulars = append (singulars, split)
elseif param == 'dual' then
duals = append (duals, split)
elseif param == 'abbr' then
abbrs = append (abbrs, split)
elseif param == 'max' then
maximum = tonumber (value)
elseif tonumber (value) ~= nil then
-- Exchange rate:
rate = tonumber (value)
else
-- Currency symbol or name:
plurals = append (plurals, split)
end -- if param == 'singular' or param == 'prefix'
end
return table.concat (implementCurrency (rate, plurals, singulars, duals, prefixes, abbrs, maximum), '\n')
end -- local function declareCurrency (args)
local function getRates (basic)
return append (ask {
'[[' .. basic .. ']]'
, '?Название=full'
, '?Код ISO 4217=iso'
, '?Символ валюты=symbol'
, '?Сокращается как=abbr'
, '?Валюта в РП ДЧ=dual'
, '?Валюта в РП МЧ=plural'
, '?'
, link = 'none'
}, ask {
'[[Целевая валюта::' .. basic .. ']]'
.. '[[Исходная валюта.Важность::>>0]]'
, '?Коэффициент исходной валюты=quantity'
, '?Курс=rate'
, '?Дата курса=date'
, '?Исходная валюта.Название=full'
, '?Исходная валюта.Код ISO 4217=iso'
, '?Исходная валюта.Символ валюты=symbol'
, '?Исходная валюта.Сокращается как=abbr'
, '?Исходная валюта.Валюта в РП ДЧ=dual'
, '?Исходная валюта.Валюта в РП МЧ=plural'
, '?'
, limit = 10
, link = 'none'
, sort = 'Дата курса,Исходная валюта.Важность'
, order = 'desc,desc'
}) -- return append ...
end -- local function getRates (basic)
local function declareAll (args)
local basic = args [1]
local annotations = {}
for _, record in ipairs (getRates (basic)) do
local full = {}
for i, str in ipairs (type (record.full) == 'table' and record.full or {record.full}) do
full [i] = lcfirst (str)
end
if record.full then
annotations [#annotations + 1] = '**' .. glue (record.full) .. '\n'
.. table.concat (implementCurrency (
(record.rate or 1) / (record.quantity or 1)
, append (record.plural)
, append (full, record.iso, record.symbol)
, append (record.dual)
, append (record.symbol)
, append (record.abbr)
), '\n')
end
end -- for _, record in ipairs (getRates ())
return table.concat (annotations, '\n')
end -- local function declareAll (args)
-- Пересчёт валют, задание единиц измерения для валют:
data = {
API = {
-- Экспортируемые имена функций:
exports = {
[{'объявить', 'Объявить', 'declare', 'Declare'}] = declareCurrency,
[{'declareAll', 'auto', 'авто'}] = declareAll,
},
params = {
['префикс'] = 'prefix', prefix = 'prefix',
['единственное'] = 'singular', singular = 'singular',
['двойственное'] = 'dual', dual = 'dual',
['сокр'] = 'abbr', abbr = 'abbr',
['макс'] = 'max', max = 'max'
}
}, -- API
-- Ошибки:
noNumber = "Передайте аргумент",
-- Аргументы:
argNumber = 1, -- число
-- Кратные:
mils = {
--[1] = {''},
{ratio = 1000, numerals = {'тыс', 'тыс.', 'тысяч', 'тысячи', 'тысяча'}},
{ratio = 1000000, numerals = {'млн', 'млн.', 'миллионов', 'миллиона', 'миллион'}},
{ratio = 1000000000, numerals = {'млрд', 'млрд.', 'миллиардов', 'миллиарда', 'миллиард'}},
{ratio = 1000000000000, numerals = {'трлн', 'трлн.', 'триллионов', 'триллиона', 'триллион'}}
}, -- mils = {...}
prop = 'Относится к'
} -- data = {...}
--------------------------------------------------------------------------------
-- Загрузка курсов валют:
local services = {}
services ['currency'] = {
template = 'Записать курс валюты'
, subobject = 'Содержит курс валюты'
, cache = 10 * 365.2475 * 24 * 60 * 60 -- ten years.
} -- services ['currency']
services ['RUB.current'] = mw.clone (services ['currency'])
services ['RUB.current'].URL = 'http://www.cbr.ru/scripts/XML_daily.asp' --'https://www.cbr-xml-daily.ru/daily_utf8.xml'
services ['RUB.current'].encoding = 'Windows-1251'
services ['RUB.current'].xpaths = {
['Коэффициент исходной валюты'] = '/ValCurs/Valute/Nominal'
, ['Код исходной валюты'] = '/ValCurs/Valute/CharCode'
, ['Курс'] = '/ValCurs/Valute/Value'
, ['Целевая валюта'] = 'Рубль'
, ['Код целевой валюты'] = 'RUB'
, ['Дата курса'] = '/ValCurs/@Date'
, ['Источник курса'] = '$url$'
} -- services ['RUB.current'].xpaths
services ['RUB.current'].postprocess = {
['Курс'] = function (str)
return gsub (str, '%s+', '')
end
}
services ['RUB.historical'] = mw.clone (services ['RUB.current'])
services ['RUB.historical'].URL = 'http://www.cbr.ru/scripts/XML_daily.asp?date_req=$date#d.m.Y$' -- 'https://www.cbr-xml-daily.ru/archive/$date#Y/m/d$/daily_utf8.xml'
services ['RUB.historical'].cache = 365.25 * 24 * 60 * 60 -- one year.
services ['FOR.current'] = mw.clone (services ['currency'])
services ['FOR.current'].URL = 'http://www.floatrates.com/daily/$iso$.xml'
services ['FOR.current'].xpaths = {
['Дата курса'] = '/channel/pubDate'
, ['Коэффициент исходной валюты'] = '1'
, ['Курс'] = '/channel/item/inverseRate'
, ['Код исходной валюты'] = '/channel/item/targetCurrency'
, ['Код целевой валюты'] = '/channel/baseCurrency'
, ['Источник курса'] = '/channel/link'
} -- services ['FOR.daily'].xpaths
services ['FOR.current'].postprocess = {
['Курс'] = function (str)
return gsub (gsub (str, '^%.', '0,'), '%.', ',')
end
}
services ['FOR.historical'] = mw.clone (services ['FOR.current'])
services ['FOR.historical'].URL = 'https://www.floatrates.com/historical-exchange-rates.html?currency_date=$date#Y-m-d$&base_currency_code=$iso$&format_type=xml'
services ['FOR.historical'].cache = 365.25 * 24 * 60 * 60 -- one year.
services ['FOR.historical'].xpaths ['Курс'] = '/channel/item/exchangeRate'
services ['FOR.historical'].xpaths ['Источник курса'] = '$url$'
services ['FOR.historical'].xpaths ['Обратный'] = 'yes'
services ['FOR.historical'].postprocess = {
['Курс'] = function (str)
return gsub (gsub (tostring (1 / tonumber (str)), '^%.', '0,'), '%.', ',')
end
}
--------------------------------------------------------------------------------
local function substitute (str, symbols)
local ret = str
local lang = mw.getContentLanguage ()
for symbol, value in pairs (symbols) do
-- Formatted metasymbols:
ret = gsub (ret, '%$' .. symbol .. '#(.-)%$', function (format)
return lang:formatDate (format, value)
end)
-- Plain metasymbols:
ret = gsub (ret, '%$' .. symbol .. '%$', value)
end
return ret
end -- local function substitute (str, symbols)
local function pickService (iso, date)
local historical = date and 'historical' or 'current'
local service = services [(iso or 'FOR') .. '.' .. historical]
or services ['FOR.' .. historical]
-- Substitute metasymbols:
local symbols = {iso = iso, date = date}
service.URL = substitute (service.URL, symbols)
symbols.url = service.URL
for key, param in pairs (service.xpaths) do
service.xpaths [key] = substitute (param, symbols)
end
return service
end -- local function pickService (iso, date)
--------------------------------------------------------------------------------
local function named_join (tbl, separator)
local ret = {}
for key, val in pairs (tbl) do
ret [#ret + 1] = tostring (key) .. '=' .. tostring (val)
end
return table.concat (ret, separator or ',')
end -- local function named_join (tbl, separator)
local function key2key_join (tbl, separator)
local ret = {}
for key, _ in pairs (tbl) do
ret [#ret + 1] = tostring (key) .. '=' .. tostring (key)
end
return table.concat (ret, separator or ',')
end -- local function key2key_join (tbl, separator)
local function downloadRates (frame, url, xpaths, cache, encoding)
return frame:callParserFunction ('#get_web_data', {
'use xpath'
, url = url
, format = 'xml'
, data = xpaths
, ['cache seconds'] = cache
, encoding = encoding
})
end -- local function downloadRates (frame, url, xpaths, cache)
local function split_xpaths (params)
local depths, max_depth = {}, 0
-- Find the deepest xpath (it will fetch the most matches):
for name, param in pairs (params) do
local depth = 0
if sub (param, 1, 4) ~= 'http' then
depth = #gsub (param, '[^/]', '')
end
depths [name] = depth
if depth > max_depth then max_depth = depth end
end
local xpaths, constants, variables = {}, {}, {}
-- in {{#display_external_table}}, xpaths will either go to template head or to params:
for name, param in pairs (params) do
if depths [name] == max_depth then
variables [name] = name
xpaths [name] = param
elseif depths [name] == 0 then
constants [name] = param
else
constants [name] = '{{#external_value:' .. name .. '}}'
xpaths [name] = param
end
end -- for name, xpath in pairs (xpaths)
return named_join (xpaths, ',')
, constants ~= {} and '|' .. named_join (constants, '|') or ''
, key2key_join (variables, ',')
end -- local function split_xpaths (params)
local function saveRates (frame, template, constants, variables)
return '\n*' ..
frame:callParserFunction ('#display_external_table', {''
, template = template .. constants
, data = variables
, delimiter= '*'
})
end -- local function saveRates (frame, template, constants, variables)
--------------------------------------------------------------------------------
local function download (frame)
local page = mw.title.getCurrentTitle ().fullText
local iso = match (page, '%f[^/\0][A-Z][A-Z][A-Z]%f[/\0]')
local date = match (page, '[0-3]%d%.[01]%d%.%d%d%d%d$')
local service = pickService (iso, date)
local xpaths, constants, variables = split_xpaths (service.xpaths)
local header = '\n== Курсы валют к валюте «' .. (iso or '') .. '» '
.. (date and ': ' .. mw.getContentLanguage ():formatDate ('l, d xg Y', date) or '')
.. '==\n'
return header
.. downloadRates (frame, service.URL, xpaths, service.cache, service.encoding)
.. saveRates (frame, service.template, constants, variables)
end -- local function download (frame)
local function test (frame)
local page = mw.title.getCurrentTitle ().fullText
local iso = mw.ustring.match (page, '%f[^/\0][A-Z][A-Z][A-Z]%f[/\0]') or 'RUB'
local date = mw.ustring.match (page, '[0-3]%d%.[01]%d%.%d%d%d%d$')
or tostring (os.date ())
local service = pickService (iso, date)
local xpaths, constants, variables = split_xpaths (service.xpaths)
local dump = mw.dumpObject
return 'ISO: ' .. dump (iso) .. '\n\n'
.. 'date: ' .. dump (date) .. '\n\n'
.. 'service:\n' .. dump (service) .. '\n\n'
.. 'data param for {{#get_web_data}}: ' .. dump (xpaths) .. '\n\n'
.. 'template:' .. dump (service.template .. '|' .. constants) .. '\n\n'
.. 'data param for {{#display_external_table}}: ' .. dump (variables) .. '\n\n'
end -- local function test (frame)
--------------------------------------------------------------------------------
-- Export function:
local m = {}
for aliases, func in pairs (data.API.exports) do
for _, alias in ipairs (aliases) do
m [alias] = function (frame)
return func ((frame or {}).args)
end
end
end -- for aliases, func in pairs (data.API.exports)
m ['курсы'] = download
m ['test'] = test
return m