go-ruby-did-you-mean

Ruby's did_you_mean matcher in pure Go — Jaro–Winkler & Levenshtein spelling suggestions, MRI byte-exact, no cgo.

pure Go · zero cgo did_you_mean-compatible SpellChecker#correct Jaro–Winkler Levenshtein Unicode code points stable tie order MRI byte-exact 100% coverage 6 arches
Documentation GitHub
Documentation (MkDocs Material + mike) License: BSD-3-Clause Go 1.26.4+ Coverage 100%

go-ruby-did-you-mean is a pure-Go (no cgo) reimplementation of the matcher at the heart of Ruby's did_you_mean standard library — MRI's DidYouMean::SpellChecker#correct and the two string-distance metrics it ranks with, Jaro–Winkler and Levenshtein. Given a mistyped word and a dictionary it returns Ruby's exact ranked list of spelling suggestions — a faithful, byte-for-byte port of upstream spell_checker.rb, jaro_winkler.rb and levenshtein.rb, without any Ruby runtime. It is a standalone, reusable module — a sibling of go-ruby-yaml, go-ruby-regexp and go-ruby-erb — and the did_you_mean matcher for go-embedded-ruby.

Normalization ready

Downcase and strip @ sigils from input and every candidate, so @ivar and IVar compare alike — the first step of MRI’s SpellChecker#correct.

Jaro–Winkler filter & ranking ready

Keep candidates whose Jaro–Winkler similarity clears the threshold (0.834 for inputs longer than 3 characters, else 0.77), drop an exact match of the original, and rank survivors by similarity descending — a stable sort then reverse, matching Ruby’s tie order.

Levenshtein mistype filter ready

Keep the ranked candidates within an edit distance of ⌈len/4⌉ of the input, exactly as MRI’s mistype filter does.

Misspell fallback ready

If nothing survives, return the first ranked candidate whose Levenshtein distance is strictly less than the shorter of the two word lengths — Ruby’s stable-sorted, input-order fallback.

Unicode-correct metrics ready

Jaro / JaroWinkler.distance and Levenshtein.distance ported exactly, comparing Unicode code points (not bytes) like Ruby’s String#each_codepoint, so multibyte words (café, naïve) rank identically.

Differential oracle & coverage ready

Golden vectors captured from MRI plus a broad corpus of typos, transpositions, case variants, multibyte words and no-match inputs fed to the system ruby’s SpellChecker#correct, reproduced byte-for-byte. 100% coverage, gofmt + go vet clean, green across all six 64-bit Go arches and three OSes.

A faithful, line-for-line port of MRI's SpellChecker#correct in pure Go, cgo disabled, so it cross-compiles and embeds anywhere. It normalizes input and candidates, applies the Jaro–Winkler similarity filter and ranking, the Levenshtein mistype filter, and the misspell fallback — comparing Unicode code points (not bytes) like Ruby's String#each_codepoint, so multibyte words rank identically. Validated differentially against the system ruby's DidYouMean::SpellChecker#correct. The did_you_mean matcher for the sibling org github.com/go-embedded-ruby.