rubyrubocop

How to query which RuboCop rules apply to a file?


I am working on a tool to analyze how rubocop is used (enabled/disabled) and fixed (excluded into todo lists) in certain areas of the codebase. Given the multitude of config options, I think I am looking for a way to programmatically ask RuboCop whether given a file or folder, a certain rule is enabled and whether this file is excluded via a todo or not. Is there an API for this?

I have so far spelunked in https://github.com/rubocop/rubocop to see if I could find an API... Searched via SO and google and can't find anything.


Solution

  • I don't think there's public interface for what you want. This mobilize_team method in the Runner is what instantiates a RuboCop::Cop::Team. The team object determines the cops to use in this roundup_relevant_cops method. Both of these methods are private, but you could use send to work around that.

    For example, say that we have a project with two files called test_one.rb and test_two.rb.

    The .rubocop_todo.yml says that one of the files still needs to be handled:

    # .rubocop_todo.yml
    Style/FrozenStringLiteralComment:
      Exclude:
        - 'test_two.rb'
    

    The .rubocop.yml config says that we just care about Style/FrozenStringLiteralComment:

    # .rubocop.yml
    inherit_from: .rubocop_todo.yml
    
    AllCops:
      DisabledByDefault: true
    
    Style/FrozenStringLiteralComment:
      Enabled: true
    

    We can see the cops that RuboCop will apply to each file if we do this:

    require 'rubocop'
    
    # Set up the Runner. Assumes no special command line options are involved.
    options, _paths = RuboCop::Options.new.parse([])
    config_store = RuboCop::ConfigStore.new
    runner = RuboCop::Runner.new(options, config_store)
    
    # For each file, figure out which cops are enabled for that file
    ['test_one.rb', 'test_two.rb'].each do |filename|
      full_path = File.join(Dir.pwd, filename)
      config = config_store.for_file(full_path)
      source = RuboCop::ProcessedSource.from_file(full_path, config.target_ruby_version)
      team = runner.send(:mobilize_team, source)
      cops = team.send(:roundup_relevant_cops, source)
      puts "#{filename}: #{cops.map(&:name).join(', ')}"
    end
    

    This will show this output:

    test_one.rb: Lint/Syntax, Style/FrozenStringLiteralComment
    test_two.rb: Lint/Syntax
    

    Because of this special condition in enable_cop? the Lint/Syntax cop is always enabled. And since test_one.rb isn't included in the TODO list, it is the only file that qualifies for the Style/FrozenStringLiteralComment cop.