diff options
| author | Paul Buetow <paul@buetow.org> | 2026-04-06 11:12:03 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-04-06 11:12:03 +0300 |
| commit | 616beecc41b573503dad9f5bfd9f353c6f826a8a (patch) | |
| tree | 3189ae3f048dfc4e8ff79b83caab8ea43c2d7492 /internal/processor | |
| parent | 05f54cc0cb8cf3535698ab5027d200842bdb28e3 (diff) | |
refactor: extract shared CardStore into internal/store to eliminate duplication
FindCardDirectory, FindOrCreateCardDirectory, GenerateCardID and the
ScanWords helper previously existed in both internal/utils.go (as
standalone functions) and were partially duplicated in
internal/gui/card_service.go (readWordFromDir, ScanExistingWords).
Introduce internal/store.CardStore as the single source of truth for
all on-disk card-directory operations. Both internal/processor and
internal/gui now hold a *store.CardStore field and delegate to it,
removing the last copy of the directory-scanning loop from
card_service.go. internal/utils.go keeps thin forwarding wrappers for
callers that import the root internal package.
Also adds table-driven unit tests for the new package covering
FindCardDirectory (including legacy _word.txt fallback),
FindOrCreateCardDirectory, and CardStore.ScanWords.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/processor')
| -rw-r--r-- | internal/processor/card_store.go | 23 | ||||
| -rw-r--r-- | internal/processor/processor.go | 9 |
2 files changed, 21 insertions, 11 deletions
diff --git a/internal/processor/card_store.go b/internal/processor/card_store.go index 1020998..25b4e36 100644 --- a/internal/processor/card_store.go +++ b/internal/processor/card_store.go @@ -1,14 +1,14 @@ package processor // CardStore manages the on-disk layout of word card directories. -// It wraps the low-level internal.FindCardDirectory / -// internal.FindOrCreateCardDirectory helpers and adds the higher-level -// isWordFullyProcessed check used by the batch processor to skip words that -// have already been completely generated. +// It delegates to the shared store.CardStore (internal/store) for all +// directory-discovery and creation logic, so those algorithms live in exactly +// one place (DRY). The methods here add the higher-level isWordFullyProcessed +// check that is specific to the batch processor. // -// All methods are on *Processor rather than a separate struct to avoid an -// extra layer of indirection while still keeping the concerns separated into -// their own file (SRP at the file level, as recommended for Go packages). +// All methods are on *Processor rather than a separate struct to keep the +// existing call sites unchanged while still separating concerns at the file +// level (SRP at the file level, as recommended for Go packages). import ( "os" @@ -21,16 +21,17 @@ import ( ) // findOrCreateWordDirectory returns the existing card directory for word -// inside the configured output directory, creating it when absent. +// inside the configured output directory, creating it when absent. Delegates +// to the shared CardStore so the directory-creation algorithm is not duplicated. func (p *Processor) findOrCreateWordDirectory(word string) string { - return internal.FindOrCreateCardDirectory(p.flags.OutputDir, word) + return p.cardStore.FindOrCreateCardDirectory(word) } // findCardDirectory searches the configured output directory for an existing // card directory that contains the given word. Returns an empty string when -// no matching directory is found. +// no matching directory is found. Delegates to the shared CardStore. func (p *Processor) findCardDirectory(word string) string { - return internal.FindCardDirectory(p.flags.OutputDir, word) + return p.cardStore.FindCardDirectory(word) } // isWordFullyProcessed returns true when the word's card directory already diff --git a/internal/processor/processor.go b/internal/processor/processor.go index 14e5341..323df23 100644 --- a/internal/processor/processor.go +++ b/internal/processor/processor.go @@ -17,6 +17,7 @@ import ( "codeberg.org/snonux/totalrecall/internal/gui" "codeberg.org/snonux/totalrecall/internal/image" "codeberg.org/snonux/totalrecall/internal/phonetic" + "codeberg.org/snonux/totalrecall/internal/store" "codeberg.org/snonux/totalrecall/internal/translation" ) @@ -77,6 +78,11 @@ type Processor struct { // so individual methods never call Viper directly. cfg *Config + // cardStore is the shared CardStore for locating and creating on-disk + // card directories. It is initialised from flags.OutputDir in NewProcessor + // and used by all card_store.go helpers. + cardStore *store.CardStore + // imageFactories groups the two image-provider construction functions. // Production code uses image.DefaultClientFactories(); tests replace fields. imageFactories image.ClientFactories @@ -103,6 +109,9 @@ func NewProcessor(flags *cli.Flags, cfg *Config) *Processor { translationCache: translation.NewTranslationCache(), phoneticFetcher: phonetic.NewFetcher(&phonetic.Config{Provider: phoneticProvider, OpenAIKey: openAIKey, GoogleAPIKey: googleAPIKey}), randomIntn: rand.Intn, + // cardStore is rooted at the output directory so card-discovery helpers + // never need to know about flags directly. + cardStore: store.New(flags.OutputDir), imageFactories: image.DefaultClientFactories(), newAudioProvider: audio.NewProvider, } |
