robotdana / leftovers

Find unused ruby methods and constants and etc
MIT License
81 stars 4 forks source link
linter rails ruby static-analysis unused-code unused-constants unused-methods

Leftovers

travis Gem Version

Find unused methods, Classes, CONSTANTS, @instance_variables, @@class_variables, and $global_variables in your ruby projects.

Why?

Code that never gets executed is code that you shouldn't need to maintain

Leftovers will use static analysis to find these bits of code for you.

It's aware of how some gems call methods for you, including support for much of rails.

Features

Installation

Add this line to your application's Gemfile:

gem 'leftovers', require: false

And then execute:

$ bundle

Or install it yourself as:

$ gem install leftovers

Usage

Run leftovers in your command line in the root of your project. This will output progress as it collects the calls/references and definitions in your project. Then it will output any defined methods (or classes etc) which are not called.

$ leftovers
checked 25 files, collected 2473 calls, 262 definitions
Only directly called in tests:
lib/hello_world.rb:10:6 tested_unused_method def tested_unused_method
lib/hello_world.rb:18:6 another_tested_unused_method def another_tested_unused_method
Not directly called at all:
lib/hello_world.rb:6:6 generated_method= attr_accessor :generated_method
lib/hello_world.rb:6:6 generated_method attr_accessor :generated_method

how to resolve: https://github.com/robotdana/leftovers/tree/main/Readme.md#how-to-resolve

if there is an overwhelming number of results, try using --write-todo

How to resolve

When running leftovers you'll be given a list of method, constant, and variable definitions it thinks are unused. Now what?

they were unintentionally left when removing their calls:

they are called dynamically:

they're defined intentionally to only be used by tests:

they're from a file that shouldn't be checked by leftovers:

if there are too many to address when first adding leftovers to your project, try running leftovers --write-todo,

--write-todo

running leftovers --write-todo will generate a supplemental configuration file allowing all the currently detected uncalled definitions, which will be read on subsequent runs of leftovers without alerting any of the items mentioned in it.

commit this file so you/your team can gradually address these items while still having leftovers alert you to any newly unused items.

Magic comments

# leftovers:keep

aliases leftovers:keeps, leftovers:skip, leftovers:skips, leftovers:skipped, leftovers:allow, leftovers:allows, leftovers:allowed To mark a method definition as not unused, add the comment # leftovers:keep on the same line as the definition

class MyClass
  def my_method # leftovers:keep
    true
  end
end

This would report MyClass is unused, but not my_method To do this for all definitions of this name, instead of adding a comment, add the name to the keep: list in the configuration file.

# leftovers:test_only

_aliases leftovers:for_test, leftovers:for_tests, leftovers:test, leftovers:tests, leftovers:testing_

To mark a definition from a non-test dir, as intentionally only used by tests, use leftovers:test_only

# app/my_class.rb
class MyClass
  def my_method # leftovers:test_only
    true
  end
end
# spec/my_class_spec.rb
describe MyClass do
  it { expect(subject.my_method).to be true }
end

This would consider my_method to be used, even though it is only called by tests.

To do this for all definitions of this name, instead of adding a comment, add the name to the test_only: list in the configuration file.

# leftovers:call

aliases leftovers:calls To mark a call that doesn't use literal values, use leftovers:call with the method name listed

method = [:puts, :warn].sample # leftovers:call puts, warn
send(method, 'text')

This would consider puts and warn to both have been called

# leftovers:dynamic:*

To mark a dynamic call for literal hash and array values without enumerating everything in the comment again, use leftovers:dynamic: on the same line as the beginning of the array or hash

[ # leftovers:dynamic:call_attributes
  :user,
  :admin
].map { |method| send("#{method}_attributes") }

with the following configuration matching the name: value to the leftovers:dynamic:process_name

dynamic:
  name: call_attributes
  arguments: '*'
  add_suffix: '_attributes'

This would consider user_attributes and admin_attributes to both have been called.

Configuration file

The configuration is read from .leftovers.yml in your project root. Its presence is optional and all of these settings are optional.

see the complete config documentation for details. see the built in config files or this repo's own config for examples.

Limitations

Other tools

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests.

To install this gem onto your local machine, run bundle exec rake install.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/robotdana/leftovers.

I especially encourage issues and improvements to the default config, whether expanding the existing config/*.yml or adding new gems. The file should be named [rubygems name].yml and its structure is identical to the project config

License

The gem is available as open source under the terms of the MIT License.