fix: reject directory args in keywords CLI - #167
Merged
Conversation
`keywords fit` and `keywords extract` passed directories straight to
File#read, so users got a raw errno and exit 1:
$ keywords fit corpus
Error: Is a directory @ io_fillbuf - fd:6 /path/corpus
Every other input error in the tool exits 2 with a clear message. This
one path did not. It also broke the README's headline workflow, because
a shell-expanded `keywords fit corpus/*` sends any subdirectory as its
own argument.
`fit` now skips directories and keeps the files around them, so
`corpus/*` works when `corpus/` holds a subdirectory. A path that
matches nothing still fails, so typos are still caught. An argument set
that yields no file at all fails with "No files to fit". `extract`
rejects a directory outright.
This also removes a split where a quoted `'corpus/*'` and an unquoted
`corpus/*` behaved differently, since the CLI expands the first itself.
Add .hound.yml pointing Hound at .rubocop.yml. Hound reported 96
offenses on #163 that CI does not see, because it flags `Metrics/
LineLength` (renamed to `Layout/LineLength` in RuboCop 0.78) at stock
defaults, and it flags cops this repo disables.
houndci-bot
reviewed
Aug 15, 2026
houndci-bot
left a comment
There was a problem hiding this comment.
Some files could not be reviewed due to errors:
.rubocop.yml: Layout/LineLength has the wrong namespace - should be Metrics
.rubocop.yml: Layout/LineLength has the wrong namespace - should be Metrics Warning: unrecognized cop plugins found in .rubocop.yml Warning: unrecognized cop Naming/MethodParameterName found in .rubocop.yml Warning: unrecognized cop Lint/UselessConstantScoping found in .rubocop.yml Warning: unrecognized cop Minitest/MultipleAssertions found in .rubocop.yml Warning: unrecognized cop Style/OneClassPerFile found in .rubocop.yml Error: Unknown Ruby version 3.1 found in `TargetRubyVersion` parameter (in .rubocop.yml). Supported versions: 2.1, 2.2, 2.3, 2.4, 2.5
Contributor
Greptile SummaryThis PR normalizes directory handling in the keywords CLI and configures Hound to use the repository’s RuboCop settings.
Confidence Score: 5/5The PR appears safe to merge with no actionable regressions identified. The changed CLI paths correctly exclude directories from fitting, reject directory extraction with the intended usage error, preserve unmatched-path failures, and include focused regression coverage. Important Files Changed
Reviews (1): Last reviewed commit: "fix: reject directory args in keywords C..." | Re-trigger Greptile |
Pointing Hound at .rubocop.yml made it read the file, but its RuboCop
cannot parse it:
.rubocop.yml: Layout/LineLength has the wrong namespace
- should be Metrics
Hound bundles a RuboCop older than 0.78, which renamed that cop in
December 2019. The same version also rejects TargetRubyVersion 3.1.
One file cannot serve both. RuboCop 1.89 refuses Metrics/LineLength as
obsolete, and Hound refuses Layout/LineLength, so any edit that satisfies
Hound breaks the CI lint job.
A translated legacy config would need its own copy of every maximum and
exclusion, would drift from .rubocop.yml, and would still judge Ruby 3.1
code and rbs-inline annotations by 2019 cops.
Disable the Ruby linter instead. CI runs RuboCop 1.89 against
.rubocop.yml on every pull request and is the real gate. Hound still
lints other file types.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fast follow to #163. Closes the one review item that did not land before the merge, and stops the Hound noise.
1. Directory arguments leaked a raw errno
command_fitglobbed arguments without a file check, andcommand_extractonly checkedFile.exist?. A directory reachedFile#readand surfaced the errno through the genericStandardErrorrescue:Every other input error in the tool exits 2 with a clear message, so this path was the odd one out.
It also broke the workflow the README leads with. A shell expands
keywords fit corpus/*before the CLI sees it, so a subdirectory arrives as its own argument and the whole run fails:Behavior now
keywords fit corpus/*(subdir present)keywords fit corpusError: No files to fit, exit 2keywords extract corpusError: "..." is a directory, not a file, exit 2keywords fit corpus/a.txt corpus/NOPE.txtNo files matched, exit 2keywords fit 'corpus/*.md'No files matched, exit 2fitskips directories and keeps the files around them. A path that matches nothing still fails, so typos are still caught. An argument set that yields no file at all fails withNo files to fit.This also removes a split introduced by the per-argument guard in #163: a quoted
'corpus/*'and an unquotedcorpus/*behaved differently, because the CLI expands the first itself. Both now do the same thing.2. Hound reported 96 offenses that CI does not see
Hound flags
Metrics/LineLength. RuboCop renamed that cop toLayout/LineLengthin 0.78 (December 2019). Hound also flags at stock defaults (LineLength 80, MethodLength 10, ClassLength 100, AbcSize 15) while.rubocop.ymlsets 140, 25, 250, and 30 and excludes this file. It flagsStyle/DocumentationandStyle/FrozenStringLiteralCommenttoo, which.rubocop.ymldisables outright.So Hound never read
.rubocop.yml. This adds.hound.ymlto point it there.Note that Hound may still not honor it. Its RuboCop is too old to parse
plugins:(needs 1.72+) orNewCops(needs 0.90+), so it can fall back to defaults again. If the noise continues, the next step is to disable the linter withruby: {enabled: false}or remove the Hound app, since the CIlintjob already runs RuboCop 1.89 against.rubocop.ymlon every PR and is the real gate.Verification
Tests written first, confirmed failing with exit 1, then fixed.
bundle exec rubocop: 56 files, no offensesrbs-inline+rbs validate: passGEM_HOME, and drove the realkeywordsbinary through the table above plus 13 regression checks from the feat: add keywords CLI tool for text vectorization (#122) #163 review rounds: bigram labels,min_word_lengthmodels, snake_case tokens, missing-model guards ontransformandinfo, empty stdin, negative-n,--min-df/--max-df/--ngramvalidation, and the 600-file run underulimit -n 256. All hold.Four tests added: glob with a subdirectory, bare directory to
fit, directory toextract, and a nonexistent path among valid ones as a regression guard.