// ZSH-GEM-COMPLETION — ENGINEERING REPORT

Full OMZ gem completion · live remote gem search for gem install · in-shell + on-disk dual-layer cache · list-grouped false zstyle pin · 3 publishing shortcuts

>_EXECUTIVE SUMMARY

zsh-gem-completion is a #compdef gem completion plugin that ships the entire OMZ gem-completion surface (30 subcommands — install, uninstall, update, list, build, cert, fetch, owner, push, yank, etc., all with man-page-quality descriptions) plus live remote package completion for gem install <TAB>. The remote dispatcher (__gem_search) shells out to gem search -q $PREFIX 2>/dev/null and parses two-column output (name version_string) into zsh's _describe format with descriptions rendered inline in the menu. Two layers of caching absorb network cost: an in-shell typeset array (__gems_${PREFIX}) for the rest of the shell session, and _retrieve_cache / _store_cache on disk for cross-session persistence. The plugin entrypoint also registers three publishing shortcuts (gemb build, gemp push, gemy yank-with-version) for the standard gem-author workflow. A single zstyle line (list-grouped false) tells zsh's menu to render each candidate on its own row instead of grouping by description — legibility win for the remote-search code path where descriptions are long and unique.

127
Total LOC (src + plugin)
30
gem Subcommands Completed
41
zunit @test Cases
21
Structural Gates (.sh)
7
zunit Files
3
Aliases (gemb/gemp/gemy)

~ARCHITECTURE · FILE STRUCTURE

Two files. _gem is the #compdef consumer that zsh's completion system autoloads; the plugin entrypoint wires src/ into fpath and adds the publishing aliases.

Path Lines Role
src/_gem115#compdef gem — 30-entry _1st_arguments subcommand table; __gem_installed queries gem list --local --no-versions; __gem_search + __gem_search_mem drive remote completion; per-subcommand case dispatch for install / list / uninstall / update / build
zsh-gem-completion.plugin.zsh12Three aliases (gemb=gem build *.gemspec, gemp=gem push *.gem, gemy=gem yank $1 -v $2 function); ZSH_ARGZERO self-locate; fpath=("${0:h}/src" $fpath)
Total source127Two files, one completion namespace

@COMPLETION COVERAGE

Full gem command surface, with the killer feature being live remote completion against rubygems.org for the install code path.

30 subcommands with descriptions

_1st_arguments hand-curates every gem(1) subcommand and its one-line description so the menu shows what each one does:

  • install/uninstall: install, uninstall, update, pristine, cleanup
  • query: list, search, query, specification, which, contents, dependency, outdated, stale
  • publish: build, push, yank, fetch, owner, mirror, cert, sources
  • server: server, generate_index, environment, rdoc
  • misc: check, help, lock, unpack

Live gem install completion (remote)

gem install <TAB>__gem_searchgem search -q $PREFIX → per-line parse (name version_string) → _describe -t remote-gem 'remote gems' tmp_ary. Names and versions are ${(q)...}-quoted so colons/spaces/special chars survive zsh's name:desc tuple format.

Installed-gem completion (local)

gem uninstall and gem update fall through to __gem_installed, which calls gem list --local --no-versions and feeds the result to _wanted installed_gems expl 'installed gems' compadd -a installed_gems. Cheap, no network, always current with the local install set.

gem build file completion

gem build <TAB>_files -g "*.gemspec". Glob-restricted to .gemspec files only, so gem build never offers random tarballs or directories.

Top-level flags

Before the subcommand state, _arguments -s offers -v/--version and -h/--help with mutex declarations ((-v --version)) so the menu doesn't double-list them.

Publishing aliases (3)

Workflow shortcuts that pre-fill the common arguments:

  • gembgem build *.gemspec (auto-glob current dir)
  • gempgem push *.gem (push freshly-built tarball)
  • gemy <name> <version>gem yank $1 -v $2 (function, not alias, so args order is enforced)

#TEST COVERAGE

41 zunit @test cases across 7 files, plus 21 structural shell gates from the umbrella.

Test file @test count What it pins
tests/t-plugin.zsh14Plugin-entrypoint surface — 3 aliases register, gemy defined as function (not alias) with positional args, fpath contains src/, _gem starts with #compdef gem
tests/t-contract.zsh3Entrypoint stem matches plugin-dir basename; src/_gem exists; #compdef gem first non-comment line
tests/t-contract2.zsh5ZSH_ARGZERO self-locate idiom intact; fpath manipulation uses "${0:h}/src" form
tests/t-contract3.zsh5Completion-function shape — __gem_search, __gem_search_mem, __gem_installed defined; cache-file name is gem_${PREFIX}_cache
tests/t-contract4.zsh5zstyle ':completion:*:*:gem:*:remote-gem' list-grouped false present (menu-rendering pin)
tests/t-aliases.zsh4Each of gemb / gemp resolves to documented expansion; gemy is a function with two positional args
tests/t-syntax.zsh5zsh -n on entrypoint + src/_gem + all helper scripts
Total417 zunit files

// STRUCTURAL GATES (21 shell scripts)

Same 21-script umbrella gate-set as the rest of the family: 9 docs/*.html gates (h1, body/html closing, final newline, no deprecated tags, https-only, no inline handlers, no placeholder hrefs, target-blank-rel-noopener) + 4 README + 3 man-page + 2 tests/ + 2 workflows + 1 cargo (vacuous).


?KEY DESIGN DECISIONS

Five places this plugin diverges from upstream OMZ and why.

Live remote completion for install

Upstream OMZ gem completion offers installed gems for install too — useless, because the gem you want to install is by definition not installed yet. This plugin shells out to gem search -q $PREFIX and offers the rubygems.org index. Cost is one rubygems network round-trip per prefix; absorbed by both cache layers after first hit.

Two-layer cache (in-shell + on-disk)

__gem_search_mem checks an in-shell typeset array (__gems_${PREFIX}) first — nanosecond hit. Misses fall through to _retrieve_cache for disk-backed persistence across shell sessions. Hits eventually fall through to gem search on network. Three tiers, latency growing by ~3 orders of magnitude each.

${(q)...} quoting on parsed output

Gem names + version strings can contain colons, spaces, parentheses (rspec-rails:7.0.0 (rspec-rails)-style descriptions). _describe's tag:description tuple format would mis-split on raw colons. ${(q)tag}:${(q)desc} backslash-quotes both halves so zsh parses them as a single tuple.

list-grouped false for remote-gem

Default zsh menu groups candidates by description — useful when many gems share a description, useless when every remote search hit has a unique version+description pair (which is the common case). The zstyle scope :completion:*:*:gem:*:remote-gem is tight enough that it only affects the remote-search code path; local gem list completion uses default grouping.

gemy as function, not alias

gemy <name> <version> needs the two args in a specific order (gem yank $1 -v $2). An alias couldn't enforce that — alias gemy='gem yank' would let users type gemy 0.0.0 some-gem and produce nonsense. The function form makes the contract typeable.