Skip to content

DOC-6967 Add Ruby (redis-rb) hash field expiration examples - #3808

Merged
andy-stark-redis merged 1 commit into
mainfrom
DOC-6967-ruby-hash-field-expiration
Aug 13, 2026
Merged

DOC-6967 Add Ruby (redis-rb) hash field expiration examples#3808
andy-stark-redis merged 1 commit into
mainfrom
DOC-6967-ruby-hash-field-expiration

Conversation

@andy-stark-redis

@andy-stark-redis andy-stark-redis commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

DOC-6967 — Ruby (redis-rb) hash field expiration examples

Adds a Ruby tab to two of the three hash field expiration examples on
content/develop/data-types/hashes.md:

  • hexpire — set a TTL in seconds on two fields with hexpire, read it back with httl
  • hpexpire — set a TTL in milliseconds with hpexpire, read it back with hpttl

Both steps go into the existing local_examples/ruby/dt_hash.rb (which previously stopped
after incrby_get_mget), and each self-resets with r.del + r.hset so it stands alone.

Why now — the exclusion was already stale

These three steps carry a lang_filter allowlist of ten clients that omits Ruby. That was
correct when authored under DOC-6887: the released gem was 5.4.1, which had no
hash-field-expiration methods at all, so hexpire fell through method_missing and omitted
the required FIELDS keyword.

But gem 6.0.0 (published 2026-07-31) ships hexpire, httl,
hpexpire(key, ttl, *fields, nx:/xx:/gt:/lt:) and hpttl — verified by reading
lib/redis/commands/hashes.rb at tag v6.0.0, not inferred from release notes. Nothing
re-checked the premise, so the tab stayed suppressed after the reason for it expired. A
lang_filter exclusion encodes a release-time gap and rots silently, because a missing tab
looks identical whether a client can't do something or merely couldn't yet.

Surfaced by the daily upstream PR scan of Thu 13 Aug 2026 while chasing
redis-rb#1374.

Also: two lang_filter allowlists removed

With Ruby added, the hexpire and hpexpire allowlists named all 11 clients in the set,
making them no-ops. Both are removed, which is a net simplification of the page source.

Verified rather than assumed — two isolated builds (hugo -d <dir>, not touching public/)
with the filters present vs removed:

Output Difference
index.html identical apart from whitespace and one nanotime element id
index.json 0 diff lines
index.html.md 0 diff lines

Tab order is unchanged because it comes from config.toml, not the filter — lang_filter has
exactly one consumer, clients-example.html:45,
which sets the tab-selector scratch var and nothing else.

The hexpireat allowlist stays, and is load-bearing. Ruby is the only client without that
step, and hexpireat/hpexpireat/hexpiretime/hpexpiretime are absent from released gem
6.0.0 (they're in the still-open redis-rb#1374). Removing that filter would not hide Ruby's
tab — it would render Ruby's entire file into the page via the legacy fallback.

Verification

Layer Status How
Method names, arity, keywords run-verified build/example-test-harness/run.sh hash_tutorial rubyPASS, against Redis 8.8.0 and the released gem 6.0.0
Wire serialization confirmed twice A stubbed replay predicted HEXPIRE … FIELDS 2 air_quality battery_level; a live server then echoed the identical arg list back
Expected-output comments observed [1, 1], [60, 60], [1], [59999] — all four printed by the real run
Signatures vs API mapping data/command-api-mapping/{HEXPIRE,HTTL,HPEXPIRE,HPTTL}.json, key redis_rb, agree with the gem source
Rendered page Built HTML checked: Ruby on 6 of 7 blocks, 11 tabs on both new steps, 10 on hexpireat, no REMOVE/HIDE scaffolding in either pane
Independent review Codex review — verdict: pass, no findings (after one medium finding was fixed, see below)

One comment was wrong before the run and would not have been caught by inspection: hpttl's
expected value was inherited from the Python tab as 59994, where Ruby actually returns
59999. Copying an expected value from a sibling tab is not verification of this one, even
when the wire format is identical. It now carries an observed value, and keeps its
"may vary" caveat because consecutive runs gave 59999 and 59998.

The Codex review's one finding was that the new output comments omitted the >>> marker. I'd
used plain comments to match this file's other four steps, but the check went against me: the
same set's other legacy-layout files (local_examples/php/DtHashTest.php,
local_examples/rust-async/dt-hash.rs) use >>> in every step, so the dt_*.rb family is
the outlier — and a reader compares tabs within one step block far more readily than steps
within one tab. Fixed; re-review came back clean.

Out of scope, deliberately

  • The hexpireat step. Blocked on redis-rb#1374, which is open and not yet on master
    either
    hashes.rb at master is byte-identical to v6.0.0. Revisit when it ships in a
    released gem.
  • data/command-api-mapping/ entries. Already present for redis_rb; nothing to add.
  • Output-comment style in the other four steps. This file is now internally mixed (two
    steps with >>>, four without), as are its six sibling dt_*.rb files. Normalizing all
    seven is mechanical but reader-visible, so it belongs in its own change.

⚠️ Pre-existing bug found while doing this — not fixed here

incrby_get_mget has no lang_filter, and node-redis has no incrby_get_mget step. So
that tab is hitting the whole-file fallback on the published page right now: the Node.js pane
renders the complete dt-hash.js, import lines and all, instead of the counter example.
Confirmed in the built HTML (data-legacy-src on that pane, body starting at import).

Two non-equivalent fixes — adding the step to the node-redis example (better; the other ten
clients all have it) or adding a lang_filter excluding Node.js (one line, but leaves a
coverage gap). Being tracked separately, along with whether other pages share the shape.

🤖 Generated with Claude Code


Note

Low Risk
Documentation and example-harness only; no runtime product or security-sensitive code changes.

Overview
Adds Ruby (redis-rb) runnable steps for hash field expiration on the hashes data-type page: hexpire/httl (second TTL) and hpexpire/hpttl (millisecond TTL), with self-contained sensor:sensor1 setup and harness assertions in local_examples/ruby/dt_hash.rb.

On hashes.md, removes the lang_filter allowlists from the hexpire and hpexpire clients-example blocks so Ruby appears in those tabs now that redis-rb 6.0.0 supports the APIs. The hexpireat block keeps its filter (Ruby still lacks those commands).

Reviewed by Cursor Bugbot for commit b3be4d3. Bugbot is set up for automated code reviews on this repo. Configure here.

Adds hexpire/httl and hpexpire/hpttl steps to the Ruby tab of the hash
field expiration examples, and drops the two lang_filter allowlists that
were keeping Ruby out.

The interesting part is why this was possible at all. Those allowlists
were not documenting an unsupported client — they encoded a gap in the
*released* gem at the time the steps were authored (5.4.1 had no
hash-field-expiration methods, so hexpire fell through method_missing).
Gem 6.0.0 shipped hexpire/httl/hpexpire/hpttl on 2026-07-31 and nothing
re-checked the premise, so the tab stayed suppressed for weeks after the
reason expired. Nothing in the build flags this: a missing tab looks
identical whether the client cannot do it or merely could not yet.

Two things the run caught that inspection did not. A stubbed replay
against the real gem confirmed arity and wire bytes, but the hpttl
comment was inherited from the Python tab and said 59994 where Ruby
actually returns 59999 — copying an expected value from a sibling tab is
not verification of this one, even when the wire format is identical.
And a hand-rolled detector for whole-file fallback panes reported none
anywhere because an optional regex group always matched empty; the one
real instance had already been seen by eye, which is the only reason the
false negative surfaced.

The output comments use the >>> marker rather than this file's own plain
style. The sibling legacy-layout files for the same set (predis, rust)
use >>> in every step, so the Ruby dt_*.rb family is the outlier, and a
reader compares tabs within one step block far more readily than steps
within one tab.

Learned: a lang_filter exclusion encodes a release-time client gap and rots silently once the client catches up
Constraint: the hexpireat step's lang_filter must keep excluding Ruby — a client whose file lacks the requested step renders its WHOLE file, not a skipped tab
Rejected: plain "# value" output comments matching this file's other four steps | the same set's other legacy-layout files all use "# >>>", and cross-tab consistency within a step beats in-file consistency across steps
Directive: never drop a lang_filter to expose a tab without first confirming every client in the set has that step — incrby_get_mget on this page is already failing that way, rendering the whole node-redis file because it has no such step
Recheck: add Ruby to the hexpireat step's lang_filter when redis-rb#1374 (hexpireat/hpexpireat/hexpiretime/hpexpiretime) ships in a released gem
Gaps: the four pre-existing steps in this file still use plain output comments, so the file is now internally mixed; the six sibling dt_*.rb files are untouched
Ticket: DOC-6967
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

DOC-6967

@github-actions

Copy link
Copy Markdown
Contributor

@github-actions

Copy link
Copy Markdown
Contributor

🧠 Redis Memory

Found 5 related items from repository history (5 new this commit):

Memory updated at b3be4d3

@dwdougherty dwdougherty left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@andy-stark-redis
andy-stark-redis merged commit 44fe24c into main Aug 13, 2026
91 checks passed
@andy-stark-redis
andy-stark-redis deleted the DOC-6967-ruby-hash-field-expiration branch August 13, 2026 14:00
@andy-stark-redis

Copy link
Copy Markdown
Contributor Author

Thanks @dwdougherty !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clients Client library docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants