새 문서: -- This module provides easy processing of arguments passed to Scribunto from -- #invoke. It is intended for use by other Lua modules, and should not be -- called from #invoke directly. local libraryUtil = require('libraryUtil') local checkType = libraryUtil.checkType local arguments = {} -- Generate four different tidyVal functions, so that we don't have to check the -- options every time we call it. local function tidyValDefault(key, val) if type(val) == 'string' then v...
 
편집 요약 없음
태그: 되돌려진 기여
1번째 줄: 1번째 줄:
-- This module provides easy processing of arguments passed to Scribunto from
-- Module:StationLayout
-- #invoke. It is intended for use by other Lua modules, and should not be
local p = {}
-- called from #invoke directly.
local getArgs = require('Module:Arguments').getArgs
local html    = mw.html


local libraryUtil = require('libraryUtil')
----------------------------------------------------------------------
local checkType = libraryUtil.checkType
-- 유틸
----------------------------------------------------------------------


local arguments = {}
local function split(list, sep)
 
    sep = sep or ','
-- Generate four different tidyVal functions, so that we don't have to check the
    local out = {}
-- options every time we call it.
    for item in mw.text.gsplit(list or '', sep, true) do
 
        if item and item ~= '' then table.insert(out, mw.text.trim(item)) end
local function tidyValDefault(key, val)
    end
if type(val) == 'string' then
    return out
val = val:match('^%s*(.-)%s*$')
if val == '' then
return nil
else
return val
end
else
return val
end
end
 
local function tidyValTrimOnly(key, val)
if type(val) == 'string' then
return val:match('^%s*(.-)%s*$')
else
return val
end
end
end


local function tidyValRemoveBlanksOnly(key, val)
local function makeColorCell(num, color, inner)
if type(val) == 'string' then
    local cell = html.create('th')
if val:find('%S') then
        :attr('scope', 'col')
return val
        :css{width = '25px', ['font-weight']='normal'}
else
        :wikitext(inner and inner or num)
return nil
    if color then
end
        if color:match('자동다크') then
else
            color = '{{자동다크|' .. color:gsub('자동다크,?', '') .. '}}'
return val
        end
end
        cell
            :cssText('background:' .. color .. '; color:#fff;')
    end
    return cell
end
end


local function tidyValNoChange(key, val)
----------------------------------------------------------------------
return val
-- 상단 "선로 번호 가이드" 테이블
end
----------------------------------------------------------------------


local function matchesTitle(given, title)
local function buildTrackGuide(tracks, up, down)
local tp = type( given )
    local tbl = html.create('table')
return (tp == 'string' or tp == 'number') and mw.title.new( given ).prefixedText == title
        :addClass('wikitable')
        :css{width='125px', ['margin-left']='0'}
    tbl:tag('tr')
        :tag('th')
            :attr('colspan', #tracks * 2 + 1)
            :css('font-weight', 'normal')
            :wikitext(up)
    local row = tbl:tag('tr')
    -- 왼쪽 완충벽
    row:node(makeColorCell('|'))
    for _, spec in ipairs(tracks) do
        local num, color = spec.num, spec.color
        row:node(makeColorCell(num, color, num))
        -- 선로 사이 구분벽
        row:node(makeColorCell('|'))
    end
    tbl:tag('tr')
        :tag('th')
            :attr('colspan', #tracks * 2 + 1)
            :css('font-weight', 'normal')
            :wikitext(down)
    return tostring(tbl)
end
end


local translate_mt = { __index = function(t, k) return k end }
----------------------------------------------------------------------
-- 본문 행(row) 테이블
----------------------------------------------------------------------


function arguments.getArgs(frame, options)
local function buildMainTable(rows)
checkType('getArgs', 1, frame, 'table', true)
    local tbl = html.create('table')
checkType('getArgs', 2, options, 'table', true)
        :addClass('wikitable')
frame = frame or {}
options = options or {}


--[[
    for _, r in ipairs(rows) do
-- Set up argument translation.
        -- r = {range, line, icons, dest}
--]]
        local tr = tbl:tag('tr')
options.translate = options.translate or {}
        local rangeText = r.range:gsub('-', '·')                  -- 3-4 → 3·4
if getmetatable(options.translate) == nil then
        local first, last = rangeText:match('^(%d+)·?(%d*)$')
setmetatable(options.translate, translate_mt)
        local rowspan = 1
end
        if last and last ~= '' and tonumber(last) > tonumber(first) then
if options.backtranslate == nil then
            rowspan = tonumber(last) - tonumber(first) + 1
options.backtranslate = {}
        end
for k,v in pairs(options.translate) do
        tr:tag('th')
options.backtranslate[v] = k
            :attr('rowspan', rowspan)
end
            :css{width='25px', background='{{자동다크|#808080}}',
end
                color='#fff', ['font-weight']='normal'}
if options.backtranslate and getmetatable(options.backtranslate) == nil then
            :wikitext(rangeText)
setmetatable(options.backtranslate, {
        tr:tag('td')
__index = function(t, k)
            :css{['min-width']='7em', ['text-align']='left', ['font-weight']='normal'}
if options.translate[k] ~= k then
            :wikitext(r.line)
return nil
        tr:tag('td')
else
            :css{['min-width']='5em', ['text-align']='center', ['font-weight']='normal'}
return k
            :wikitext(r.icons)
end
        tr:tag('td')
end
            :css{['min-width']='7em', ['text-align']='left', ['font-weight']='normal'}
})
            :wikitext(r.dest)
end
    end
    return tostring(tbl)
end


--[[
----------------------------------------------------------------------
-- Get the argument tables. If we were passed a valid frame object, get the
-- 파서
-- frame arguments (fargs) and the parent frame arguments (pargs), depending
----------------------------------------------------------------------
-- on the options set and on the parent frame's availability. If we weren't
-- passed a valid frame object, we are being called from another Lua module
-- or from the debug console, so assume that we were passed a table of args
-- directly, and assign it to a new variable (luaArgs).
--]]
local fargs, pargs, luaArgs
if type(frame.args) == 'table' and type(frame.getParent) == 'function' then
if options.wrappers then
--[[
-- The wrappers option makes Module:Arguments look up arguments in
-- either the frame argument table or the parent argument table, but
-- not both. This means that users can use either the #invoke syntax
-- or a wrapper template without the loss of performance associated
-- with looking arguments up in both the frame and the parent frame.
-- Module:Arguments will look up arguments in the parent frame
-- if it finds the parent frame's title in options.wrapper;
-- otherwise it will look up arguments in the frame object passed
-- to getArgs.
--]]
local parent = frame:getParent()
if not parent then
fargs = frame.args
else
local title = parent:getTitle():gsub('/sandbox$', '')
local found = false
if matchesTitle(options.wrappers, title) then
found = true
elseif type(options.wrappers) == 'table' then
for _,v in pairs(options.wrappers) do
if matchesTitle(v, title) then
found = true
break
end
end
end


-- We test for false specifically here so that nil (the default) acts like true.
local function parseTracks(arg)
if found or options.frameOnly == false then
    local list = split(arg or '')
pargs = parent.args
    local tracks = {}
end
    for _, item in ipairs(list) do
if not found or options.parentOnly == false then
        local num, clr = item:match('^([%d%-]+)%s*%(([^%)]*)%)')
fargs = frame.args
        if not num then num, clr = item, nil end
end
        table.insert(tracks, {num = num, color = clr})
end
    end
else
    return tracks
-- options.wrapper isn't set, so check the other options.
end
if not options.parentOnly then
fargs = frame.args
end
if not options.frameOnly then
local parent = frame:getParent()
pargs = parent and parent.args or nil
end
end
if options.parentFirst then
fargs, pargs = pargs, fargs
end
else
luaArgs = frame
end


-- Set the order of precedence of the argument tables. If the variables are
local function parseRows(args)
-- nil, nothing will be added to the table, which is how we avoid clashes
    local rows = {}
-- between the frame/parent args and the Lua args.
    for k, v in pairs(args) do
local argTables = {fargs}
        if k:match('^row%d+') then
argTables[#argTables + 1] = pargs
            local parts = split(v, ';')
argTables[#argTables + 1] = luaArgs
            table.insert(rows, {
 
                range = parts[1] or '',
--[[
                line  = parts[2] or '',
-- Generate the tidyVal function. If it has been specified by the user, we
                icons = parts[3] or '',
-- use that; if not, we choose one of four functions depending on the
                dest  = parts[4] or ''
-- options chosen. This is so that we don't have to call the options table
            })
-- every time the function is called.
        end
--]]
    end
local tidyVal = options.valueFunc
    -- 원래 입력 순서를 유지하기 위해 sort
if tidyVal then
    table.sort(rows, function(a, b) return a.range < b.range end)
if type(tidyVal) ~= 'function' then
    return rows
error(
end
"bad value assigned to option 'valueFunc'"
.. '(function expected, got '
.. type(tidyVal)
.. ')',
2
)
end
elseif options.trim ~= false then
if options.removeBlanks ~= false then
tidyVal = tidyValDefault
else
tidyVal = tidyValTrimOnly
end
else
if options.removeBlanks ~= false then
tidyVal = tidyValRemoveBlanksOnly
else
tidyVal = tidyValNoChange
end
end
 
--[[
-- Set up the args, metaArgs and nilArgs tables. args will be the one
-- accessed from functions, and metaArgs will hold the actual arguments. Nil
-- arguments are memoized in nilArgs, and the metatable connects all of them
-- together.
--]]
local args, metaArgs, nilArgs, metatable = {}, {}, {}, {}
setmetatable(args, metatable)
 
local function mergeArgs(tables)
--[[
-- Accepts multiple tables as input and merges their keys and values
-- into one table. If a value is already present it is not overwritten;
-- tables listed earlier have precedence. We are also memoizing nil
-- values, which can be overwritten if they are 's' (soft).
--]]
for _, t in ipairs(tables) do
for key, val in pairs(t) do
if metaArgs[key] == nil and nilArgs[key] ~= 'h' then
local tidiedVal = tidyVal(key, val)
if tidiedVal == nil then
nilArgs[key] = 's'
else
metaArgs[key] = tidiedVal
end
end
end
end
end
 
--[[
-- Define metatable behaviour. Arguments are memoized in the metaArgs table,
-- and are only fetched from the argument tables once. Fetching arguments
-- from the argument tables is the most resource-intensive step in this
-- module, so we try and avoid it where possible. For this reason, nil
-- arguments are also memoized, in the nilArgs table. Also, we keep a record
-- in the metatable of when pairs and ipairs have been called, so we do not
-- run pairs and ipairs on the argument tables more than once. We also do
-- not run ipairs on fargs and pargs if pairs has already been run, as all
-- the arguments will already have been copied over.
--]]
 
metatable.__index = function (t, key)
--[[
-- Fetches an argument when the args table is indexed. First we check
-- to see if the value is memoized, and if not we try and fetch it from
-- the argument tables. When we check memoization, we need to check
-- metaArgs before nilArgs, as both can be non-nil at the same time.
-- If the argument is not present in metaArgs, we also check whether
-- pairs has been run yet. If pairs has already been run, we return nil.
-- This is because all the arguments will have already been copied into
-- metaArgs by the mergeArgs function, meaning that any other arguments
-- must be nil.
--]]
if type(key) == 'string' then
key = options.translate[key]
end
local val = metaArgs[key]
if val ~= nil then
return val
elseif metatable.donePairs or nilArgs[key] then
return nil
end
for _, argTable in ipairs(argTables) do
local argTableVal = tidyVal(key, argTable[key])
if argTableVal ~= nil then
metaArgs[key] = argTableVal
return argTableVal
end
end
nilArgs[key] = 'h'
return nil
end
 
metatable.__newindex = function (t, key, val)
-- This function is called when a module tries to add a new value to the
-- args table, or tries to change an existing value.
if type(key) == 'string' then
key = options.translate[key]
end
if options.readOnly then
error(
'could not write to argument table key "'
.. tostring(key)
.. '"; the table is read-only',
2
)
elseif options.noOverwrite and args[key] ~= nil then
error(
'could not write to argument table key "'
.. tostring(key)
.. '"; overwriting existing arguments is not permitted',
2
)
elseif val == nil then
--[[
-- If the argument is to be overwritten with nil, we need to erase
-- the value in metaArgs, so that __index, __pairs and __ipairs do
-- not use a previous existing value, if present; and we also need
-- to memoize the nil in nilArgs, so that the value isn't looked
-- up in the argument tables if it is accessed again.
--]]
metaArgs[key] = nil
nilArgs[key] = 'h'
else
metaArgs[key] = val
end
end
 
local function translatenext(invariant)
local k, v = next(invariant.t, invariant.k)
invariant.k = k
if k == nil then
return nil
elseif type(k) ~= 'string' or not options.backtranslate then
return k, v
else
local backtranslate = options.backtranslate[k]
if backtranslate == nil then
-- Skip this one. This is a tail call, so this won't cause stack overflow
return translatenext(invariant)
else
return backtranslate, v
end
end
end
 
metatable.__pairs = function ()
-- Called when pairs is run on the args table.
if not metatable.donePairs then
mergeArgs(argTables)
metatable.donePairs = true
end
return translatenext, { t = metaArgs }
end


local function inext(t, i)
----------------------------------------------------------------------
-- This uses our __index metamethod
-- 메인 엔트리
local v = t[i + 1]
----------------------------------------------------------------------
if v ~= nil then
return i + 1, v
end
end


metatable.__ipairs = function (t)
function p.main(frame)
-- Called when ipairs is run on the args table.
    local args = getArgs(frame, {trim=true, removeBlanks=false})
return inext, t, 0
    local top  = args.top  or ''
end
    local bottom = args.bottom or ''
    local trackSpec = parseTracks(args.tracks)
    local rows = parseRows(args)


return args
    local out = {}
    table.insert(out, buildTrackGuide(trackSpec, top, bottom))
    table.insert(out, buildMainTable(rows))
    return table.concat(out, '\n')
end
end


return arguments
return p

2025년 6월 29일 (일) 14:54 판

이 모듈에 대한 설명문서는 모듈:Arguments/설명문서에서 만들 수 있습니다

-- Module:StationLayout
local p = {}
local getArgs = require('Module:Arguments').getArgs
local html    = mw.html

----------------------------------------------------------------------
-- 유틸
----------------------------------------------------------------------

local function split(list, sep)
    sep = sep or ','
    local out = {}
    for item in mw.text.gsplit(list or '', sep, true) do
        if item and item ~= '' then table.insert(out, mw.text.trim(item)) end
    end
    return out
end

local function makeColorCell(num, color, inner)
    local cell = html.create('th')
        :attr('scope', 'col')
        :css{width = '25px', ['font-weight']='normal'}
        :wikitext(inner and inner or num)
    if color then
        if color:match('자동다크') then
            color = '{{자동다크|' .. color:gsub('자동다크,?', '') .. '}}'
        end
        cell
            :cssText('background:' .. color .. '; color:#fff;')
    end
    return cell
end

----------------------------------------------------------------------
-- 상단 "선로 번호 가이드" 테이블
----------------------------------------------------------------------

local function buildTrackGuide(tracks, up, down)
    local tbl = html.create('table')
        :addClass('wikitable')
        :css{width='125px', ['margin-left']='0'}
    tbl:tag('tr')
        :tag('th')
            :attr('colspan', #tracks * 2 + 1)
            :css('font-weight', 'normal')
            :wikitext(up)
    local row = tbl:tag('tr')
    -- 왼쪽 완충벽
    row:node(makeColorCell('|'))
    for _, spec in ipairs(tracks) do
        local num, color = spec.num, spec.color
        row:node(makeColorCell(num, color, num))
        -- 선로 사이 구분벽
        row:node(makeColorCell('|'))
    end
    tbl:tag('tr')
        :tag('th')
            :attr('colspan', #tracks * 2 + 1)
            :css('font-weight', 'normal')
            :wikitext(down)
    return tostring(tbl)
end

----------------------------------------------------------------------
-- 본문 행(row) 테이블
----------------------------------------------------------------------

local function buildMainTable(rows)
    local tbl = html.create('table')
        :addClass('wikitable')

    for _, r in ipairs(rows) do
        -- r = {range, line, icons, dest}
        local tr = tbl:tag('tr')
        local rangeText = r.range:gsub('-', '·')                   -- 3-4 → 3·4
        local first, last = rangeText:match('^(%d+)·?(%d*)$')
        local rowspan = 1
        if last and last ~= '' and tonumber(last) > tonumber(first) then
            rowspan = tonumber(last) - tonumber(first) + 1
        end
        tr:tag('th')
            :attr('rowspan', rowspan)
            :css{width='25px', background='{{자동다크|#808080}}',
                 color='#fff', ['font-weight']='normal'}
            :wikitext(rangeText)
        tr:tag('td')
            :css{['min-width']='7em', ['text-align']='left', ['font-weight']='normal'}
            :wikitext(r.line)
        tr:tag('td')
            :css{['min-width']='5em', ['text-align']='center', ['font-weight']='normal'}
            :wikitext(r.icons)
        tr:tag('td')
            :css{['min-width']='7em', ['text-align']='left', ['font-weight']='normal'}
            :wikitext(r.dest)
    end
    return tostring(tbl)
end

----------------------------------------------------------------------
-- 파서
----------------------------------------------------------------------

local function parseTracks(arg)
    local list = split(arg or '')
    local tracks = {}
    for _, item in ipairs(list) do
        local num, clr = item:match('^([%d%-]+)%s*%(([^%)]*)%)')
        if not num then num, clr = item, nil end
        table.insert(tracks, {num = num, color = clr})
    end
    return tracks
end

local function parseRows(args)
    local rows = {}
    for k, v in pairs(args) do
        if k:match('^row%d+') then
            local parts = split(v, ';')
            table.insert(rows, {
                range = parts[1] or '',
                line  = parts[2] or '',
                icons = parts[3] or '',
                dest  = parts[4] or ''
            })
        end
    end
    -- 원래 입력 순서를 유지하기 위해 sort
    table.sort(rows, function(a, b) return a.range < b.range end)
    return rows
end

----------------------------------------------------------------------
-- 메인 엔트리
----------------------------------------------------------------------

function p.main(frame)
    local args = getArgs(frame, {trim=true, removeBlanks=false})
    local top  = args.top   or ''
    local bottom = args.bottom or ''
    local trackSpec = parseTracks(args.tracks)
    local rows = parseRows(args)

    local out = {}
    table.insert(out, buildTrackGuide(trackSpec, top, bottom))
    table.insert(out, buildMainTable(rows))
    return table.concat(out, '\n')
end

return p