Skip to content

refactor: expose Character.slugify/1 and Expression.parse_ref/1, delete copies#151

Merged
QMalcolm merged 1 commit into
mainfrom
qmalcolm--refactor-expose-slugify-parse-ref
Jul 19, 2026
Merged

refactor: expose Character.slugify/1 and Expression.parse_ref/1, delete copies#151
QMalcolm merged 1 commit into
mainfrom
qmalcolm--refactor-expose-slugify-parse-ref

Conversation

@QMalcolm

@QMalcolm QMalcolm commented Jul 19, 2026

Copy link
Copy Markdown
Collaborator

Closes #124

What

  • Character.slugify/1 is now public with doctests, documented as the single definition of the slug rules. The server's byte-for-byte slugify_name copy is deleted — previously, if the library's slug rules changed, characters created via build_start would become unfindable.
  • Expression.parse_ref/1 parses a whole-string single node ref, returning {:ok, {type, id, field}} | :error. Loader.parse_effect and the server's parse_effect_target! both use it; the server's @effect_target_regex is deleted. The anchored/leading variants Expression needs internally are derived from @ref_pattern via Regex.source at compile time — the pattern literal now exists exactly once in the codebase.

Behavior note

parse_ref is anchored, so Loader.parse_effect no longer prefix-matches targets with trailing content: target = "ability('dexterity').total_score + 1" previously matched the leading ref and silently discarded the + 1; it now warns and skips the effect, consistent with #149's unparseable-target handling. Covered in the (now table-driven) malformed-contributes loader test.

Verification

  • New doctests for parse_ref (valid ref, missing quotes, trailing content) and slugify.
  • dnd_5e_srd still loads with zero warnings (all its targets are exact refs).
  • Full suite (313 + 55), credo, dialyzer, CodeScene delta all pass.

Summary by Bito

  • Centralized character name slugification logic into `ExTTRPGDev.Characters.Character.slugify/1`.
  • Added `ExTTRPGDev.RuleSystem.Expression.parse_ref/1` to strictly validate and parse node references.
  • Refactored `RuleSystem.Loader` and `CLI.Server` to use the new `parse_ref/1` function for consistent target parsing.
  • Updated `LoaderTest` to include more comprehensive test cases for malformed contributes entries.

…te copies

Two pieces of library knowledge were copy-pasted into the server and
would silently drift:

- slugify_name in server.ex was byte-for-byte the private slugify in
  Character. If the library's slug rules ever changed, characters
  created via build_start would be saved under slugs the library can
  no longer derive from their names. Character.slugify/1 is now public
  and documented as the single definition; the server copy is deleted.

- The node-ref regex existed three times: Expression.@ref_pattern,
  a copy in Loader.parse_effect, and an anchored variant in
  server.ex's parse_effect_target!. Expression.parse_ref/1 now parses
  a whole-string single ref, and both call sites use it. The anchored
  and leading variants used internally are derived from @ref_pattern
  via Regex.source at compile time, so the pattern literal exists
  exactly once in the codebase.

Behavior note: parse_ref is anchored, so Loader.parse_effect no longer
prefix-matches a target with trailing content ("...total_score + 1"
previously matched the leading ref and silently ignored the rest); it
now warns and skips the effect, consistent with the other unparseable-
target handling from #149. The malformed-contributes loader tests are
consolidated into one table-driven test covering all three cases.

Closes #124
@QMalcolm
QMalcolm merged commit 086c30f into main Jul 19, 2026
5 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor: expose Character.slugify/1 and Expression.parse_ref/1, delete duplicated copies

1 participant