모듈:Category

최근 편집: 2021년 11월 22일 (월) 05:47
인쇄용 판은 더 이상 지원되지 않으며 렌더링 오류가 있을 수 있습니다. 브라우저 북마크를 업데이트해 주시고 기본 브라우저 인쇄 기능을 대신 사용해 주십시오.

알려진 문제

순환 참조가 발생했을 시 ?action=edit으로 내용을 변경하기 전까지 문서 로딩이 되지 않습니다.


local p = {}

--- 주어진 분류들로 문서를 분류하고 분류들을 표시하기 위한 위키텍스트를 만듭니다.
-- 만약 '{{#invoke:Category|categorize|성격/단체, 성향/페미니즘}}'과 같이
-- 호출되었다면 다음 작업을 수행합니다:
-- 1. 반환값에 '[[분류:성격/단체]]'를 추가합니다.
-- 2. '분류:성격/단체'라는 문서가 있는지, 있다면 상위분류가 있는지를 확인합니다.
--     둘다 맞다면 반환값에 '분류:성격/단체'를 전개하여 추가합니다.
--     (해당 틀은 이 함수를 재귀호출합니다.)
-- 3. '성향/페미니즘'에 대해서도 같은 작업을 수행합니다.
-- @param frame 호출되면서 자동으로 만들어진 frame 객체.
-- @return 문서를 분류해 주는 위키텍스트, 오류가 있었다면 빈 문자열.
function p.categorize(frame)
	local args = safeArgs(frame)
	if args[1] == nil or args[1] == '' then
		return error('분류를 입력해 주세요', 0)
	end
	return _categorize(safeCategories(args), frame)
end

--- 다면분류에서 패싯을 찾습니다. 예를 들어 'A/B'를 인자로 받으면 A를 반환합니다.
-- @param frame 호출되면서 자동으로 만들어진 frame 객체.
-- @return 패싯 문자열.
function p.facet(frame)
	local text = ''
	if type(frame) == 'string' then text = frame
	else text = frame.args[1] end
	local slash = string.find(text, '/')
	if slash == nil then return text end
	return string.sub(text, 1, slash-1)
end

--- 다면분류에서 멤버를 찾습니다. 예를 들어 'A/B'를 인자로 받으면 B를 반환합니다.
-- @param frame 호출되면서 자동으로 만들어진 frame 객체.
-- @return 멤버 문자열.
function p.member(frame)
	local text = ''
	if type(frame) == 'string' then text = frame
	else text = frame.args[1] end
	local slash = string.find(text, '/')
	if slash == nil then return text end
	return string.sub(text, slash+1, #text)
end

--- 주어진 분류들로 문서를 분류하고 분류들을 표시하기 위한 위키텍스트를 반환합니다.
-- @param categories 표시할 분류들.
-- @param frame 호출되면서 자동으로 만들어진 frame 객체.
-- @return 문서를 분류해 주는 위키텍스트, 오류가 있었다면 빈 문자열.
function _categorize(categories, frame)
	local returnText = ''

	for i, v in ipairs(categories) do
		if v == nil then
			error('사용하신 분류 문법이 잘못되었습니다.' ..
				'[[도움말:문서 분류하기]]를 참고해 주세요', 0)
			return ''
		elseif v == mw.title.getCurrentTitle().text then
			error('자기자신으로 분류할 수 없습니다.' ..
				'[[도움말:문서 분류하기]]를 참고해 주세요', 0)
		end

		returnText = returnText .. '[[분류:' .. v .. ']]\n'
	end

	return returnText
end

--- 전달인자들이 포함하고 있는 분류 정보를 묶어 정해진 형태의 배열로 만듭니다.
-- @param args args은 다음 중 하나의 형태일 수 있습니다.
-- { 'A/B' } (권장)
-- { 'A/B, C/D' } (권장)
-- { 'A/B|C/D' }
-- { 'A|B|C|D' }
-- { 'A', 'B', 'C', 'D' }
-- { 'A/B', 'C/D' }
-- @return 'A/B' 형식의 문자열들을 담은 배열.
function safeCategories(args)
	if type( args ) == 'string' then args = { args } end

	local temp = {}
	-- 첫 번재 전달인자에 '|'가 있다면 '|'를 기준으로 분리시킵니다
	-- (예: 'A|B|C|D'이나 'A|B')
	if string.match(args[1], '|') ~= nil then
		for word in string.gmatch(args[1], '%s*([^%|]+)%s*') do
			temp[#temp+1] = word
		end
		args = temp
	end

	--1. 첫 번재 전달인자에 슬래시가 없는데 전달인자가 하나라면 오류(예: 'A')
	--2. 첫 번재 전달인자에 슬래시가 없으면서 여럿이라면
	--	슬래시를 추가하여 둘씩 묶습니다(예: 'A', 'B', 'C', 'D').
	if string.find(args[1], '/') == nil then
		if #args == 1 then
			error(
				'사용하신 구문은 다면분류가 아닙니다.' ..
				'[[도움말:문서 분류하기]]를 참고해 주세요',
				0)
		else
			temp = {}
			for i, v in ipairs(args) do
				if i % 2 ~= 0 then
					temp[#temp+1] = string.match(v, '^%s*(.-)%s*$')
				else
					temp[#temp] = temp[#temp] .. '/' ..
						string.match(v, '^%s*(.-)%s*$')
				end
			end
			args = temp
		end
	end

	-- 첫 번재 전달인자에 쉼표가 있다면 쉼표를 기준으로 각각을 분리합니다.
	-- 예시: 'A/B, C/D'
	if string.match(args[1], ',') ~= nil then
		temp = {}
		for word in string.gmatch(args[1], '%s*([^,]+)%s*') do
			temp[#temp+1] = word
		end
		args = temp
	end

	--전체적으로 trim 합니다.
	for i in ipairs(args) do
		args[i] = string.match(args[i], '^%s*(.-)%s*$')
	end

	return args
end

function hasValue(tab, val)
    for index, value in ipairs(tab) do
        if value == val then
            return true
        end
    end

    return false
end

--- frame 객체가 틀에서 호출되어 생긴 frame인지 바로 모듈이 호출되어 생긴
-- frame인지와 무관하게 args를 찾습니다.
-- @param frame 호출되면서 자동으로 만들어진 frame 객체.
-- @return args 호출되면서 전달받은 전달인자.
function safeArgs(frame)
	--frame은 metatable이라 next(frame.args)가 안 된다고 합니다.
	--@reference https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#frame.args
	if frame.args[1] ~= nil then
		return frame.args
	else
		return frame:getParent().args
	end
end

return p