Module:WikiProjectBanner/Grade

Documentation for this module may be created at Module:WikiProjectBanner/Grade/doc

-------------------------------------------------------------------------------
--                  Grade class for Module:WikiProjectBanner                 --
--                                                                           --
-- This module contains the Grade class used in Module:WikiProjectBanner.    --
-- It is used for finding quality and importance grades.                     --
-------------------------------------------------------------------------------

-- Load required modules.
require('Module:No globals')
local libraryUtil = require('libraryUtil')
local checkType = libraryUtil.checkType
local mShared = require('Module:WikiProjectBanner/shared')

local Grade = {}
Grade.__index = Grade

function Grade.new(assessmentType, args, bannerData, cfg, gradeCfg)
	checkType('Grade.new', 1, assessmentType, 'string')
	checkType('Grade.new', 2, args, 'table')
	checkType('Grade.new', 3, bannerData, 'table')
	checkType('Grade.new', 4, cfg, 'table')
	checkType('Grade.new', 5, gradeCfg, 'table')
	
	local obj = setmetatable({}, Grade)

	obj.assessmentType = assessmentType
	obj.args = args
	obj.bannerData = bannerData
	obj.cfg = cfg
	obj.gradeCfg = gradeCfg

	return obj
end

function Grade:_validatePageStatusScales(scales)
	-- If banners specify a custom set of scales for each page status, this
	-- function checks that the scales table is valid.

	-- Check the type of the scales table.
	if scales == nil then
		return nil
	elseif type(scales) ~= 'table' then
		error(string.format(
			"type error in the 'pageStatusScales' field of gradeCfg"
				.. " (expected table, got %s)",
			type(scales)
		), 3)
	end

	-- Check that we have an "other" field.
	if not scales.other then
		error("the page status scale must have an 'other' field", 3)
	end

	-- Check all the grades.
	local grades = self.grades
	for key, scale in pairs(scales) do
		if key ~= 'other' and key ~= 'redirect' and type(key) ~= 'number' then
			error(
				"keys to the page status scales must be the string 'other',"
					.. " the string 'redirect', or a namespace number",
				3
			)
		end
		local scaleType = type(scale)
		if scaleType ~= 'table' and scaleType ~= 'string' then
			error(string.format(
				"type error in page status scale '%s' (expected table or string, got %s)",
				tostring(key), scaleType
			), 3)
		end
		scale = scaleType == 'table' and scale or {scale = true}
		for grade in pairs(scale) do
			if type(grade) ~= 'string' then
				error(string.format(
					"grades in page status scale '%s' must be strings; %s detected",
					tostring(key), type(grade)
				), 3)
			elseif not grades[grade] then
				error(string.format(
					"no grade data found for grade key '%s' in the page status scale",
					tostring(key)
				), 3)
			end
		end
	end
end

function Grade:getPageStatus()
	local title = self.bannerData.subjectTitle
	if title.isRedirect then
		return 'redirect'
	else
		return title.namespace
	end
end

function Grade:makeScale()
	-- Makes a scale table from the page status, the scale config, and the
	-- module config. It will look something like this:
	-- {
	--   fa = true,
	--   a  = true,
	--   b  = true,
	--   ...
	-- }
	local scales = self.cfg.assessment[self.assessmentType].scales
	local scaleCfg = self.gradeCfg.scale
	local pageStatus = self:getPageStatus()
	local scale
	if type(scaleCfg) == 'string' then
		scale = scales[scaleCfg][pageStatus] or scales[scaleCfg].other
	elseif type(scaleCfg) == 'table' then
		local grades = self.cfg.assessment[self.assessmentType].grades
		scale = {}
		for gradeName in pairs(scaleCfg) do
			if grades[gradeName] then
				scale[gradeName] = true
			end
		end
	elseif scaleCfg ~= false then
		scale = scales.standard[pageStatus] or scales.standard.other
	end
	return scale
end

function Grade:resolveGrade()
	local grade = self.gradeCfg.forceGrade
	if not grade then
		local param = self.gradeCfg.param or self.cfg.assessment[self.assessmentType].param
		local scale = self:makeScale()
		local rawGrade = self.args[param] or 'unassessed'
		rawGrade = mw.ustring.lower(rawGrade)
		grade = scale[rawGrade] and rawGrade or 'na'
	end
	return self.cfg.assessment[self.assessmentType].grades[grade]
end

function Grade:makeAssessmentCategory(t)
	t = t or {}
	local topic = t.topic or self.gradeCfg.topic or self.bannerData.project
	local msg = t.msg or self.gradeCfg.assessmentCategory or self.cfg.msg['assessment-category']
	local grade = t.grade
	return mShared.substituteParams(msg, grade, topic)
end

function Grade:exportData()
	-- Finds the grade and exports a table of data about it. The data is
	-- memoised so that we only have to generate it once.
	if not self._data then
		-- Grade data.
		local data = {}
		local grade = self:resolveGrade()
		for k, v in pairs(grade) do
			data[k] = v
		end

		-- Categories
		data.mainCategory = self.gradeCfg.mainCategory or nil
		data.assessmentCategory = self:makeAssessmentCategory{grade = data.full}

		self._data = data
	end
	return self._data
end

function Grade:exportCategories()
	local data = self:exportData()
	local cats = { data.mainCategory }
	cats[#cats + 1] = data.assessmentCategory
	return cats
end

return Grade