A company that writes with LaTeX ends up with a document class, a letter class and a presentation theme that share a design and not a line of code. Every fix is then made three times, two of them late and the third never. Here the page is written once. A company declares its colours, faces and logo in one file, and the document template, the letter class and the presentation theme read that one file. Nothing in the suite carries a colour value, a font name or a file name of any company, which is what lets it be published while the companies stay private. Every measure of the page follows from a measurement or from a named definition: the room the head and the foot need is taken from the boxes they really build, one line of the body text stands between the head and the text and between the text and the foot, a heading never stands alone at the foot of a page, a picture takes the size of the family, and a Markdown file reaches the same page as the same document written in LaTeX. The suite ships with a company that does not exist, Nordwind AG, so that it builds and is measured anywhere: three colours, the TeX Gyre families every installation carries, and an icon drawn in TikZ. 574 checks over five measurements, all of them on the rendered page or on the build log rather than on the source. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
93 lines
3.8 KiB
Python
93 lines
3.8 KiB
Python
#!/usr/bin/env python3
|
|
"""The values the family decided, against the defaults of this suite.
|
|
|
|
The suite came out of `pacta.sty`, and the proportions of its logo were decided
|
|
there and confirmed for every company of the family. A derivation that replaces
|
|
one of those numbers has to REPRODUCE it; where it does not, it is a new value,
|
|
and nobody decided it.
|
|
|
|
That is not an abstract risk. On 2026-09-21 this suite carried four derivations
|
|
in place of those numbers for half a day — the logo of the page head measured
|
|
off the running head instead of 2em, the one of the title block as three times
|
|
that instead of 6em, the name beside the logo fitted to the ink of the drawing
|
|
instead of 0.8 of its height, the gap in ems of the name instead of 0.1 of that
|
|
height — and every one of them came out at another size than in the two companies
|
|
beside it. It was visible on the first page of the first document.
|
|
|
|
The origin is read where LaTeX finds it. Where it is not installed, this says so
|
|
and passes: a company that has no Pacta beside it cannot compare, and a test that
|
|
fails for a missing neighbour says nothing about this suite.
|
|
"""
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
import support
|
|
from support import Check
|
|
|
|
SUITE = os.path.join(support.SUITE, "business-suite.sty")
|
|
IDENTITY = os.path.join(support.SUITE, "business-identity.sty")
|
|
|
|
# What is compared, and where each value stands in the two files.
|
|
HEIGHTS = (
|
|
("logoheight", r"\\newcommand\{\\pacta@logoheight\}\{([^}]*)\}",
|
|
r"\\newcommand\{\\business@logoheight\}\{([^}]*)\}",
|
|
"the logo of the page head"),
|
|
("titlelogoheight", r"\\newcommand\{\\pacta@titlelogoheight\}\{([^}]*)\}",
|
|
r"\\newcommand\{\\business@titlelogoheight\}\{([^}]*)\}",
|
|
"the logo of the title block"),
|
|
)
|
|
# The three proportions of the lockup, as the origin writes them: the name at
|
|
# 0.8 of the height, the gap beside it at 0.1, the gap over the address at 0.1.
|
|
FACTORS = (
|
|
("namefactor", 0.8, r"\\newcommand\{\\business@namefactor\}\{([0-9.]+)\}",
|
|
"the size of the name beside the logo"),
|
|
("namegap", 0.1, r"\\newcommand\{\\business@namegap\}\{([0-9.]+)\}",
|
|
"the gap between the logo and the name"),
|
|
("addressgap", 0.1, r"\\newcommand\{\\business@addressgap\}\{([0-9.]+)\}",
|
|
"the gap between the lockup and the address line"),
|
|
)
|
|
|
|
|
|
def read(path):
|
|
with open(path, encoding="utf-8") as handle:
|
|
return handle.read()
|
|
|
|
|
|
def first(pattern, text):
|
|
found = re.search(pattern, text)
|
|
return found.group(1) if found else None
|
|
|
|
|
|
def main():
|
|
check = Check("origin")
|
|
ours = read(SUITE) + read(IDENTITY)
|
|
|
|
# The factors of the family stand here as numbers, because they are what
|
|
# the origin writes into its own `\fpeval` calls and cannot be read out of
|
|
# it without parsing TeX. The heights are read out of the file itself.
|
|
for name, value, pattern, what in FACTORS:
|
|
mine = first(pattern, ours)
|
|
check.that(mine is not None, f"{name} is not declared in this suite")
|
|
check.that(mine is not None and abs(float(mine) - value) < 0.0001,
|
|
f"{what}: this suite says {mine}, the family {value}")
|
|
|
|
origin = support.run(["kpsewhich", "pacta.sty"]).stdout.strip()
|
|
if not origin or not os.path.exists(origin):
|
|
print(" pacta.sty is not installed; the heights were not compared")
|
|
return check.done()
|
|
theirs = read(origin)
|
|
for name, there, here, what in HEIGHTS:
|
|
want = first(there, theirs)
|
|
mine = first(here, ours)
|
|
check.that(want is not None, f"{name} was not found in {origin}")
|
|
check.that(mine is not None, f"{name} is not declared in this suite")
|
|
check.that(want is not None and mine is not None and want == mine,
|
|
f"{what}: this suite says {mine}, the origin {want}")
|
|
return check.done()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|