diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-23 23:01:02 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-23 23:01:02 +0200 |
| commit | 2b1f044aa59d516d2e3497066751d3baa5b1c749 (patch) | |
| tree | 2737e0729e30c803c0dc8c62acff2d4704dc5853 | |
| parent | 55b5f40cc1f2d42bc3a277f60a3798742ce29170 (diff) | |
Refactor calculator.Parse to use registration pattern for parsing strategies
Created ParsingStrategy type and strategyRegistry struct to manage parsing strategies.
All parsing strategies are now registered in a registry and executed in sequence.
This makes the parsing logic more maintainable and extensible.
| -rw-r--r-- | internal/calculator/calculator.go | 54 |
1 files changed, 43 insertions, 11 deletions
diff --git a/internal/calculator/calculator.go b/internal/calculator/calculator.go index edf529f..f3ebc17 100644 --- a/internal/calculator/calculator.go +++ b/internal/calculator/calculator.go @@ -9,6 +9,36 @@ import ( "codeberg.org/snonux/perc/internal/rpn" ) +// ParsingStrategy represents a parsing function that attempts to parse input. +type ParsingStrategy func(input string) (result string, handled bool) + +// strategyRegistry maintains a registry of parsing strategies. +type strategyRegistry struct { + strategies []ParsingStrategy +} + +// newStrategyRegistry creates a new strategy registry. +func newStrategyRegistry() *strategyRegistry { + return &strategyRegistry{ + strategies: make([]ParsingStrategy, 0), + } +} + +// register adds a parsing strategy to the registry. +func (r *strategyRegistry) register(strategy ParsingStrategy) { + r.strategies = append(r.strategies, strategy) +} + +// parse attempts to parse input using registered strategies in order. +func (r *strategyRegistry) parse(input string) (string, bool) { + for _, strategy := range r.strategies { + if result, handled := strategy(input); handled { + return result, true + } + } + return "", false +} + // Parse parses a percentage calculation input string and returns the result. // It handles formats like "20% of 150", "30 is what % of 150", and "30 is 20% of what". func Parse(input string) (string, error) { @@ -16,25 +46,27 @@ func Parse(input string) (string, error) { input = strings.ReplaceAll(input, "what is ", "") input = strings.TrimSpace(input) - if result, ok := parseXPercentOfY(input); ok { - return result, nil - } + // Create registry and register parsing strategies + registry := newStrategyRegistry() + registry.register(parseXPercentOfY) + registry.register(parseXIsWhatPercentOfY) + registry.register(parseXIsYPercentOfWhat) + registry.register(parseRPNFallback) - if result, ok := parseXIsWhatPercentOfY(input); ok { + if result, ok := registry.parse(input); ok { return result, nil } - if result, ok := parseXIsYPercentOfWhat(input); ok { - return result, nil - } + return "", fmt.Errorf("calculator: unable to parse input %q. See usage for examples", input) +} - // Try RPN as a fallback +// parseRPNFallback is a parsing strategy that delegates to ParseRPN. +func parseRPNFallback(input string) (string, bool) { result, err := ParseRPN(input) if err == nil { - return result, nil + return result, true } - - return "", fmt.Errorf("calculator: unable to parse input %q. See usage for examples", input) + return "", false } // ParseRPN parses and evaluates an RPN (Reverse Polish Notation) expression. |
