# Reek: a code smell detector for Ruby that reports before it prescribes

> Reek inspects Ruby classes, modules and methods and reports code smells such as Feature Envy and Uncommunicative Name. It is deliberately narrow: it flags, it does not fix, and its defaults assume you will tune them.

**troessner/reek** — Code smell detector for Ruby

- Repository: https://github.com/troessner/reek
- Website: https://github.com/troessner/reek
- Stars: 4,131 · Forks: 282
- Language: Ruby
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/troessner-reek

## What Reek reports, and who the report is for

Reek examines Ruby classes, modules and methods and reports code smells. That is the whole job. The README's own quickstart sentence is blunt about the scope, and the project does not claim to do style formatting, type checking or security analysis. The audience follows from that: teams working in Ruby who want a structural read on their code, particularly on files that have grown past the point where a reviewer can hold the whole shape in their head.

The smell list is the interesting part, because it is not a list of syntax rules. The README names Control Couple, Data Clump, Feature Envy, Large Class, Long Parameter List, Simulated Polymorphism, Too Many Statements, Uncommunicative Name and Unused Parameters, and points readers at docs/Code-Smells.md for the current detail. These are design observations. Feature Envy, for example, fires when a method reaches into another object more than it works with itself, which is a coupling signal rather than a formatting one.

That framing sets expectations correctly. Reek is a reviewer's assistant, not a gate that can be satisfied by reformatting. If your team wants a tool that produces a pass or fail on style, this is the wrong category of tool.

## How Reek inspects a Ruby file

The mechanism visible in the README is straightforward: Reek parses Ruby sources and runs a set of detectors over the resulting structure, then prints warnings with file, line and detector name. The example output shows the shape clearly. Running the tool on a file with a method named x and a variable named y produces warnings tagged UncommunicativeMethodName and UncommunicativeVariableName, each with the line number in brackets and a human sentence naming the offending identifier.

One detail matters more than it looks. The README states that on each Ruby version, Reek uses the parser for that version of Ruby, and advises running Reek with one of your project's target Ruby versions. That is a real operational constraint. If you run Reek under a Ruby older than the syntax your code uses, the parse itself is the failure mode, not the smell detection. Pinning Reek's runtime to a target version is not a nicety, it is how you avoid false parse errors.

Sources are flexible. Reek accepts directories or source files as arguments, defaults to the current working directory when given none, and can read from standard input, which makes it usable inside a pipe. The README shows the stdin path producing warnings attributed to $stdin, with the same line-numbered format.

## Installing Reek and getting a first warning

Reek ships as a gem. The README gives one install command and one invocation form, and both are worth copying exactly before you start adding flags.

```bash
gem install reek
```

With the gem on your path, point Reek at a directory or a single file. Running it with no arguments inspects the current working directory, which the README says is identical to passing a dot.

```bash
reek lib/
```

To see the warning format without touching your own code, the README's own demo file is the fastest path. Create demo.rb with a class whose method is named x and whose local variable is named y, then run Reek with documentation checks suppressed so the output is not crowded by missing-comment warnings.

```bash
reek --no-documentation demo.rb
```

The expected output is a short block listing two warnings, one for the method name and one for the variable name, each prefixed with its line number. If you see a parse error instead, check the Ruby version running Reek against the syntax in the file, per the README's note about per-version parsers.

From there, configuration lives in .reek.yml at the repository root. The README's controversial-detector examples show the file shape: a detector name as a key, options beneath it. Unused Private Method is disabled by default and has to be turned on explicitly.

```yaml
UnusedPrivateMethod:
  enabled: true
```

Utility Function is enabled but can be narrowed so it only applies to public methods, which the README frames as a way to make an unforgiving detector less so.

```yaml
---
UtilityFunction:
  public_methods_only: true
```

The README also warns about multiple configuration files, so it is worth confirming which one Reek actually loaded before you conclude a setting had no effect.

## Where Reek is the wrong tool

The README is unusually candid about the biggest limitation: Reek focuses on high-level code smells and, in the project's own words, cannot tell you how to fix warnings in a generic fashion, because the correct fix depends on domain language and business logic. That is not a documentation gap, it is a design position. A tool that flags Feature Envy cannot know whether the calculation belongs on the other object or whether the coupling is intentional.

The practical consequence is that Reek's output is a queue of judgement calls, not a to-do list. On a large legacy codebase, the first run can be long, and the README's answer to that is a todo list workflow rather than pretending the warnings are all actionable now. Teams that want a tool whose default output is clean on day one will be disappointed.

Two detectors are flagged as controversial in the README itself. Unused Private Method is off by default. Utility Function can be restricted to public methods because it is described as potentially unforgiving. That is a signal about false positives: the maintainers would rather you opt in than have the tool cry wolf. Reek is also Ruby-specific and parser-based, so it has nothing to say about a mixed-language repository outside the Ruby files, and it cannot reason about runtime behaviour, metaprogramming side effects, or whether a method is actually called through send. Static inspection has a ceiling, and Reek sits under it.

## Reek against a general-purpose Ruby linter

The obvious comparison is RuboCop, and the difference is one of intent rather than quality. RuboCop is a style and lint framework: it covers formatting, layout and a broad rule catalogue, and it is designed to be auto-corrected in many cases. Reek does none of that. It has no formatter role and no auto-fix story in the README; its detectors are about structure, coupling and naming at the level of classes and methods.

The tell is in the repository layout. Reek's own tree carries both .reek.yml and .rubocop.yml, plus a .rubocop_todo.yml. The project runs both tools on itself. That is the honest answer for most teams: they are complements, not substitutes. RuboCop tells you the code is formatted and consistent; Reek tells you a method envies another object or a class has grown too large.

If you already run RuboCop and want one more lint pass, Reek adds a different axis of feedback. If you want a single tool that handles formatting and structure together, Reek alone will not replace what you have.

## Running Reek in Docker and inside other tools

Reek has a Dockerfile in the repository, and it is not a general-purpose image. The header comment describes it as a CodeClimate specification build, and the documented build and run commands are aimed at producing a codeclimate/codeclimate-reek image. The container runs as a non-root user, installs the gem dependencies, and its default command is the CodeClimate engine entry point rather than the reek CLI.

```bash
docker build -t codeclimate/codeclimate-reek . && docker run codeclimate/codeclimate-reek
```

If you want Reek inside a container for your own pipeline, the gem install is the simpler route; the shipped Dockerfile is shaped around the CodeClimate engine contract, including environment variables for the code directory and the engine's entry script. The README separately lists editor integrations and projects that use or support Reek, which is the place to look if you want warnings surfaced in your editor rather than in a terminal.

Output formats are configurable, and the README points at a dedicated section for them, so CI consumers are not limited to the default human-readable text. The samples directory in the repository includes a checkstyle.xml, which suggests a checkstyle-shaped output is among the options, though the README's output-format section is the authority on the current list.

## Licence, maintenance and upgrade cost

Reek is MIT licensed, and the repository carries a License.txt at the root alongside the gemspec. MIT is permissive: it allows use, modification and redistribution provided the copyright notice and licence text are preserved. That is the licence implication to check with your own legal process, not a substitute for it.

The repository is not archived, and the last push was on 2026-08-28, which is recent. The README states official support for CRuby 3.0 through 3.3 and for JRuby 9.4, with other implementations described as not officially supported but likely to work. That support window is the main upgrade cost: when your project moves to a newer CRuby, you are relying on Reek's parser support for that version, and the README's advice to run Reek under a target Ruby version means the tool's runtime and your application's runtime are coupled by design. There is a CHANGELOG.md in the repository, which is where to check what a version bump changes before you take it.

The Dockerfile pins ruby:2.6.0-alpine, which sits well below the supported CRuby range in the README. That image is built for the CodeClimate engine, so the mismatch is explainable, but anyone forking that Dockerfile for their own pipeline should treat the base image as something to revisit rather than inherit.

## Conclusion

Adopt Reek if you maintain Ruby code and want a fast, configurable second opinion on structure, especially on legacy files where a Feature Envy or Long Parameter List warning is worth a look before a refactor. Do not adopt it expecting automatic fixes or a clean out-of-the-box run on a large existing codebase, because the README is explicit that it cannot tell you how to fix a warning in a generic way, and detectors such as Unused Private Method and Utility Function are off or restricted by default precisely because they are controversial. Before you wire it into CI, run reek on your own tree, inspect the output formats the project documents, and decide which detectors you want to enable in .reek.yml; verify first that the Ruby version you run Reek with matches a version your project targets, since the README states Reek uses the parser for whichever Ruby version runs it.

## FAQ

### How do I install Reek?

The README gives a single command, gem install reek, after which you run it as reek with options and one or more directories or source files. With no source arguments it inspects the current working directory.

### What Ruby versions does Reek support?

The README states official support for CRuby 3.0 through 3.3 and for JRuby 9.4, and notes that other implementations are not officially supported but should work. It also advises running Reek with one of your project's target Ruby versions, because Reek uses the parser for whichever Ruby version runs it.

### Can Reek fix the warnings it reports?

No. The README states that Reek focuses on high-level code smells and cannot tell you how to fix warnings in a generic fashion, since the fix depends on your domain language and business logic. It offers an example of moving a calculation to the class where it belongs, but no automatic correction.

### Why does Reek not report unused private methods by default?

The README describes Unused Private Method as disabled by default because it is kind of controversial, and shows enabling it in configuration with an UnusedPrivateMethod key and enabled: true.

## Sources

- [Issues](https://github.com/troessner/reek/issues)
- [License: MIT](https://github.com/troessner/reek/blob/master/LICENSE)
- [Project website](https://github.com/troessner/reek)
- [README](https://github.com/troessner/reek/blob/master/README.md)
- [troessner/reek on GitHub](https://github.com/troessner/reek)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/troessner-reek
