Reek
Code smell detector for Ruby
Install / Use
/learn @troessner/ReekREADME

Code smell detector for Ruby
Table of Contents
- Overview
- Quickstart
- Example
- Supported Ruby versions
- Fixing Smell Warnings
- Sources
- Code smells
- Configuration
- Usage
- Developing Reek / Contributing
- Output formats
- Working with Rails
- Integrations
- Brothers and sisters
- Contributors
- Additional resources
Overview
Quickstart
Reek is a tool that examines Ruby classes, modules and methods and reports any Code Smells it finds.
For an excellent introduction to Code Smells and Reek check out this blog post or that one. There is also this talk from RubyConfBY (there is also a slide deck if you prefer that).
Install it via rubygems:
gem install reek
and run it like this:
reek [options] [dir_or_source_file]*
Example
Imagine a source file demo.rb containing:
# Smelly class
class Smelly
# This will reek of UncommunicativeMethodName
def x
y = 10 # This will reek of UncommunicativeVariableName
end
end
Reek will report the following code smells in this file:
$ reek --no-documentation demo.rb
Inspecting 1 file(s):
S
demo.rb -- 2 warnings:
[4]:UncommunicativeMethodName: Smelly#x has the name 'x'
[5]:UncommunicativeVariableName: Smelly#x has the variable name 'y'
Supported Ruby versions
Reek is officially supported for CRuby 3.0 through 3.3 and for JRuby 9.4. Other Ruby implementations (like Rubinius) are not officially supported but should work as well.
Note that, on each Ruby version, Reek will use the parser for that version of Ruby. So, you should always run Reek using one of your project's target Ruby versions.
Fixing Smell Warnings
Reek focuses on high-level code smells, so we can't tell you how to fix warnings in a generic fashion; this is and will always be completely dependent on your domain language and business logic.
That said, an example might help you get going. Have a look at this sample of a Ruby on Rails model (be aware that this is truncated, not working code):
class ShoppingCart < ActiveRecord::Base
has_many :items
def gross_price
items.sum { |item| item.net + item.tax }
end
end
class Item < ActiveRecord::Base
belongs_to :shopping_cart
end
Running Reek on this file like this:
reek app/models/shopping_cart.rb
would report:
[5, 5]:ShoppingCart#gross_price refers to item more than self (FeatureEnvy)
Fixing this is pretty straightforward. Put the gross price calculation for a single item
where it belongs, which would be the Item class:
class ShoppingCart < ActiveRecord::Base
has_many :items
def gross_price
items.sum { |item| item.gross_price }
end
end
class Item < ActiveRecord::Base
belongs_to :shopping_cart
def gross_price
net + tax
end
end
The Code Smells docs may give you further hints - be sure to check out those first when you have a warning that you don't know how to deal with.
Sources
There are multiple ways you can have Reek work on sources, the most common one just being
reek lib/
If you don't pass any source arguments to Reek it just takes the current working directory as source.
So
reek
is the exact same thing as being explicit:
reek .
Additionally you can pipe code to Reek like this:
echo "class C; def m; end; end" | reek
This would print out:
$stdin -- 3 warnings:
[1]:C has no descriptive comment (IrresponsibleModule)
[1]:C has the name 'C' (UncommunicativeModuleName)
[1]:C#m has the name 'm' (UncommunicativeMethodName)
Code smells
Reek currently includes checks for some aspects of Control Couple, Data Clump, Feature Envy, Large Class, Long Parameter List, Simulated Polymorphism, Too Many Statements, Uncommunicative Name, Unused Parameters and more. See the Code Smells for up to date details of exactly what Reek will check in your code.
Special configuration for controversial detectors:
Unused Private Method is disabled by default because it is kind of controversial which means you have to explicitly activate it in your configuration via
UnusedPrivateMethod:
enabled: true
Utility Function is a controversial detector as well that can turn out to be really unforgiving. As a consequence, we made it possible to disable it for non-public methods like this:
---
UtilityFunction:
public_methods_only: true
Configuration
Command-line interface
For a basic overview, run
reek --help
For a summary of those CLI options see Command-Line Options.
Configuration file
Configuration loading
Configuring Reek via a configuration file is by far the most powerful way.
Reek expects this filename to be .reek.yml but you can override this via the CLI -c switch (see below).
There are three ways of passing Reek the configuration file:
- Using the CLI
-cswitch (see Command-line interface above) - Having the configuration file either in your current working directory or in a parent directory (more on that later)
- Having the configuration file in your home directory
The order in which Reek tries to find such a configuration file is exactly the above: first it checks if we have given it a configuration file explicitly via CLI; then it checks the current working directory for a file and if it can't find one, it traverses up the directories until it hits the root directory; lastly, it checks your home directory.
As soon as Reek detects a configuration file it stops searching
immediately, meaning that from Reek's point of view there exists
exactly one configuration file and one configuration, regardless
of how many *.reek files you might have on your filesystem.
Configuration options
We put a lot of effort into making Reek's configuration as self explanatory as possible so the
best way to understand it is by looking at a simple
example (e.g. .reek.yml in your project directory):
---
### Generic smell configuration
detectors:
# You can disable smells completely
IrresponsibleModule:
enabled: false
# You can use filters to silence Reek warnings.
# Either because you simply disagree with Reek (we are not the police) or
# because you want to fix this at a later point in time.
NestedIterators:
exclude:
- "MyWorker#self.class_method" # should be refactored
- "AnotherWorker#instance_method" # should be refactored as well
# A lot of smells allow fine tuning their configuration. You can look up all available options
# in the corresponding smell documentation in /docs. In most cases you probably can just go
# with the defaults as documented in defaults.reek.yml.
DataClump:
max_copies: 3
min_clump_size: 3
### Directory specific configuration
# You can configure smells on a per-directory base.
# E.g. the classic Rails case: controllers smell of NestedIterators (see /docs/Nested-Iterators.md) and
# helpers smell of UtilityFunction (see docs/Utility-Function.md)
#
# Note that we only allow configuration on a directory level, not a file level,
# so all paths have to point to directories.
# A Dir.glob pattern can be used.
directories:
"web_app/app/controllers":
NestedIterators:
enabled: false
"web_app/app/helpers**":
UtilityFunction:
enabled: false
"web_app/lib/**/test/**":
UtilityFunction:
enabled: false
### Excluding directories
# Directories and files below will not be scanned at all
exclude_paths:
- lib/legacy
- lib/rake/legacy_tasks
- lib/smelly.rb
As you see abov

