Module:Hatnote list: Difference between revisions

From Zoophilia Wiki
Jump to navigationJump to search
meta>Nihiltres
Simplified p.forSee
meta>Nihiltres
Updated from sandbox
Line 1: Line 1:
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- For see
--                           Module:Hatnote list                              --
--
--                                                                            --
-- Makes a "For X, see [[Y]]." list from raw parameters. Intended for the
-- This module produces and formats lists for use in hatnotes. In particular, --
-- {{about}} and {{redirect}} templates and their variants. Also incidentally
-- it implements the for-see list, i.e. lists of "For X, see Y" statements,  --
-- introduces andList & orList helpers, useful for other hatnote lists.
-- as used in {{about}}, {{redirect}}, and their variants. Also introduced    --
-- are andList & orList helpers for formatting lists with those conjunctions. --
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


Line 13: Line 14:
local p = {}
local p = {}


--------------------------------------------------------------------------------
-- List stringification helper functions
--
-- These functions are used for stringifying lists, usually page lists inside
-- the "Y" portion of "For X, see Y" for-see items.
--------------------------------------------------------------------------------
--default options table used across the list stringification functions
local stringifyListDefaultOptions = {
conjunction = "and",
separator = ",",
altSeparator = ";",
space = " "
}
-- Stringifies a list generically; probably shouldn't be used directly
function stringifyList(list, options)
-- Type-checks, defaults, and a shortcut
checkType("stringifyList", 1, list, "table")
if #list == 0 then return nil end
checkType("stringifyList", 2, options, "table", true)
options = options or {}
for k, v in pairs(stringifyListDefaultOptions) do
if options[k] == nil then options[k] = v end
end
local s = options.space
-- Set the separator; if any item contains it, use the alternate separator
local separator = options.separator
for k, v in pairs(list) do
if string.find(v, separator) then
separator = options.altSeparator
break
end
end
-- Set the conjunction, apply Oxford comma, and force a comma if #1 has "§"
local conjunction = s .. options.conjunction .. s
if #list == 2 and string.find(list[1], "§") or #list > 2 then
conjunction = separator .. conjunction
end
-- Return the formatted string
return mw.text.listToText(list, separator .. s, conjunction)
end
-- Stringifies a list with "and"
function p.andList (list)
function p.andList (list)
-- Stringifies a list with "and"
return stringifyList(list, {conjunction = "and"})
return mw.text.listToText(list, nil, (#list > 2 and ',' or '') .. ' and ')
end
end


-- Stringifies a list with "or"
function p.orList (list)
function p.orList (list)
-- Stringifies a list with "or"
return stringifyList(list, {conjunction = "or"})
return mw.text.listToText(list, nil, (#list > 2 and ',' or '') .. ' or ')
end
end


function p.forSee (frame, from, options)
--------------------------------------------------------------------------------
-- Calls _forSee but pulls from the frame.
-- For see
mArguments = require('Module:Arguments')
--
return p._forSee(mArguments.getArgs(frame), from, options)
-- Makes a "For X, see [[Y]]." list from raw parameters. Intended for the
end
-- {{about}} and {{redirect}} templates and their variants.
--------------------------------------------------------------------------------


function p._forSee (args, from, options)
--default options table used across the forSee family of functions
-- Produces a "For X, see [[Y]]" string from arguments. Expects index gaps
local forSeeDefaultOptions = {
-- but not blank or whitespace values; those should be filtered. Ignores
disambiguator = ' (disambiguation)',
-- arguments less than "from", and named arguments.
title = mw.title.getCurrentTitle().text,
otherText = 'other uses',
forseeForm = 'For %s, see %s.',
punctuationCollapseReplacements = {
["%.%.$"] = ".",
["%?%.$"] = "?",
["%!%.$"] = "!",
["%.%]%]%.$"] = ".]]",
["%?%]%]%.$"] = "?]]",
["%!%]%]%.$"] = "!]]"
}
}


-- Structures arguments into a table for stringification, & options
function p.forSeeArgsToTable (args, from, options)
-- Type-checks and defaults
-- Type-checks and defaults
checkType("_forSee", 1, args, 'table')
checkType("forSeeArgsToTable", 1, args, 'table')
checkType("_forSee", 2, from, 'number', true)
checkType("forSeeArgsToTable", 2, from, 'number', true)
from = from or 1
from = from or 1
checkType("_forSee", 3, options, 'table', true)
checkType("forSeeArgsToTable", 3, options, 'table', true)
options = options or {}
options = options or {}
local defaultOptions = {
for k, v in pairs(forSeeDefaultOptions) do
disambiguator = ' (disambiguation)',
forseeForm = 'For %s, see %s.',
title = mw.title.getCurrentTitle().text,
otherText = 'other uses'
}
for k, v in pairs(defaultOptions) do
if options[k] == nil then options[k] = v end
if options[k] == nil then options[k] = v end
end
end
-- maxArg's gotten manually because getArgs() and table.maxn aren't friends
-- maxArg's gotten manually because getArgs() and table.maxn aren't friends
local maxArg = 0
local maxArg = 0
Line 55: Line 106:
if type(k) == 'number' and k > maxArg then maxArg = k end
if type(k) == 'number' and k > maxArg then maxArg = k end
end
end
-- Structure the data out from the parameter list
-- Structure the data out from the parameter list
-- forTable is the wrapper table, with forRow rows
-- forTable is the wrapper table, with forRow rows
Line 89: Line 139:
table.insert(forTable, forRow)
table.insert(forTable, forRow)
until terminated or i > maxArg
until terminated or i > maxArg
return forTable
end


-- Stringify the table, which is easy because it's structured now
-- Takes a table as formatted by forSeeArgsToTable and stringifies it
function p.forSeeTableToString (forSeeTable, options)
-- Type-checks and defaults
checkType("forSeeTableToString", 1, forSeeTable, "table")
checkType("forSeeTableToString", 2, options, "table", true)
options = options or {}
for k, v in pairs(forSeeDefaultOptions) do
if options[k] == nil then options[k] = v end
end
-- Format each for-see item and make a table containing them
local strList = {}
local strList = {}
for k, v in pairs(forTable) do
for k, v in pairs(forSeeTable) do
local useStr = v.use
local useStr = v.use or options.otherText
local pagesStr = p.andList(mHatnote.formatPages(unpack(v.pages)))
local pagesStr = p.andList(mHatnote.formatPages(unpack(v.pages))) or
table.insert(strList, string.format(options.forseeForm, useStr, pagesStr))
mHatnote._formatLink(options.title .. options.disambiguator)
local forSeeStr = string.format(options.forseeForm, useStr, pagesStr)
for k, v in pairs(options.punctuationCollapseReplacements) do
forSeeStr = string.gsub(forSeeStr, k, v)
end
table.insert(strList, forSeeStr)
end
end
-- Return the concatenated list
return table.concat(strList, ' ')
return table.concat(strList, ' ')
end
-- Produces a "For X, see [[Y]]" string from arguments. Expects index gaps
-- but not blank or whitespace values; those should be filtered. Ignores
-- arguments less than "from", and named arguments.
function p._forSee (args, from, options)
local forSeeTable = p.forSeeArgsToTable(args, from, options)
return p.forSeeTableToString(forSeeTable, options)
end
-- Calls _forSee but pulls from the frame.
function p.forSee (frame, from, options)
mArguments = require('Module:Arguments')
return p._forSee(mArguments.getArgs(frame), from, options)
end
end


return p
return p

Revision as of 16:25, 5 May 2016

Usage from wikitext

This module is not designed be used directly from wikitext even though forSee does take an initial frame argument and could potentially be used from wikitext, e.g.:

  • {{hatnote|PREFIX {{#invoke:Hatnote list|forSee|{{tl|For}}|Module:For|{{tl|About}}|Module:About}} POSTFIX}}
    PREFIX Lua error at line 158: attempt to call field 'formatPages' (a nil value). POSTFIX

Usage from Lua

To call the module, use <syntaxhighlight lang="lua">local mHatList = require('Module:Hatnote list')</syntaxhighlight> or similar, then access its methods through the mHatList variable (or whatever was used).

andList

andList takes a list in table form, and returns a string with the list separated with "and" and commas as appropriate.

orList

orList takes a list in table form, and returns a string with the list separated with "or" and commas as appropriate.

forSee

_forSee takes three arguments: a table of trimmed arguments with blanks removed, a "from" number with the index to start at, and an options table, and returns a string with a number of "For X, see [[Y]]" sentences. The links are formatted using the methods from Module:Hatnote.

As a convenience, the forSee method (without the leading underscore) takes the same arguments except with a frame instead of an args table, using getArgs() from Module:Arguments to preprocess the arguments.


--------------------------------------------------------------------------------
--                           Module:Hatnote list                              --
--                                                                            --
-- This module produces and formats lists for use in hatnotes. In particular, --
-- it implements the for-see list, i.e. lists of "For X, see Y" statements,   --
-- as used in {{about}}, {{redirect}}, and their variants. Also introduced    --
-- are andList & orList helpers for formatting lists with those conjunctions. --
--------------------------------------------------------------------------------

local mArguments --initialize lazily
local mHatnote = require('Module:Hatnote')
local libraryUtil = require('libraryUtil')
local checkType = libraryUtil.checkType
local p = {}

--------------------------------------------------------------------------------
-- List stringification helper functions
--
-- These functions are used for stringifying lists, usually page lists inside
-- the "Y" portion of "For X, see Y" for-see items.
--------------------------------------------------------------------------------

--default options table used across the list stringification functions
local stringifyListDefaultOptions = {
	conjunction = "and",
	separator = ",",
	altSeparator = ";",
	space = " "
}

-- Stringifies a list generically; probably shouldn't be used directly
function stringifyList(list, options)
	-- Type-checks, defaults, and a shortcut
	checkType("stringifyList", 1, list, "table")
	if #list == 0 then return nil end
	checkType("stringifyList", 2, options, "table", true)
	options = options or {}
	for k, v in pairs(stringifyListDefaultOptions) do
		if options[k] == nil then options[k] = v end
	end
	local s = options.space
	-- Set the separator; if any item contains it, use the alternate separator
	local separator = options.separator
	for k, v in pairs(list) do
		if string.find(v, separator) then
			separator = options.altSeparator
			break
		end
	end
	-- Set the conjunction, apply Oxford comma, and force a comma if #1 has "§"
	local conjunction = s .. options.conjunction .. s
	if #list == 2 and string.find(list[1], "§") or #list > 2 then
		conjunction = separator .. conjunction
	end
	-- Return the formatted string
	return mw.text.listToText(list, separator .. s, conjunction)
end

-- Stringifies a list with "and"
function p.andList (list)
	return stringifyList(list, {conjunction = "and"})
end

-- Stringifies a list with "or"
function p.orList (list)
	return stringifyList(list, {conjunction = "or"})
end

--------------------------------------------------------------------------------
-- For see
--
-- Makes a "For X, see [[Y]]." list from raw parameters. Intended for the
-- {{about}} and {{redirect}} templates and their variants.
--------------------------------------------------------------------------------

--default options table used across the forSee family of functions
local forSeeDefaultOptions = {
	disambiguator = ' (disambiguation)',
	title = mw.title.getCurrentTitle().text,
	otherText = 'other uses',
	forseeForm = 'For %s, see %s.',
	punctuationCollapseReplacements = {
		["%.%.$"] = ".",
		["%?%.$"] = "?",
		["%!%.$"] = "!",
		["%.%]%]%.$"] = ".]]",
		["%?%]%]%.$"] = "?]]",
		["%!%]%]%.$"] = "!]]"
	}
}

-- Structures arguments into a table for stringification, & options
function p.forSeeArgsToTable (args, from, options)
	-- Type-checks and defaults
	checkType("forSeeArgsToTable", 1, args, 'table')
	checkType("forSeeArgsToTable", 2, from, 'number', true)
	from = from or 1
	checkType("forSeeArgsToTable", 3, options, 'table', true)
	options = options or {}
	for k, v in pairs(forSeeDefaultOptions) do
		if options[k] == nil then options[k] = v end
	end
	-- maxArg's gotten manually because getArgs() and table.maxn aren't friends
	local maxArg = 0
	for k, v in pairs(args) do
		if type(k) == 'number' and k > maxArg then maxArg = k end
	end
	-- Structure the data out from the parameter list
	-- forTable is the wrapper table, with forRow rows
	-- Rows are tables of a "use" string and a "pages" table of pagename strings
	local forTable = {}
	local i = from
	local terminated = false
	-- Repeat to generate and append each row
	repeat
		-- New empty row
		local forRow = {}
		-- If there's a blank use, assume the list's ended, use the default,
		-- and break at the end of this loop-through.
		forRow.use = args[i] or options.otherText
		if not args[i] then terminated = true end
		-- New empty list of pages
		forRow.pages = {}
		-- If there's not at least one page listed, use the default.
		table.insert(forRow.pages, args[i + 1] or (options.title .. options.disambiguator))
		-- If the option after next is "and", do an inner loop where we collect
		-- items following "and"'s until the "and"'s stop. If there's a blank
		-- where we'd expect an item, ignore it: "1|and||and|3" → {1, 3}
		while args[i + 2] == 'and' do
			if args[i + 3] then 
				table.insert(forRow.pages, args[i + 3])
			end
			-- Increment to the next "and"
			i = i + 2
		end
		-- Increment to the next use
		i = i + 2
		-- Add the row to the table
		table.insert(forTable, forRow)
	until terminated or i > maxArg
	
	return forTable
end

-- Takes a table as formatted by forSeeArgsToTable and stringifies it
function p.forSeeTableToString (forSeeTable, options)
	-- Type-checks and defaults
	checkType("forSeeTableToString", 1, forSeeTable, "table")
	checkType("forSeeTableToString", 2, options, "table", true)
	options = options or {}
	for k, v in pairs(forSeeDefaultOptions) do
		if options[k] == nil then options[k] = v end
	end
	-- Format each for-see item and make a table containing them
	local strList = {}
	for k, v in pairs(forSeeTable) do
		local useStr = v.use or options.otherText
		local pagesStr = p.andList(mHatnote.formatPages(unpack(v.pages))) or
			mHatnote._formatLink(options.title .. options.disambiguator)
		local forSeeStr = string.format(options.forseeForm, useStr, pagesStr)
		for k, v in pairs(options.punctuationCollapseReplacements) do
			forSeeStr = string.gsub(forSeeStr, k, v)
		end
		table.insert(strList, forSeeStr)
	end
	-- Return the concatenated list
	return table.concat(strList, ' ')
end

-- Produces a "For X, see [[Y]]" string from arguments. Expects index gaps
-- but not blank or whitespace values; those should be filtered. Ignores
-- arguments less than "from", and named arguments.
function p._forSee (args, from, options)
	local forSeeTable = p.forSeeArgsToTable(args, from, options)
	return p.forSeeTableToString(forSeeTable, options)
end

-- Calls _forSee but pulls from the frame.
function p.forSee (frame, from, options)
	mArguments = require('Module:Arguments')
	return p._forSee(mArguments.getArgs(frame), from, options)
end

return p