Class: RuboCop::Cop::Generator

Inherits:
Object
  • Object
show all
Defined in:
lib/rubocop/cop/generator.rb,
lib/rubocop/cop/generator/require_file_injector.rb

Overview

Source and spec generator for new cops

This generator will take a cop name and generate a source file and spec file when given a valid qualified cop name.

Defined Under Namespace

Classes: RequireFileInjector

Constant Summary collapse

SOURCE_TEMPLATE =
<<-RUBY.strip_indent
  # frozen_string_literal: true

  # TODO: when finished, run `rake generate_cops_documentation` to update the docs
  module RuboCop
    module Cop
      module %<department>s
        # TODO: Write cop description and example of bad / good code. For every
        # `SupportedStyle` and unique configuration, there needs to be examples.
        # Examples must have valid Ruby syntax. Do not use upticks.
        #
        # @example EnforcedStyle: bar (default)
        #   # Description of the `bar` style.
        #
        #   # bad
        #   bad_bar_method
        #
        #   # bad
        #   bad_bar_method(args)
        #
        #   # good
        #   good_bar_method
        #
        #   # good
        #   good_bar_method(args)
        #
        # @example EnforcedStyle: foo
        #   # Description of the `foo` style.
        #
        #   # bad
        #   bad_foo_method
        #
        #   # bad
        #   bad_foo_method(args)
        #
        #   # good
        #   good_foo_method
        #
        #   # good
        #   good_foo_method(args)
        #
        class %<cop_name>s < Cop
          # TODO: Implement the cop in here.
          #
          # In many cases, you can use a node matcher for matching node pattern.
          # See https://github.com/rubocop-hq/rubocop/blob/master/lib/rubocop/node_pattern.rb
          #
          # For example
          MSG = 'Use `#good_method` instead of `#bad_method`.'.freeze

          def_node_matcher :bad_method?, <<-PATTERN
            (send nil? :bad_method ...)
          PATTERN

          def on_send(node)
            return unless bad_method?(node)

            add_offense(node)
          end
        end
      end
    end
  end
RUBY
SPEC_TEMPLATE =
<<-SPEC.strip_indent
  # frozen_string_literal: true

  RSpec.describe RuboCop::Cop::%<department>s::%<cop_name>s do
    subject(:cop) { described_class.new(config) }

    let(:config) { RuboCop::Config.new }

    # TODO: Write test code
    #
    # For example
    it 'registers an offense when using `#bad_method`' do
      expect_offense(<<-RUBY.strip_indent)
        bad_method
        ^^^^^^^^^^ Use `#good_method` instead of `#bad_method`.
      RUBY
    end

    it 'does not register an offense when using `#good_method`' do
      expect_no_offenses(<<-RUBY.strip_indent)
        good_method
      RUBY
    end
  end
SPEC

Instance Method Summary collapse

Constructor Details

#initialize(name, github_user, output: $stdout) ⇒ Generator

Returns a new instance of Generator.

Raises:

  • (ArgumentError)


101
102
103
104
105
106
107
108
# File 'lib/rubocop/cop/generator.rb', line 101

def initialize(name, github_user, output: $stdout)
  @badge = Badge.parse(name)
  @github_user = github_user
  @output = output
  return if badge.qualified?

  raise ArgumentError, 'Specify a cop name with Department/Name style'
end

Instance Method Details

#inject_config(config_file_path: 'config/enabled.yml') ⇒ Object



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/rubocop/cop/generator.rb', line 125

def inject_config(config_file_path: 'config/enabled.yml')
  config = File.readlines(config_file_path)
  content = <<-YAML.strip_indent
    #{badge}:
      Description: 'TODO: Write a description of the cop.'
      Enabled: true

  YAML
  target_line = config.find.with_index(1) do |line, index|
    next if line =~ /^[\s#]/
    break index - 1 if badge.to_s < line
  end
  config.insert(target_line, content)
  File.write(config_file_path, config.join)
  output.puts <<-MESSAGE.strip_indent
    [modify] A configuration for the cop is added into #{config_file_path}.
             If you want to disable the cop by default, move the added config to config/disabled.yml
  MESSAGE
end

#inject_require(root_file_path: 'lib/rubocop.rb') ⇒ Object



118
119
120
121
122
123
# File 'lib/rubocop/cop/generator.rb', line 118

def inject_require(root_file_path: 'lib/rubocop.rb')
  RequireFileInjector.new(
    source_path: source_path,
    root_file_path: root_file_path
  ).inject
end

#todoObject



145
146
147
148
149
150
151
152
153
# File 'lib/rubocop/cop/generator.rb', line 145

def todo
  <<-TODO.strip_indent
    Do 3 steps:
      1. Add an entry to the "New features" section in CHANGELOG.md,
         e.g. "Add new `#{badge}` cop. ([@#{github_user}][])"
      2. Modify the description of #{badge} in config/enabled.yml
      3. Implement your new cop in the generated file!
  TODO
end

#write_sourceObject



110
111
112
# File 'lib/rubocop/cop/generator.rb', line 110

def write_source
  write_unless_file_exists(source_path, generated_source)
end

#write_specObject



114
115
116
# File 'lib/rubocop/cop/generator.rb', line 114

def write_spec
  write_unless_file_exists(spec_path, generated_spec)
end