사용자:BANIP/모듈:GameJSONParser
보이기
local p = {
SCHEME_PAGENAME = '리버티게임:게임 메타데이터/스키마.json'
} local table = require('table') -- 배열 입출력을 위한 테이블 내부 라이브러리
-- 속성 케이스 검사할 값, 발견시 반환할 값 정의 p.propertyCases = {
platform = { validate = function(gameMeta, scheme) local platform = t.walk(gameMeta, {"platform"}) if platform == nil then return false end local platFormDef = t.walk(scheme, {"$defs", "platform", "oneOf"}) local platFormData = t.find(platFormDef, function(p) return p.const == platform end) if platFormData == nil then return false end return platFormData end }, abandon = { validate = function(gameMeta, scheme) return {const = t.walk(gameMeta, {"abandon"}) or false} end }, construction = { validate = function(gameMeta, scheme) local construction = t.walk(gameMeta, {"construction"}) if not construction then return {const = false} end if construction == true then return {const = true} end return {const = true, date = construction} end }, progress = { validate = function(gameMeta, scheme) local progress = t.walk(gameMeta, {"progress"}) if progress == nil then return false end local progressDef = t.walk(scheme, {"properties", "progress", "oneOf"}) local progressData = t.find(progressDef, function(p) return p.const == progress end) if progressData == nil then return false end return progressData end }, editpolicy = { validate = function(gameMeta, scheme) local constKey = t.walk(gameMeta, {"editpolicy"}) or "closed" local progressDef = t.walk(scheme, {"properties", "editpolicy", "oneOf"}) if( progressDef == nil ) then mw.log("editpolicy가 null입니다.") return false end local progressData = t.find(progressDef, function(p) return p.const == constKey end) or progressDef[3] return progressData end }, rating = { validate = function(gameMeta, scheme) local age = t.walk(gameMeta, {"rating", "libertygame", "age"}) if age == nil then return false end local ageDef = t.walk(scheme, {"properties", "rating", "oneOf", 2, "properties", "libertygame", "properties", "age", "oneOf"}) local ageData = t.find(ageDef, function(a) return a.const == age end) if ageData == nil then return false end return ageData end }, repair = { validate = function(gameMeta, scheme) local repair = t.walk(gameMeta, {"repair"}) if not repair then return {const = false} end if repair == true then return {const = true} end return {const = true, date = repair} end }, genre = { validate = function(gameMeta, scheme) local genres = t.walk(gameMeta, {"genre"}) if genres == nil then return false end if type(genres) == "string" then genres = {genres} end local genreDef = t.walk(scheme, {"$defs", "genre", "oneOf"}) local genreData = t.filter(t.map(genres, function(genre) return t.find(genreDef, function(genreData) return genreData.const == genre end) end), function(genreData) return genreData ~= nil end)
return genreData end }
}
-- 테이블 관련 유틸리티 함수들 t = {
-- 자바스크립트의 find 함수와 동일 -- 주어진 함수를 만족하는 첫 번째 요소를 반환 find = function(tb, func) for _, value in ipairs(tb) do if func(value) then return value end end return nil end, -- 자바스크립트의 map 함수와 동일 -- 주어진 함수를 이용하여 테이블의 모든 요소를 변환 map = function(tb, func) local newTable = {} for i, value in ipairs(tb) do newTable[i] = func(value) end return newTable end, -- 자바스크립트의 filter 함수와 동일 -- 주어진 함수를 만족하는 요소만으로 새 테이블 생성 filter = function(tb, func) local newTable = {} for _, value in ipairs(tb) do if func(value) then table.insert(newTable, value) end end return newTable end, -- gameMeta.rating.libertygame.age와 같이 다단계 키로 이루어진 테이블 값을 가져오는 함수 -- 키의 경로 중간에 nil이 있는 경우 nil 반환 walk = function(tbl, keys) local value = tbl for i, key in ipairs(keys) do value = value[key] if value == nil or type(value) == 'number' or type(value) == 'string' then return value end end return value end,
}
-- 게임 메타데이터를 분석하고 각 속성에 대해 적절한 포맷을 적용하는 함수
function p._getParsedGameJson(scheme, gameMeta, formatters)
local results = {}
-- 각 속성 케이스를 순회합니다. for resultKey, formatterItem in pairs(formatters) do local formatter = formatterItem.formatter
local propertyKey = formatterItem.key -- propertyCase에 없는 키면 contiuue if p.propertyCases[propertyKey] == nil then mw.log("파싱하려는 " .. propertyKey .. "키는 propertyCase에 없습니다.") else -- 현재 속성의 유효성을 확인합니다. local validatedGroup = p.propertyCases[propertyKey].validate(gameMeta,scheme)
if validatedGroup ~= false and validatedGroup ~= nil then
-- 배열이 아닌 경우 기본 배열로 변환 if type(validatedGroup) ~= 'table' then validatedGroup = {} end
-- 1차원일 경우 2차원으로 변환 if type(validatedGroup[1]) ~= 'table' then validatedGroup = {validatedGroup} end
local resultItem = "" for propIndex, props in ipairs(validatedGroup) do local isEnable = formatterItem.enable or true if type(isEnable) == 'function' then isEnable = isEnable(props, propIndex) end
if isEnable then local thisItemString = formatter -- formatter가 함수면 prop 파라미터로 넣어서 실행 if type(formatter) == 'function' then thisItemString = formatter(props) end
-- props foreach for propKey, propValue in pairs(props) do thisItemString = thisItemString:gsub("${" .. propKey .. "}", propValue) end resultItem = resultItem .. thisItemString end end
--results[resultKey]에 resultItem입력 results[resultKey] = resultItem end end end return results
end
function p._getGameJsonTable(pagename, frame)
frame = frame or mw.getCurrentFrame() local gameMetaPagename = pagename or mw.title.getCurrentTitle().prefixedText
-- /game.json으로 안끝나면 붙여주기 if not gameMetaPagename:find("/game.json$") then gameMetaPagename = gameMetaPagename .. "/game.json" end
-- 위키낚시/game.json => :위키낚시/game.json -- 사:BANIP/위키낚시/game.json => 사:BANIP/위키낚시/game.json if not gameMetaPagename:find(":") then gameMetaPagename = ":" .. gameMetaPagename end
-- gameMetaPagename 페이지가 존재하는지 확인 없으면 null 반환 if not mw.title.new(gameMetaPagename).exists then return nil end -- -- 게임 메타데이터 획득 후 테이블로 변환 local gameMetaRaw = frame:expandTemplate{title = gameMetaPagename} local gameMeta = mw.text.jsonDecode(gameMetaRaw) return gameMeta
end
function p._getSchemaTable(frame)
frame = frame or mw.getCurrentFrame()
-- schemePagename 페이지가 존재하는지 확인 없으면 null 반환 if not mw.title.new(p.SCHEME_PAGENAME).exists then return nil end
-- 메타데이터 스키마 획득 후 테이블로 변환 local schemeRaw = frame:expandTemplate{title = p.SCHEME_PAGENAME} local scheme = mw.text.jsonDecode(schemeRaw)
return scheme
end
function p.getGameCategories(frame)
-- 틀 호출하기 위해서 필요한 현재 페이지 프레임 변수 획득
local currentFrame = mw.getCurrentFrame()
-- 스키마 획득 local scheme = p._getSchemaTable(currentFrame) -- 첫번째 변수혹은 현재 페이지명으로 게임 메타데이터 페이지 이름 획득 local gameMeta = p._getGameJsonTable(frame.args[1],currentFrame)
-- schemePagename 페이지가 존재하는지 확인 없으면 오류반환 if scheme == nil then return "자동 분류에 필요한 " .. p.SCHEME_PAGENAME .. " 페이지가 존재하지 않습니다. 관리자에게 알려주세요. " end -- game.json 페이지 있는지 확인 및 없으면 오류 반환 if gameMeta == nil then return "" end
local formatters = { { key = "platform", formatter = "[[분류:${title} 게임]]", }, { key = "abandon", formatter = "", enable = function(prop) return prop.const end }, { key = "construction", formatter = "", enable = function(prop) return prop.const end }, { key = "repair", formatter = "", enable = function(prop) return prop.const end }, { key = "progress", formatter = "[[분류:${title}]]", }, { key = "rating", formatter = "[[분류:${title} 게임]]", }, { key = "genre", formatter = "[[분류:${title}]]", } }
-- 게임 메타데이터 파싱 local parsed = p._getParsedGameJson(scheme, gameMeta, formatters)
-- 파싱 결과 join후 반환 return table.concat(parsed)
end
function p.getGamecard(pagename) local currentFrame = mw.getCurrentFrame()
-- 스키마 획득 local scheme = p._getSchemaTable(currentFrame) -- 첫번째 변수혹은 현재 페이지명으로 게임 메타데이터 페이지 이름 획득 local gameMeta = p._getGameJsonTable(pagename or frame.args[1],currentFrame)
-- 게임 메타데이터가 비어있으면 빈값 반환 if( gameMeta == nil ) then return "" end
local rand = function(seed, start_val, end_val) math.randomseed(seed) return math.random(start_val, end_val) end
local iconFormatter = [[
${icon} ${description}
]]
local formatters = { genre={ key = "genre", formatter = function(props) return "hsl(".. rand(props.const,0,360) ..",".. rand(props.const,50,100) .."%,92%)" end, }, platform={ key = "platform", formatter = iconFormatter, }, progress={ key = "progress", formatter = iconFormatter, }, editpolicy={ key = "editpolicy", formatter = iconFormatter, -- 파서 구현 필요 } }
-- 게임 메타데이터 파싱 local parsed = p._getParsedGameJson(scheme, gameMeta, formatters) return parsed -- return [[
--
--
--
--
-- ]].. parsed.platform .. parsed.editpolicy .. parsed.progress .. [[
--
-- ]].. (gameMeta.Name or pagename) ..[[
-- ]].. (gameMeta.Summary or "")..[[
-- ]].. (gameMeta.Description or "") ..[[
--
--
--
-- ]].. (gameMeta.Created or "") ..[[
--
-- -- ]]
end
return p