From a0da020a99a9ded8c7f4f79aebb689ee300c769d Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sat, 23 May 2026 22:11:02 +0300 Subject: refactor: fix parseCategory OCP violation with range-based iteration Replace the switch/case in parseCategory() with range-based iteration over all Category constants (Universal through _sentinel). This achieves true OCP compliance: adding a new Category constant before _sentinel automatically makes it available in parseCategory without modifying the function. Added _sentinel constant as the upper bound for range-based iteration, with a comment explaining how to add new categories correctly. --- internal/rpn/metric_type.go | 4 ++++ internal/rpn/operations_metric_cmd.go | 27 ++++++++------------------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/internal/rpn/metric_type.go b/internal/rpn/metric_type.go index b9a9514..1a9c9f5 100644 --- a/internal/rpn/metric_type.go +++ b/internal/rpn/metric_type.go @@ -25,6 +25,10 @@ const ( Distance // Custom is for user-defined units. Custom + // _sentinel marks the upper bound for range-based Category iteration. + // Adding a new Category: insert before _sentinel, and it will be + // automatically picked up by parseCategory() and other range-based lookups. + _sentinel ) // String returns the human-readable name of the category. diff --git a/internal/rpn/operations_metric_cmd.go b/internal/rpn/operations_metric_cmd.go index b8daa1a..868c92a 100644 --- a/internal/rpn/operations_metric_cmd.go +++ b/internal/rpn/operations_metric_cmd.go @@ -81,27 +81,16 @@ func (o *Operations) MetricCompatible(stack *Stack) (string, error) { } // parseCategory converts a category name string to a Category constant. +// Iterates over all valid Category values using range, so adding a new +// Category constant (between Universal and _sentinel) automatically makes +// it available here without modifying this function (OCP compliance). func parseCategory(name string) (Category, bool) { - switch name { - case "Universal": - return Universal, true - case "DataRate": - return DataRate, true - case "DataSize": - return DataSize, true - case "Time": - return Time, true - case "Weight": - return Weight, true - case "Speed": - return Speed, true - case "Distance": - return Distance, true - case "Custom": - return Custom, true - default: - return 0, false + for cat := Category(0); cat <= _sentinel; cat++ { + if cat.String() == name { + return cat, true + } } + return 0, false } // CustomList returns all custom metric names. -- cgit v1.2.3