Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a rake task for generation a new cop #3533

Merged
merged 1 commit into from Sep 26, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions Rakefile
Expand Up @@ -16,6 +16,8 @@ require 'rspec/core'
require 'rspec/core/rake_task'
require 'rubocop/rake_task'

Dir['tasks/**/*.rake'].each { |t| load t }

RSpec::Core::RakeTask.new(:spec)

RSpec::Core::RakeTask.new(:ascii_spec) do |t|
Expand Down
2 changes: 2 additions & 0 deletions manual/contributing.md
Expand Up @@ -16,6 +16,8 @@ Before submitting a patch or a pull request make sure all tests are
passing and that your patch is in line with the [contribution
guidelines](https://github.com/bbatsov/rubocop/blob/master/.github/CONTRIBUTING.md).

See also. [development.md](development.md)

## Documentation

Good documentation is just as important as good code.
Expand Down
17 changes: 17 additions & 0 deletions manual/development.md
@@ -0,0 +1,17 @@
## Add a new cop

Use a rake task to generate a cop template.

```sh
$ bundle exec rake new_cop[Category/Name]
created
- lib/rubocop/cop/category/name.rb
- spec/rubocop/cop/category/name_spec.rb

Do 4 steps
- Add an entry to `New feature` section in CHANGELOG.md
- e.g. Add new `Category/Name` cop. ([@your_id][])
- Add `require 'lib/rubocop/cop/category/name'` into lib/rubocop.rb
- Add an entry into config/enabled.yml or config/disabled.yml
- Implement a new cop to the generated file!
```
1 change: 1 addition & 0 deletions mkdocs.yml
Expand Up @@ -15,6 +15,7 @@ pages:
- Integration with other tools: integration_with_other_tools.md
- Support: support.md
- Contributing: contributing.md
- Development: development.md
extra_css:
- css/extra.css
theme: readthedocs
110 changes: 110 additions & 0 deletions tasks/new_cop.rake
@@ -0,0 +1,110 @@
# encoding: utf-8
# frozen_string_literal: true

desc 'Generate a new cop template'
task :new_cop, [:cop] do |_task, args|
def to_snake(str)
str
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
.tr('-', '_')
.downcase
end

cop_name = args[:cop] # Category/Name
raise ArgumentError, 'One argument is required' unless cop_name
category, name = *cop_name.split('/', 2)
unless category && name
raise ArgumentError, 'Specify a cop name with Category/Name style'
end

cop_code = <<-END
# encoding: utf-8
# frozen_string_literal: true

module RuboCop
module Cop
module #{category}
# TODO: Write cop description and example of bad / good code.
#
# @example
# # bad
# bad_method()
#
# # bad
# bad_method(args)
#
# # good
# good_method()
#
# # good
# good_method(args)
class #{name} < Cop
# TODO: Implement the cop into here.
#
# In many cases, you can use a node matcher for matching node pattern.
# See. https://github.com/bbatsov/rubocop/blob/master/lib/rubocop/node_pattern.rb
#
# For example
MSG = 'Message of #{cop_name}'.freeze

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

def on_send(node)
return unless bad_method?(node)
add_offense(node, :expression)
end
end
end
end
end
END

cop_path = "lib/rubocop/cop/#{to_snake(cop_name)}.rb"
File.write(cop_path, cop_code)

spec_code = <<-END
# encoding: utf-8
# frozen_string_literal: true

require 'spec_helper'

describe RuboCop::Cop::#{category}::#{name} do
let(:config) { RuboCop::Config.new }
subject(:cop) { described_class.new(config) }

# TODO: Write test code
#
# For example
it 'registers an offense for offending code' do
inspect_source(cop, 'bad_method')
expect(cop.offenses.size).to eq(1)
expect(cop.messages)
.to eq(['Message of #{cop_name}'])
end

it 'accepts' do
inspect_source(cop, 'good_method')
expect(cop.offenses).to be_empty
end
end
END

spec_path = "spec/rubocop/cop/#{to_snake(cop_name)}_spec.rb"
File.write(spec_path, spec_code)

puts <<-END
created
- #{cop_path}
- #{spec_path}

Do 4 steps
- Add an entry to `New feature` section in CHANGELOG.md
- e.g. Add new `#{cop_name}` cop. ([@your_id][])
- Add `require '#{cop_path.gsub(/\.rb$/, '')}'` into lib/rubocop.rb
- Add an entry into config/enabled.yml or config/disabled.yml
- Implement a new cop to the generated file!
END
end