Modul:NLG
Utseende
This will use Closure-based inheritance as referenced tables will have metatables and because of that can't use the ordinary inheritance mechanism.
The inputs to a NLG-system will depend on a 4-tuple
Where is the knowledge source (Wikidata), is the communicative goal, is a user model, and is a discourse history.
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