Skip to content

refactor!: drop six runtime dependencies - #5

Merged
Halvanhelv merged 1 commit into
mainfrom
refactor/drop-runtime-dependencies
Sep 7, 2026
Merged

Halvanhelv merged 1 commit into
mainfrom
refactor/drop-runtime-dependencies

Conversation

@Halvanhelv

Copy link
Copy Markdown
Owner

Summary

The gemspec declared eight runtime dependencies. Six of them are never loaded by this gem. After this change it loads two: ox and punkt-segmenter.

That is what the README promised all along — "This dependencies are not included, as you might need to roll your own cache based on different store" — the gemspec just never agreed with it.

What was actually used

gem where its constant appears in lib/ verdict
ox Ox::Sax, Ox.sax_parse in the tokenizer kept
punkt-segmenter Punkt::SentenceTokenizer in the tokenizer kept
dry-initializer five extend lines dropped
connection_pool nowhere — the pool is duck typed on #with dropped
redis nowhere — bare Redis is never named dropped
deepl-rb nowhere — require "deepl" at load, constant unused dropped
redis-namespace inside one method body of RedisCacheStore dropped
ratelimit inside one method body of RedisRateLimiter dropped

The last two already resolved lazily: they are named inside method bodies, so the gem loaded fine without them and only broke if you actually used those classes. Declaring them as hard runtime dependencies forced them on everyone who used their own cache store.

dry-initializer → plain Ruby

Dry::Initializer generated private readers, so replacing them with a private attr_reader keeps the public API byte-for-byte identical:

# before
extend Dry::Initializer
param :values
option :limit, default: proc { MAX_CHUNK_SIZE }

# after
def initialize(values, limit: MAX_CHUNK_SIZE, count_limit: COUNT_LIMIT)
  @values = values
  @limit = limit
  @count_limit = count_limit
end

private

attr_reader :values, :limit, :count_limit

Bug fixed on the way

RedisRateLimiter declared threshold and interval as positional params, so the keyword call the README documents silently discarded them:

RedisRateLimiter.new(pool, threshold: 999, interval: 7)
#=> threshold 8000, interval 60

They are keywords now, matching RedisCacheStore. There is a regression test.

Tests

Both Redis wrappers had no tests at all. They have them now — 6 new cases. The stand-ins they use for Redis::Namespace, Ratelimit and the connection pool double as an executable statement of the duck types this gem expects.

Coverage: 94.68% → 97.57% (282/289).

Breaking changes → 2.0.0

  • Applications relying on this gem to install the DeepL client, redis, redis-namespace, connection_pool or ratelimit must depend on them directly. The README now says so explicitly and its example requires deepl.
  • Callers passing threshold/interval to RedisRateLimiter positionally must switch to keywords.

Test plan

  • bundle exec rake test — 34 runs, 44 assertions, 0 failures, on Ruby 4.0.5 and 3.2.4.
  • bundle exec rubocop — 0 offenses.
  • Gemfile.lock re-resolved: zero matches for dry-initializer, deepl-rb, redis, connection_pool, ratelimit. With none of them installed, require "deepl_diff" loads and DeepLDiff::Tokenizer.tokenize("<b>hi</b>") returns the expected tokens.

https://claude.ai/code/session_01Pda49PcgziFVnibkKKjXRE

The gemspec declared eight runtime dependencies. Six of them were never
loaded by this gem:

  * dry-initializer, used for five initializers that plain Ruby writes
    just as short. Its readers were private, so replacing them with
    private attr_readers leaves the public API untouched.
  * connection_pool and redis, whose constants appear nowhere in lib/.
    The pool is duck typed on #with, and Redis::Namespace comes from
    redis-namespace.
  * deepl-rb, required at load time but never referenced. The API object
    is supplied by the application through DeepLDiff.api.
  * redis-namespace and ratelimit, named only inside method bodies of
    the two optional Redis wrappers, so they already resolved lazily.

Only ox and punkt-segmenter remain, which is what the README promised
all along: "This dependencies are not included, as you might need to
roll your own cache based on different store."

Fix RedisRateLimiter while here. threshold and interval were positional
params, so the keyword call the README documents silently fell back to
8000 and 60. They are keywords now, matching RedisCacheStore.

Cover both Redis wrappers, which had no tests at all. The stand-ins they
use for Redis::Namespace, Ratelimit and the connection pool double as an
executable statement of the duck types this gem expects.

BREAKING CHANGE: applications that relied on this gem to install the
DeepL client, redis, redis-namespace, connection_pool or ratelimit must
now depend on them directly. Callers passing threshold and interval to
RedisRateLimiter positionally must switch to keywords.
@Halvanhelv
Halvanhelv merged commit dc60264 into main Sep 7, 2026
5 checks passed
@Halvanhelv
Halvanhelv deleted the refactor/drop-runtime-dependencies branch September 7, 2026 15:04
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