From 38a6a0a745022ed7f0336f7deb121d75f589a916 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sun, 26 Apr 2026 18:32:02 -0500 Subject: refactor: extract wttrin--mode-line-extract-emoji helper The regex that pulls the emoji character out of a wttr.in mode-line response was inlined inside `wttrin--mode-line-update-display`, mixed in with the render logic. Six tests of the parser couldn't be written without invoking the whole render path. The new pure helper takes the weather string, runs the regex, and returns either the first non-whitespace character after the colon or "?" as a placeholder. The format-explanation comment that used to sit above the inline code is gone now that the same explanation lives in the helper's docstring. There's no risk of comment and code drifting apart. Six tests cover Normal (typical response, different emoji), Boundary (no whitespace after colon, multiple whitespace chars), and Error (no colon, empty string). --- tests/test-wttrin--mode-line-helpers.el | 40 +++++++++++++++++++++++++++++++++ wttrin.el | 14 ++++++++---- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/tests/test-wttrin--mode-line-helpers.el b/tests/test-wttrin--mode-line-helpers.el index 6eae822..408711b 100644 --- a/tests/test-wttrin--mode-line-helpers.el +++ b/tests/test-wttrin--mode-line-helpers.el @@ -171,5 +171,45 @@ distinguish a missing key from a present key bound to nil." "Nil cache-entry returns nil with no signal." (should-not (wttrin--mode-line-stale-p nil))) +;;; -------------------------------------------------------------------------- +;;; wttrin--mode-line-extract-emoji +;;; -------------------------------------------------------------------------- + +;;; Normal Cases + +(ert-deftest test-wttrin--mode-line-extract-emoji-normal-typical-response () + "Typical response \"Location: emoji rest\" returns the emoji." + (should (equal (wttrin--mode-line-extract-emoji "Paris: ☀ +72°F Clear") + "☀"))) + +(ert-deftest test-wttrin--mode-line-extract-emoji-normal-different-emoji () + "Different emoji is returned correctly (no hardcoded match)." + (should (equal (wttrin--mode-line-extract-emoji "London: ⛅ +15°C Cloudy") + "⛅"))) + +;;; Boundary Cases + +(ert-deftest test-wttrin--mode-line-extract-emoji-boundary-no-whitespace-after-colon () + "Colon with no whitespace before the emoji still extracts." + (should (equal (wttrin--mode-line-extract-emoji "X:Y rest") + "Y"))) + +(ert-deftest test-wttrin--mode-line-extract-emoji-boundary-multiple-whitespace () + "Multiple whitespace chars between colon and emoji are skipped." + (should (equal (wttrin--mode-line-extract-emoji "X: Z rest") + "Z"))) + +;;; Error Cases + +(ert-deftest test-wttrin--mode-line-extract-emoji-error-no-colon () + "String with no colon returns the placeholder \"?\"." + (should (equal (wttrin--mode-line-extract-emoji "no colon here") + "?"))) + +(ert-deftest test-wttrin--mode-line-extract-emoji-error-empty-string () + "Empty string returns the placeholder \"?\"." + (should (equal (wttrin--mode-line-extract-emoji "") + "?"))) + (provide 'test-wttrin--mode-line-helpers) ;;; test-wttrin--mode-line-helpers.el ends here diff --git a/wttrin.el b/wttrin.el index eb66868..b117bf3 100644 --- a/wttrin.el +++ b/wttrin.el @@ -676,6 +676,15 @@ On failure with no cache, shows error placeholder." ;; No cache at all — show error placeholder (wttrin--mode-line-update-placeholder-error)))))))) +(defun wttrin--mode-line-extract-emoji (weather-string) + "Extract the emoji character from WEATHER-STRING. +The expected format is \"Location: emoji temp conditions\". Returns +the first non-whitespace character after the colon, or \"?\" when +WEATHER-STRING contains no colon." + (if (string-match ":\\s-*\\(.\\)" weather-string) + (match-string 1 weather-string) + "?")) + (defun wttrin--mode-line-stale-p (cache-entry) "Return non-nil if CACHE-ENTRY is stale. Stale means age greater than 2 × `wttrin-mode-line-refresh-interval'. @@ -715,10 +724,7 @@ shows staleness info in tooltip." (let* ((weather-string (cdr wttrin--mode-line-cache)) (stale-p (wttrin--mode-line-stale-p wttrin--mode-line-cache))) (wttrin--debug-log "mode-line-display: Updating from cache, stale=%s" stale-p) - ;; Response format is "Location: ☀️ +72°F Clear" — grab first char after colon - (let ((emoji (if (string-match ":\\s-*\\(.\\)" weather-string) - (match-string 1 weather-string) - "?"))) + (let ((emoji (wttrin--mode-line-extract-emoji weather-string))) (wttrin--debug-log "mode-line-display: Extracted emoji = %S, stale = %s" emoji stale-p) (setq wttrin--mode-line-rendered-stale stale-p) -- cgit v1.2.3