Jump to content

Module:Auphen/sandbox/frame

From Yezur Wiki
Revision as of 12:37, 26 August 2026 by Thiorosan (talk | contribs) (test rig: Auphen/frame pointed at the sandbox engine)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

This is the documentation for Module:Auphen/sandbox/frame, a working copy of Module:Auphen/frame, the template-facing wrapper around the Auphen sound engine. It is a test rig rather than production code: no article, entry or template should depend on it, and its output is not evidence of what the live engine does.

It differs from the live frame in two places only — its header comment, and the require, which names Module:Auphen/sandbox in place of Module:Auphen. A candidate engine placed in the sandbox can therefore be driven through the same wrapper as the live one and the two compared side by side before the candidate is promoted. The per-language data pages it reads are the live ones at Module:Auphen/<code>; there are no sandbox copies of those. When the live frame changes, this copy has to be brought back into step with it by hand.

Template:Auphen invokes the live frame, so {{auphen}} never reaches this module. It is called directly, and exports nothing beyond the two entry points below:

{{#invoke:Auphen/sandbox/frame|auphen|word|code|ruleset}}
{{#invoke:Auphen/sandbox/frame|raw|word|code|ruleset}}

auphen formats the result: an estimated pronunciation is wrapped in slashes and marked up as IPA, while a named ruleset returns plain text. raw returns the engine's output unformatted, which is what a comparison table wants.

Parameters

Parameter Purpose
1 The word, in the language's orthography. Required. It is passed to the engine unaltered; a ~ is a word boundary handled there rather than here, each part being run as its own word.
2 The language registry code, such as YAQ-HE or YBS-PJ. Required. It is upper-cased before the matching Module:Auphen/<code> data page is loaded.
3 The name of a ruleset from that data page's sets table. Left empty, the module runs the page's pronounce ruleset instead and marks the result as an estimate.

All three are trimmed of surrounding whitespace. For an estimate the engine is built from the data page's ipacats (falling back to cats) together with its ipa_rules; for a named ruleset it is built from cats (falling back to ipacats) and no spelling rules are applied.

A missing word, a missing code, a code with no data page, or a ruleset name absent from sets yields an error rather than a script failure. auphen shows the message as an error span prefixed Auphen: and files the calling page into Category:Auphen errors — the live maintenance category, which a failing sandbox call will populate like any other; raw returns the message prefixed ERROR:.

Data pages are loaded with require rather than mw.loadData, because the read-only proxy mw.loadData returns does not enumerate nested tables under pairs(), which would hide the category members; the frame then copies the category tables into plain Lua tables before handing them to the engine. Template:Auphen/testcases holds the acceptance tests against the live frame, and the same rows can be pointed at this module to measure a candidate against them. The engine's design notes and behaviour log are on Module talk:Auphen.


-- Module:Auphen/sandbox/frame -- test rig: [[Module:Auphen/frame]] pointed at
-- [[Module:Auphen/sandbox]], so a candidate engine can be run side by side with
-- the live one before it is promoted. Keep in step with the real frame.
-- Backs {{auphen}}: with no ruleset it estimates pronunciation; with a named
-- ruleset it runs that derivation. p.auphen formats the result (/.../ for an
-- estimate); p.raw returns the bare engine output (used by the testcases page).
local Auphen = require('Module:Auphen/sandbox')

local p = {}

-- Copy an mw.loadData category proxy into plain Lua tables for the engine.
local function plain_cats(src)
	if type(src) ~= 'table' then return nil end
	local out = {}
	for name, members in pairs(src) do
		local m = {}
		for i = 1, #members do m[i] = members[i] end
		out[name] = m
	end
	return out
end

-- Core: returns (output, isEstimation, errMessage). errMessage ~= nil on error.
local function run_core(a)
	local word = mw.text.trim(a[1] or '')
	local code = mw.text.trim(a[2] or '')
	local rs   = mw.text.trim(a[3] or '')
	if word == '' then return nil, nil, 'no word given' end
	if code == '' then return nil, nil, 'no language code given' end

	-- require (not mw.loadData): loadData's read-only proxy does not enumerate
	-- nested tables under pairs() in Lua 5.1, which would hide the categories.
	local ok, data = pcall(require, 'Module:Auphen/' .. code:upper())
	if not ok or type(data) ~= 'table' then
		return nil, nil, 'no sound data for code "' .. code .. '"'
	end

	if rs == '' then
		local eng = Auphen.new(plain_cats(data.ipacats or data.cats), data.ipa_rules)
		return eng:run(data.pronounce or '', word, true), true, nil
	else
		local ruleset = (type(data.sets) == 'table') and data.sets[rs] or nil
		if ruleset == nil then
			return nil, nil, 'unknown ruleset "' .. rs .. '" for code "' .. code .. '"'
		end
		local eng = Auphen.new(plain_cats(data.cats or data.ipacats))
		return eng:run(ruleset, word, false), false, nil
	end
end

local function err(msg)
	return '<strong class="error">Auphen: ' .. mw.text.nowiki(msg) ..
		'</strong>[[Category:Auphen errors]]'
end

-- {{#invoke:Auphen/frame|auphen | word | code | ruleset }}  (via {{auphen}})
function p.auphen(frame)
	local out, est, e = run_core(frame.args)
	if e then return err(e) end
	if est then return '<span class="IPA">/' .. out .. '/</span>' end
	return out
end

-- {{#invoke:Auphen/frame|raw | word | code | ruleset }} -- bare output, no
-- formatting (for the testcases page and callers that want the phonemes only).
function p.raw(frame)
	local out, _, e = run_core(frame.args)
	if e then return 'ERROR: ' .. e end
	return out
end

return p