Skip to content

refactor: group lib the way the concepts group - #26

Merged
Halvanhelv merged 7 commits into
mainfrom
refactor/lib-layout
Sep 11, 2026
Merged

refactor: group lib the way the concepts group#26
Halvanhelv merged 7 commits into
mainfrom
refactor/lib-layout

Conversation

@Halvanhelv

Copy link
Copy Markdown
Owner

lib/translation_diff/ had thirty files at its top level, mixing the
pipeline's domain objects with cache stores, rate limiters and pieces of
configuration. ruby_llm, the architecture this project follows, uses one
rule without exception: a file names a concept, a directory of the same name
holds its implementations. Our providers/, segmenters/, languages/ and
translation/ already had that shape; the rest did not.

Behaviour is unchanged. No back-compatibility aliases — the gem is not
really released yet, so the old constants are simply gone.

was is
MemoryCacheStore, RedisCacheStore, ActiveRecordCacheStore Stores::Memory, Stores::Redis, Stores::ActiveRecord
RedisRateLimiter, ActiveRecordRateLimiter RateLimiters::Redis, RateLimiters::ActiveRecord
ActiveRecordSupport ActiveRecord::Support
CacheTtlOption, CacheGuardOptions under Configuration::

Class names now match the names they are registered as:
Stores.register(:redis, Stores::Redis). The registry names themselves —
:memory, :redis, :active_record, the six providers — are untouched,
since they are what applications actually configure.

The pipeline's domain objects stay at the top level. ruby_llm keeps its own
domain there for the same reason, and moving them would be rearranging for
its own sake.

The risk, which is the only interesting part

Stores::Redis shadows ::Redis and Stores::ActiveRecord shadows
::ActiveRecord for every constant lookup nested inside them: an unqualified
Redis::Namespace would resolve to the gem's own class and fail somewhere
unhelpful. Every reference to the real gems is ::-qualified, and every
class is declared in compact form (class TranslationDiff::Stores::Redis),
which keeps Module.nesting to one entry and makes the shadowing
structurally impossible rather than merely avoided.

That was verified where it can actually fail: against a real redis-server
and a real PostgreSQL, not the suite's fakes — every Redis test in this
project runs against a double, so a green suite proves nothing here.

Also

  • The error tree's base class had a file to itself for no reason but load
    order; it now lives with the rest.
  • One TranslationDiff::RateLimitExceeded. The two limiters used to
    raise two same-named classes under their own namespaces, so rescuing one
    and switching rate_limiter to the other quietly stopped catching it.

745 runs on SQLite, 753 against real PostgreSQL, rubocop clean. Cache keys
byte-identical to main, and nothing eager-loads: require "translation_diff"
still leaves ActiveRecord and Redis undefined with those gems stripped
from the load path.

MemoryCacheStore, RedisCacheStore and ActiveRecordCacheStore become
TranslationDiff::Stores::Memory/Redis/ActiveRecord, living beside the
Stores registry the way ruby_llm nests providers under Providers.
Stores.register(:redis, Stores::Redis) now reads the way it means.

Stores::Redis qualifies Redis::Namespace with :: since it now shares
a namespace with the class of the same name; also rewires
lib/translation_diff.rb's require order for the whole cache/limiter/
active_record/configuration reorganisation landing across this and
the next few commits.
RedisRateLimiter and ActiveRecordRateLimiter become
TranslationDiff::RateLimiters::Redis/ActiveRecord, matching Stores'
new shape and the registry name each is registered under.
ActiveRecordSupport becomes TranslationDiff::ActiveRecord::Support,
the mixin the cache store and rate limiter both include. Since
TranslationDiff::ActiveRecord now shares its name with ::ActiveRecord,
the two references it makes to the real gem across a genuinely
missing constant (ar_error?'s defined?/is_a? pair) are :: qualified;
the version floor check and the anonymous model's base class already
were.
CacheTtlOption and CacheGuardOptions become
TranslationDiff::Configuration::CacheTtlOption/CacheGuardOptions,
prepended pieces of Configuration rather than loose top-level
modules -- the same shape option_table.rb already had. Their
requires move inside Configuration's own class body, next to
option_table's, since the modules they define now nest under a
class that has to exist first.
…move

MemoryCacheStore, RedisCacheStore, ActiveRecordCacheStore,
RedisRateLimiter, ActiveRecordRateLimiter and ActiveRecordSupport are
gone; every mention across README, docs/ and the Gemfile's dependency
comments now names the class actually in lib/. Adds an Unreleased
CHANGELOG entry naming the renames, since the source now shows them
even though behaviour didn't change.
@Halvanhelv
Halvanhelv merged commit 778f282 into main Sep 11, 2026
5 checks passed
@Halvanhelv
Halvanhelv deleted the refactor/lib-layout branch September 11, 2026 06:53
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.

1 participant