본문으로 이동

모듈:Pipeline

리버티게임, 모두가 만들어가는 자유로운 게임


모듈 설명문서[보기] [편집] [역사] [새로 고침]
단축:
틀:pipe


이전 값에 종속되는 여러 틀을 연속적으로 실행합니다. 이를 통해 복잡한 로직을 함수형으로 구현하거나 중첩된 틀을 가독성 좋게 바꿀 수 있습니다.

사용법[원본 편집]

code_blocks 코드
{{#invoke:Pipeline|pipe |{{>>|9|a=10}}11 |<nowiki>{{#expr:{{{1}}}+{{{a}}}+{{_}}}}</nowiki> }}
code
낙서장에서 확인
description 결과
30

이전에 실행된 함수의 값을 {{_}}를 통해 통째로 다음 함수에 넘겨줍니다. {{>>}} 함수를 활용하여 여러 값을 넘겨줄 수 있습니다.


local p = {}
local tf = require('모듈:TemplateFunction')
local random = require('모듈:Random')

local passRandStr = random.id(6, os.time())
local passTag = 'pipe-passed-data--' .. passRandStr
local passTagPattern = 'pipe%-passed%-data%-%-' .. passRandStr
local passPattern = '<' .. passTagPattern .. '>(.-)</' .. passTagPattern .. '>'

local iterRandStr = random.id(6, os.time())
local iterTag = 'pipe-passed-iterator--' .. iterRandStr
local iterTagPattern = 'pipe%-passed%-iterator%-%-' .. iterRandStr
local iterPattern = '<' .. iterTagPattern .. '>(.-)</' .. iterTagPattern .. '>'

function iferror(wt)
	local frame = mw.getCurrentFrame()
	local result = frame:callParserFunction('#iferror', wt, 1, 0)
	
	if result == '1' then
		return true
	elseif result == '0' then
		return false
	else
		error('Cannot detect error')
	end
end

function merge(target, source)
	for key, value in pairs(source) do
		target[key] = value
	end
	
	return target
end

function render(template, returned, passed)
	return template:transform('{{_}}', function(default)
		return returned or ''
	end):parse(passed)
end

function p.pipe(frame)
	local returned = ''
	local passed = nil
	
	-- 한 단계씩 파싱
	for _, source in ipairs(frame.args) do
		local title = mw.title.new(source, 'Template')
		
		-- {{>>| 파싱
		source = frame:preprocess(source:gsub('{{%s*>>%s*%|', '{{#invoke:Pipeline|pass|'))
		
		-- <nowiki> 해제
		source = mw.text.unstripNoWiki(mw.text.decode(source))
		
		if title and title.exists then
			-- 틀/문서 제목과 일치할 경우 틀로 처리
			returned = render(tf.load(source), returned, passed)
		elseif not pcall(function()
			-- 파서 함수 이름과 일치할 경우 파서 함수로 처리
			returned = frame:callParserFunction(source, passed)
		end) then
			-- 아니면 인라인 위키텍스트로 처리
			
			returned = render(tf.create(source), returned, passed) -- 이전 반환값 위키텍스트 파싱
			passed = returned:match(passPattern) -- pass 인자로 넘겨줄 부분: #pass 부분만 추출
			passed = passed and mw.text.jsonDecode(passed) -- pass 부분 테이블로 파싱
			returned = returned:gsub(passPattern, '') -- RETURNED로 넘겨줄 부분: #pass 부분 제외
		end
	end
	
	return returned
end

function p.from(args)
	return '<' .. passTag .. '>'
		.. mw.text.nowiki(mw.text.jsonEncode(args))
		.. '</' .. passTag .. '>'
end

function p.pass(frame)
	local args = {}
	
	for key, value in pairs(frame.args) do
		args[key] = mw.text.unstripNoWiki(value)
	end
	
	return p.from(args)
end

function p.each(frame)
	local source = frame.args[1]
	local iter = nil
	local passed = {}
	local returned = nil
	
	repeat
		iter = source:match(iterPattern)

		local nextsrc = source:gsub(iterPattern, function(json)
			local data = mw.text.jsonEncode(json)
			return data.next
		end)
		source = source:gsub(iterPattern, function(json)
			local data = mw.text.jsonEncode(json)
			return data.next
		end)
		
		local title = mw.title.new(source, 'Template')
			
		-- {{>>| 파싱
		handler = frame:preprocess(source:gsub('{{%s*>>%s*%|', '{{#invoke:Pipeline|pass|'))
		
		-- <nowiki> 해제
		handler = mw.text.unstripNoWiki(mw.text.decode(source))
		
		if title and title.exists then
			-- 틀/문서 제목과 일치할 경우 틀로 처리
			returned = render(tf.load(source), returned, passed)
		elseif not pcall(function()
			-- 파서 함수 이름과 일치할 경우 파서 함수로 처리
			returned = frame:callParserFunction(source, passed)
		end) then
			-- 아니면 인라인 위키텍스트로 처리
			
			returned = render(tf.create(source), returned, passed) -- 이전 반환값 위키텍스트 파싱
			local passedstr = returned:match(passPattern) -- pass 인자로 넘겨줄 부분: #pass 부분만 추출
			passed = passedstr and mw.ext.jsonDecode(passedstr) -- pass 부분 테이블로 파싱
			returned = returned:gsub(passPattern, '') -- RETURNED로 넘겨줄 부분: #pass 부분 제외
		end
		
		source = nextsrc
	until not iter
	
	return returned
end

function p.iter(frame)
	local this = frame.args[1]
	local next = mw.fratext.nowiki(frame.args[2])
	local json = mw.json.jsonEncode({
		this = this,
		next = next
	})
	
	return '<' .. iterTag .. '>'
		.. json
		.. '</' .. iterTag .. '>'
end

return p