From b69c2e83d9290225f64e38ea8175a821a4c4f91f Mon Sep 17 00:00:00 2001 From: Jared Miller Date: Sun, 15 Feb 2026 09:45:17 -0500 Subject: [PATCH] Add HelpTopic dataclass and TOML loader --- src/mudlib/content.py | 40 ++++++++++++++++++++ tests/test_help_topics.py | 79 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 tests/test_help_topics.py diff --git a/src/mudlib/content.py b/src/mudlib/content.py index 85c108e..98a8297 100644 --- a/src/mudlib/content.py +++ b/src/mudlib/content.py @@ -3,6 +3,7 @@ import importlib import logging import tomllib +from dataclasses import dataclass from pathlib import Path from typing import cast @@ -139,3 +140,42 @@ def load_commands(directory: Path) -> list[CommandDefinition]: log.warning("failed to load command from %s: %s", path, e) return commands + + +@dataclass +class HelpTopic: + """A help topic loaded from a TOML file.""" + + name: str + body: str + title: str = "" + admin: bool = False + + def __post_init__(self): + if not self.title: + self.title = self.name + + +def load_help_topic(path: Path) -> HelpTopic: + """Load a single help topic from a TOML file.""" + with open(path, "rb") as f: + data = tomllib.load(f) + + return HelpTopic( + name=data["name"], + body=data["body"].strip(), + title=data.get("title", ""), + admin=data.get("admin", False), + ) + + +def load_help_topics(directory: Path) -> dict[str, HelpTopic]: + """Load all help topics from a directory of TOML files.""" + topics: dict[str, HelpTopic] = {} + for path in directory.glob("*.toml"): + try: + topic = load_help_topic(path) + topics[topic.name] = topic + except Exception as e: + log.warning("failed to load help topic from %s: %s", path, e) + return topics diff --git a/tests/test_help_topics.py b/tests/test_help_topics.py new file mode 100644 index 0000000..b939cce --- /dev/null +++ b/tests/test_help_topics.py @@ -0,0 +1,79 @@ +"""Tests for TOML help topic loading.""" + +import textwrap + +import pytest + +from mudlib.content import load_help_topics + + +@pytest.fixture +def help_dir(tmp_path): + """Create a temp directory with sample help TOML files.""" + topic = tmp_path / "combat.toml" + topic.write_text( + textwrap.dedent("""\ + name = "combat" + title = "combat primer" + body = \"\"\" + combat is initiated when you attack another entity. + use skills to learn your available moves. + \"\"\" + """) + ) + + admin_topic = tmp_path / "building.toml" + admin_topic.write_text( + textwrap.dedent("""\ + name = "building" + title = "builder's guide" + admin = true + body = \"\"\" + use @dig to create zones and @paint to edit terrain. + \"\"\" + """) + ) + return tmp_path + + +def test_load_help_topics(help_dir): + topics = load_help_topics(help_dir) + assert "combat" in topics + assert "building" in topics + + +def test_help_topic_fields(help_dir): + topics = load_help_topics(help_dir) + combat = topics["combat"] + assert combat.name == "combat" + assert combat.title == "combat primer" + assert combat.admin is False + assert "combat is initiated" in combat.body + + +def test_help_topic_admin_flag(help_dir): + topics = load_help_topics(help_dir) + building = topics["building"] + assert building.admin is True + + +def test_help_topic_title_defaults_to_name(tmp_path): + topic = tmp_path / "simple.toml" + topic.write_text('name = "simple"\nbody = "just a test"\n') + topics = load_help_topics(tmp_path) + assert topics["simple"].title == "simple" + + +def test_load_help_topics_empty_dir(tmp_path): + topics = load_help_topics(tmp_path) + assert topics == {} + + +def test_load_help_topics_skips_bad_files(tmp_path): + bad = tmp_path / "broken.toml" + bad.write_text("not valid toml [[[") + good = tmp_path / "good.toml" + good.write_text('name = "good"\nbody = "works"\n') + topics = load_help_topics(tmp_path) + assert "good" in topics + assert "broken" not in topics