Giter Club home page Giter Club logo

reek's Introduction

reek: code smell detection for Ruby

Overview

Build Status Gem Version Dependency Status Inline docs

Quickstart

reek is a tool that examines Ruby classes, modules and methods and reports any Code Smells it finds. Install it like this:

gem install reek

and run it like this:

reek [options] [dir_or_source_file]*

Example

Imagine a source file demo.rb containing:

class Dirty
  # This method smells of :reek:NestedIterators but ignores them
  def awful(x, y, offset = 0, log = false)
    puts @screen.title
    @screen = widgets.map { |w| w.each { |key| key += 3 * x } }
    puts @screen.contents
  end
end

reek will report the following code smells in this file:

$ reek demo.rb
demo.rb -- 8 warnings:
  [1]:Dirty has no descriptive comment (IrresponsibleModule)
  [3]:Dirty#awful has 4 parameters (LongParameterList)
  [3]:Dirty#awful has boolean parameter 'log' (BooleanParameter)
  [3]:Dirty#awful has the parameter name 'x' (UncommunicativeParameterName)
  [5]:Dirty#awful has the variable name 'w' (UncommunicativeVariableName)
  [3]:Dirty#awful has unused parameter 'log' (UnusedParameters)
  [3]:Dirty#awful has unused parameter 'offset' (UnusedParameters)
  [3]:Dirty#awful has unused parameter 'y' (UnusedParameters)

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 bussiness 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.

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.

There are three ways of passing reek a configuration file:

  1. Using the CLI -c switch (see Command-line interface above)
  2. Having a file ending with .reek either in your current working directory or in a parent directory (more on that later)
  3. Having a file ending with .reek 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. config.reek in your project directory):

---

### Generic smell configuration

# 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.
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)
"web_app/app/controllers":
  NestedIterators:
    enabled: false
"web_app/app/helpers":
  UtilityFunction:
    enabled: false

### Excluding directories

# Directories below will not be scanned at all
exclude_paths:
  - lib/legacy
  - lib/rake/legacy_tasks

Note you do not need a configuration file at all. If you're fine with all the defaults we set you can skip this completely.

For more details please check out the Basic Smell Options which are supported by every smell type. As you can see above, certain smell types offer a configuration that goes beyond that of the basic smell options, for instance Data Clump. All options that go beyond the Basic Smell Options are documented in the corresponding smell type /docs page (if you want to get a quick overview over all possible configurations you can also check out the default.reek file in this repository.

Source code comments

In case you need to suppress a smell warning and you can't or don't want to use configuration files for whatever reasons you can also use special source code comments like this:

# This method smells of :reek:NestedIterators
def smelly_method foo
  foo.each {|bar| bar.each {|baz| baz.qux}}
end

You can even pass in smell specific configuration settings:

# :reek:NestedIterators: { max_allowed_nesting: 2 }
def smelly_method foo
  foo.each {|bar| bar.each {|baz| baz.qux}}
end

This is an incredible powerful feature and further explained under Smell Suppresion.

Usage

Besides the obvious

reek [options] [dir_or_source_file]*

there are quite a few other ways how to use reek in your projects:

Developing reek / Contributing

The first thing you want to do after checking out the source code is to run Bundler:

bundle install

and then run the tests:

bundle exec rspec spec/your/file_spec.rb            # Runs all tests in spec/your/file_spec.rb
bundle exec rspec spec/your/file_spec.rb:23         # Runs test in line 23
bundle exec cucumber features/your_file.feature     # Runs all scenarios in your_file.feature
bundle exec cucumber features/your_file.feature:23  # Runs scenario at line 23

Or just run the whole test suite:

bundle exec rake

From then on you should check out:

If you don't feel like getting your hands dirty with code there are still other ways you can help us:

  • Open up an issue and report bugs
  • Suggest other improvements like additional smells for instance

Output formats

reek supports 5 output formats:

  • plain text (default)
  • HTML (--format html)
  • YAML (--format yaml, see also YAML Reports)
  • JSON (--format json)
  • XML (--format xml)

Working with Rails

Making reek "Rails"-friendly is fairly simple since we support directory specific configurations (directory directives in reek talk). Just add this to your configuration file:

"app/controllers":
  IrresponsibleModule:
    enabled: false
  NestedIterators:
    max_allowed_nesting: 2
"app/helpers":
  IrresponsibleModule:
    enabled: false
  UtilityFunction:
    enabled: false

Be careful though, reek does not merge your configuration entries, so if you already have a directory directive for "app/controllers" or "app/helpers" you need to update those directives instead of copying the above YAML sample into your configuration file.

Integrations

Editor integrations

Projects that use or support us

Misc

Brothers and sisters

A non-exhaustive list of other static code analyzers you might want to look into:

  • debride - analyze code for potentially uncalled / dead methods
  • flay - analyze code for structural similarities
  • flog - reports the most tortured code in an easy to read pain report
  • SandiMeter - checking your Ruby code for Sandi Metz' four rules
  • ruby-lint - static code analysis tool
  • Fasterer - Fasterer will suggest some speed improvements based on fast-ruby

Contributors

The reek core team consists of:

The original author of reek is Kevin Rutherford.

Notable contributions came from:

Additional resources

Miscellaneous

More information

reek's People

Contributors

kevinrutherford avatar mvz avatar troessner avatar chastell avatar arwagner avatar gilles-leblanc avatar emilrehnberg avatar beanieboi avatar bf4 avatar andyw8 avatar tuexss avatar aakritigupta avatar tansaku avatar sometimesfood avatar rrrene avatar snusnu avatar apiology avatar vasfed avatar sauliusgrigaitis avatar salimane avatar peeyush1234 avatar oliverklee avatar miketheman avatar maser avatar marcofognog avatar leonelgalan avatar apuratepp avatar lencioni avatar jhwist avatar guilhermesimoes avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.