Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions aastex/_aastex.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,39 @@ def affiliations(self) -> list[Affiliation]:

@dataclasses.dataclass
class Acronym(pylatex.base_classes.LatexObject):
r"""
An acronym which is expanded on first use and abbreviated thereafter.

Defining an acronym also defines LaTeX commands for using it:
``\NASA`` expands it on first use and abbreviates it afterwards, and
``\NASACapital`` does the same with the first letter capitalized, for a
sentence which begins with the acronym.
The capitalized form matters for an instrument whose name reads as
``"the Multi-slit Solar Explorer"``, since a sentence should open with
"The" rather than "the".
``\NASAs`` and ``\NASACapitals`` are the plural forms, and ``\NASAShort``
is the abbreviation whether or not it has been used before.
"""

acronym: str
"""The abbreviated form of this acronym."""

name_full: str
"""
The expanded form of this acronym.

Include a leading article, as in ``"the Multi-slit Solar Explorer"``,
for a name which needs one.
"""

name_short: None | str = None
"""The abbreviation to display, if it differs from :attr:`acronym`."""

plural: bool = False
"""Whether to define the plural forms of this acronym."""

short: bool = False
"""Whether to define a command which always gives the abbreviation."""

def __post_init__(self):
self.packages.append(pylatex.Package("acronym"))
Expand Down Expand Up @@ -187,6 +215,21 @@ def dumps(self):
pylatex.NoEscape(rf"\acs{{{self.acronym}}}"),
],
).dumps()
command += pylatex.Command(
command="newcommand",
arguments=[
pylatex.NoEscape(rf"\{self.acronym}Capital"),
pylatex.NoEscape(rf"\Ac{{{self.acronym}}}"),
],
).dumps()
if self.plural:
command += pylatex.Command(
command="newcommand",
arguments=[
pylatex.NoEscape(rf"\{self.acronym}Capitals"),
pylatex.NoEscape(rf"\Acp{{{self.acronym}}}"),
],
).dumps()
return command


Expand Down
46 changes: 46 additions & 0 deletions aastex/_tests/test_aastex.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,52 @@ def test_short(self, a: aastex.Acronym):
def test_dumps(self, a: aastex.Title):
assert isinstance(a.dumps(), str)

def test_capital(self, a: aastex.Acronym):
"""A capitalized command is defined for a sentence starting with the acronym."""
dumps = a.dumps()
assert rf"\{a.acronym}Capital" in dumps
assert rf"\Ac{{{a.acronym}}}" in dumps
if a.plural:
assert rf"\{a.acronym}Capitals" in dumps
assert rf"\Acp{{{a.acronym}}}" in dumps


@pytest.mark.skipif(
shutil.which("latexmk") is None,
reason="requires a LaTeX installation",
)
def test_acronym_capital_compiles(tmp_path: pathlib.Path):
"""
The capitalized command raises the article of a name which carries one.

An instrument named "the Multi-slit Solar Explorer" should open a sentence
with "The", which is what the underlying `acronym` package provides.
"""
doc = aastex.Document(document_options="twocolumn", linenumbers=False)
doc.preamble.append(aastex.Acronym("MUSE", "the Multi-slit Solar Explorer"))
doc.append(aastex.Title("Acronyms"))
doc += [
aastex.Author(
name="Jane Doe",
affiliation=aastex.Affiliation("Fancy University"),
)
]
section = aastex.Section("Introduction")
section.append(pylatex.NoEscape(r"\MUSECapital\ observes the Sun. \MUSE\ again."))
doc.append(section)

path = tmp_path / "acronyms"
doc.generate_pdf(path, clean_tex=False)

text = subprocess.run(
args=["pdftotext", str(path.with_suffix(".pdf")), "-"],
capture_output=True,
text=True,
).stdout

assert "The Multi-slit Solar Explorer (MUSE)" in text
assert "MUSE again" in text


@pytest.mark.parametrize(
argnames="a",
Expand Down
Loading