Module:Sandbox/Jeblad/NLG

local nlg = {}

--- Create the intersection of two tag sets local function intersection( a, b ) local check = {} for _,v in ipairs(a) do		check[v] = true end local found = {} for _,v in ipairs(b) do		if check[v] then found[1+#found] = v		end end return found end

local classes = {} -- this should probably in a separate module local layout = { ['lead-in'] = 0, ['history'] = 50, ['geography'] = 60, ['politics'] = 70, ['early-life'] = 30, ['death'] = 40, ['legacy'] = 50, ['bibliography'] = 60, ['notes'] = 70, ['footnotes'] = 70, ['references'] = 80, ['literature'] = 90, ['external-links'] = 100, }

local function createFromClass(t) return classes[t.class] and classes[t.class](t) end

local function createFromWeight(t) local max = -100 local constructor = nil local class = nil for _,v in pairs(classes) do		local weight = v.weight(t) if weight>max then max = weight constructor = v		end end return constructor and constructor(t) end

local function create(t) return createFromClass(t) or createFromWeight(t) end

--- Table acting as a baseclass for Plan local Plan = {} Plan.__index = Plan

classes.plan = Plan

setmetatable(Plan, {	__call = function(cls, ...)		local self = setmetatable({}, cls)		self:_init(...)		return self	end, })

--- Initialiser for the Plan class -- @param t table holding additional data function Plan:_init( t ) self._data = t	self._active = true self._position = 0 if self._data.class == nil then self._class = self:class end end

--- Get nudge -- @return number function Plan:nudge for k,v in pairs(layout) do	return self._class or self._data.class or 'plan' end return end

--- Get class -- @return string function Plan:class return self._class or self._data.class or 'plan' end

--- Is status active? -- @return boolean function Plan:isActive return self._active end

--- Activate status -- @return boolean function Plan:activate self._active = true return self._active end

--- Deactivate status -- @return boolean function Plan:deactivate self._active = false return self._active end

--- Weight of the given class viewed as a possible Plan instance -- @param t table holding data used during test function Plan.weight( t ) local weight = 0 if not t then return weight end weight = weight + (t.class == 'plan' and 100 or 0) weight = weight + (t.tags and 10 or 0) weight = weight + (t.preconditions and 10 or 0) weight = weight + (t.postconditions and 10 or 0) return weight end

--- Get the spawned tags by optionally filtering out a subset -- @param id(s) from the tagset -- @return table of Tags, otherwise empty table function Plan:tags(...) local args = {...} if #args == 0 then return self._data.tags or {} else return intersection({...}, self._data.tags) end end

--- Get the preconditions -- @return table of Expressions, otherwise empty table function Plan:preconditions return self._data.preconditions or {} end

--- Get the postconditions -- @return table of Expressions, otherwise empty table function Plan:postconditions return self._data.postconditions or {} end

--- Table acting as a subclass for Document local Document = {} Document.__index = Document

classes.document = Document

setmetatable(Document, { __index = Plan,  __call = function (cls, ...)    local self = setmetatable({}, cls)    self:_init(...)    return self  end, })

--- Initialiser for the Document class -- @param t table holding additional data function Document:_init( t ) Plan._init(self, t) end

--- Get class -- @return string function Document:class return self._class or self._data.class or 'document' end

--- Weight of the given class viewed as a possible Document instance -- @param t table holding data used during test function Document.weight( t ) local weight = 0 if not t then return weight end weight = weight + 0.9*Plan.weight(t) weight = weight + (t.class == 'document' and 100 or 0) weight = weight + (t.constituent and 10 or 0) weight = weight + (t.title and 10 or 0) return weight end

--- Get the title -- @return any if found, otherwise nil function Document:title return self._data.title end

--- Get the constituents -- @return table of Plan, otherwise empty table function Document:constituents return self._data.constituents or {} end

--- Get the activeConstituents -- @return table of Plan, otherwise empty table function Document:constituents local found = {} for _,v in ipairs(self._data.constituents or {}) do		found[1+#found] = v	end return found end

--- Table acting as a subclass for Constituent local Constituent = {} Constituent.__index = Constituent

classes.constituent = Constituent

setmetatable(Constituent, { __index = Plan,  __call = function (cls, ...)    local self = setmetatable({}, cls)    self:_init(...)    return self  end, })

--- Initialiser for the Constituent class -- @param t table holding additional data function Constituent:_init( t ) Plan._init(self, t) end

--- Get class -- @return string function Constituent:class return self._class or self._data.class or 'constituent' end

--- Weight of the given class viewed as a possible Constituent instance -- @param t table holding data used during test function Constituent.weight( t ) local weight = 0 if not t then return weight end weight = weight + 0.9*Plan.weight(t) weight = weight + (t.class == 'constituent' and 100 or 0) weight = weight + (t.nucleus and 10 or 0) weight = weight + (t.satelite and 10 or 0) weight = weight + (t.constituents and 10 or 0) weight = weight + (t.relation and 10 or 0) return weight end

if 1 or _G['_BDD'] then nlg['filter'] = filter nlg['create'] = create nlg['createFromClass'] = createFromClass nlg['createFromWeight'] = createFromWeight nlg['Plan'] = Plan nlg['Document'] = Document nlg['Constituent'] = Constituent end

nlg.load = function(...) local constituents = {} for _,v in ipairs({...}) do		local data = nil local title = 'Module:NLG/' .. v		if pcall(function data = mw.loadData( title ) end) and data then for _,w in ipairs(data) do				constituents[1+#constituents] = create(w) end end end local root = Document({		['class'] = 'document',		['constituents'] = constituents	}) return root end

return nlg