Go to file
Joshua Clayton a6e926e4d2 Move thread management to app wrapper
Why?
====

With multiple calls to `parallel`, `stopGlobalPool` stops working
correctly.

This moves `stopGlobalPool` higher up, and executes it once, allowing
multiple calls to `parallel` to happen without causing issues.
2016-06-21 06:10:18 -04:00
app Roll up App into a monad transformer stack 2016-06-16 06:12:29 -04:00
data Initial support of aliases based on wildcard matching 2016-06-01 22:16:44 -04:00
src/Unused Move thread management to app wrapper 2016-06-21 06:10:18 -04:00
test Cover case within autoLowLikelihood where no matches are present 2016-06-07 05:19:40 -04:00
.gitignore Ignore tmp 2016-05-01 05:25:50 -04:00
.travis.yml Test unused on TravisCI 2016-05-11 23:09:35 -04:00
LICENSE Initial 2016-04-28 05:37:06 -04:00
NEWS Bump version to 0.4.0.0 2016-06-10 07:05:58 -04:00
README.md Remove reference to unsupported config matcher 2016-06-11 06:05:29 -04:00
Setup.hs Initial 2016-04-28 05:37:06 -04:00
stack.yaml Bump to LTS 6.0 2016-05-26 22:24:28 -04:00
unused.cabal Roll up App into a monad transformer stack 2016-06-16 06:12:29 -04:00

Unused Build Status

A command line tool to identify unused code.

Image of Unused Output

"What kinds of projects can I used it on?"

Anything.

Yes, literally anything.

It's probably best if you have a ctags file it can read from (it looks in .git, tmp, and the root directory for a tags file), but if you have another way to pipe a bunch of methods/functions/classes/modules/whatever in, that works too.

Right now, there are some special cases built in for Rails and Phoenix apps (specifically, assumptions about what's fine to only have one reference to, e.g. Controllers in Rails and Views in Phoenix), but it'll work on Rubygems, Elixir packages, or anything else.

That said, be confident the code you're removing won't break your program. Especially with projects built in Ruby, Elixir, or JavaScript, there are ways to dynamically trigger or define behavior that may be surprising. A test suite can help here, but still cannot determine every possible execution path.

Installing

You can install my formulae via Homebrew with brew tap:

brew tap joshuaclayton/formulae

Next, run:

brew install unused

Alternatively, you can install by hand.

Installing by hand

This project uses Haskell and Stack.

Once you have these tools installed:

stack setup
stack install

This will generate a binary in $HOME/.local/bin; ensure this directory is in your $PATH.

Using Unused

unused attempts to read from common tags file locations (.git/tags, tags, and tmp/tags).

In an application where the tags file exists, run:

unused

If you want to specify a custom tags file, or load tokens from somewhere else, run:

cat .custom/tags | unused --stdin

To view more usage options, run:

unused --help

Custom Configuration

The first time you use unused, you might see a handful of false positives. unused will look in two additional locations in an attempt to load additional custom configuration to help improve this.

Configuration format

# Language or framework name
#   e.g. Rails, Ruby, Go, Play
- name: Framework or language
  # Collection of matches allowed to have one occurrence
  autoLowLikelihood:
    # Low likelihood match name
    - name: ActiveModel::Serializer
      # Flag to capture only capitalized names
      #   e.g. would match `ApplicationController`, not `with_comments`
      classOrModule: true

      # Matcher for `.*Serializer$`
      #   e.g. `UserSerializer`, `ProjectSerializer`
      termEndsWith: Serializer

      # Matcher for `^with_.*`
      #   e.g. `with_comments`, `with_previous_payments`
      termStartsWith: with_

      # Matcher for `^ApplicationController$`
      termEquals: ApplicationController

      # Matcher for `.*_factory.ex`
      #   e.g. `lib/appname/user_factory.ex`, `lib/appname/project_factory.ex`
      pathEndsWith: _factory.ex

      # Matcher for `^app/policies.*`
      #   e.g. `app/policies/user_policy.rb`, `app/policies/project_policy.rb`
      pathStartsWith: app/policies

      # list of termEquals
      # Matcher allowing any exact match from a list
      allowedTerms:
      - index?
      - edit?
      - create?

~/.unused.yml

The first location is ~/.unused.yml. This should hold widely-used configuration roughly applicable across projects. Here's an example of what might be present:

- name: Rails
  autoLowLikelihood:
    - name: ActiveModel::Serializer
      termEndsWith: Serializer
      classOrModule: true
    - name: Pundit
      termEndsWith: Policy
      classOrModule: true
      pathEndsWith: .rb
    - name: Pundit Helpers
      allowedTerms:
        - Scope
        - index?
        - new?
        - create?
        - show?
        - edit?
        - destroy?
        - resolve
    - name: JSONAPI::Resources
      termEndsWith: Resource
      classOrModule: true
      pathStartsWith: app/resources
    - name: JSONAPI::Resources Helpers
      allowedTerms:
      - updatable_fields
      pathStartsWith: app/resources

I tend to work on different APIs, and the two libraries I most commonly use have a fairly similar pattern when it comes to class naming. They both also use that naming structure to identify serializers automatically, meaning they very well may only be referenced once in the entire application (when they're initially defined).

Similarly, with Pundit, an authorization library, naming conventions often mean only one reference to the class name.

This is a file that might grow, but is focused on widely-used patterns across codebases. You might even want to check it into your dotfiles.

APP_ROOT/.unused.yml

The second location is APP_ROOT/.unused.yml. This is where any project-specific settings might live. If you're working on a library before extracting to a gem or package, you might have this configuration take that into account.

Validation

unused will attempt to parse both of these files, if it finds them. If either is invalid either due to missing or mistyped keys, an error will be displayed.

Requirements

Unused leverages Ag to analyze the codebase; as such, you'll need to have ag available in your $PATH. This is set as an explicit dependency in Homebrew.

Testing

To run the test suite, run:

stack test

License

Copyright 2016 Josh Clayton. See the LICENSE.