Skip to content

Commit

Permalink
[Fix rubocop#3666] Add new Uncommunicative MethodArg & BlockParam cops
Browse files Browse the repository at this point in the history
  • Loading branch information
garettarrowood committed Dec 28, 2017
1 parent 150be51 commit 3f65be3
Show file tree
Hide file tree
Showing 11 changed files with 455 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

### New features

* [#3666](https://github.com/bbatsov/rubocop/issues/3666): Add new `Naming/UncommunicativeBlockParamName` cop. ([@garettarrowood][])
* [#3666](https://github.com/bbatsov/rubocop/issues/3666): Add new `Naming/UncommunicativeMethodArgName` cop. ([@garettarrowood][])
* [#5248](https://github.com/bbatsov/rubocop/pull/5248): Add new `Lint/BigDecimalNew` cop. ([@koic][])
* [#3394](https://github.com/bbatsov/rubocop/issues/3394): Add new `Style/TrailingCommmaInArrayLiteral` cop. ([@garettarrowood][])
* [#3394](https://github.com/bbatsov/rubocop/issues/3394): Add new `Style/TrailingCommmaInHashLiteral` cop. ([@garettarrowood][])
Expand Down
9 changes: 9 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,15 @@ Naming/PredicateName:
Exclude:
- 'spec/**/*'

Naming/UncommunicativeBlockParamName:
# Parameter names may be equal to or greater than this value
MinParamNameLength: 1

Naming/UncommunicativeMethodArgName:
# Argrument names may be equal to or greater than this value
MinArgNameLength: 3


Naming/VariableName:
EnforcedStyle: snake_case
SupportedStyles:
Expand Down
12 changes: 12 additions & 0 deletions config/disabled.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ Layout/MultilineAssignmentLayout:
StyleGuide: '#indent-conditional-assignment'
Enabled: false

Naming/UncommunicativeBlockParamName:
Description: >-
Checks for block parameter names that contain capital letters,
end in numbers, or do not meet a minimal length.
Enabled: false

Naming/UncommunicativeMethodArgName:
Description: >-
Checks for method argument names that contain capital letters,
end in numbers, or do not meet a minimal length.
Enabled: false

# By default, the rails cops are not run. Override in project or home
# directory .rubocop.yml files, or by giving the -R/--rails option.
Rails:
Expand Down
3 changes: 3 additions & 0 deletions lib/rubocop.rb
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
require_relative 'rubocop/cop/mixin/target_rails_version'
require_relative 'rubocop/cop/mixin/too_many_lines'
require_relative 'rubocop/cop/mixin/trailing_comma'
require_relative 'rubocop/cop/mixin/uncommunicative_name'
require_relative 'rubocop/cop/mixin/unused_argument'

require_relative 'rubocop/cop/correctors/alignment_corrector'
Expand Down Expand Up @@ -330,6 +331,8 @@
require_relative 'rubocop/cop/naming/method_name'
require_relative 'rubocop/cop/naming/binary_operator_parameter_name'
require_relative 'rubocop/cop/naming/predicate_name'
require_relative 'rubocop/cop/naming/uncommunicative_block_param_name'
require_relative 'rubocop/cop/naming/uncommunicative_method_arg_name'
require_relative 'rubocop/cop/naming/variable_name'
require_relative 'rubocop/cop/naming/variable_number'

Expand Down
68 changes: 68 additions & 0 deletions lib/rubocop/cop/mixin/uncommunicative_name.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# frozen_string_literal: true

module RuboCop
module Cop
# Common functionality shared by Uncommunicative cops
module UncommunicativeName
CASE_MSG = 'Only use lowercase characters for %<name_type>s.'.freeze
NUM_MSG = 'Do not end %<name_type>s with a number.'.freeze
LENGTH_MSG = '%<name_type>s must be longer than %<min>s ' \
'characters.'.freeze

def check(node, args, min:)
args.each do |arg|
source = arg.children.first.to_s
range = arg_range(arg, source.size)
case_offense(node, range) if uppercase?(source)
num_offense(node, range) if ends_with_num?(source)
length_offense(node, range, min) unless long_enough?(source, min)
end
end

def case_offense(node, range)
add_offense(node, location: range,
message: format(CASE_MSG, name_type: name_type(node)))
end

def uppercase?(name)
name =~ /[[:upper:]]/
end

def name_type(node)
@name_type ||= begin
case node.type
when :block then 'block parameter'
when :def, :defs then 'method argument'
end
end
end

def num_offense(node, range)
add_offense(node, location: range,
message: format(NUM_MSG, name_type: name_type(node)))
end

def ends_with_num?(name)
name[-1] =~ /\d/
end

def length_offense(node, range, min)
add_offense(node, location: range,
message: format(LENGTH_MSG,
name_type: name_type(node).capitalize,
min: min))
end

def long_enough?(name, min)
name.size >= min
end

def arg_range(arg, length)
begin_pos = arg.source_range.begin_pos
Parser::Source::Range.new(processed_source.buffer,
begin_pos,
begin_pos + length)
end
end
end
end
44 changes: 44 additions & 0 deletions lib/rubocop/cop/naming/uncommunicative_block_param_name.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Naming
# This cop makes sure block parameter names meet a configurable
# level of description
#
# @example
# # bad
# foo { |num1, num2| num1 + num2 }
#
# bar do |varOne, varTwo|
# varOne + varTwo
# end
#
# # With `MinParamNameLength` set to number greater than 1
# baz { |x, y, z| do_stuff(x, y, z) }
#
# # good
# foo { |first_num, second_num| first_num + second_num }
#
# bar do |var_one, var_two|
# var_one + var_two
# end
#
# baz { |age, height, gender| do_stuff(age, height, gender) }
class UncommunicativeBlockParamName < Cop
include UncommunicativeName

def on_block(node)
return unless node.arguments?
check(node, node.arguments, min: min_length)
end

private

def min_length
cop_config['MinParamNameLength']
end
end
end
end
end
52 changes: 52 additions & 0 deletions lib/rubocop/cop/naming/uncommunicative_method_arg_name.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Naming
# This cop makes sure method argument names meet a configurable
# level of description
# @example
# # bad
# def foo(num1, num2)
# num1 + num2
# end
#
# def bar(varOne, varTwo)
# varOne + varTwo
# end
#
# # With `MinArgNameLength` set to number greater than 1
# def baz(x, y, z)
# do_stuff(x, y, z)
# end
#
# # good
# def foo(first_num, second_num)
# first_num + second_num
# end
#
# def bar(var_one, var_two)
# var_one + var_two
# end
#
# def baz(age_x, height_y, gender_z)
# do_stuff(age_x, height_y, gender_z)
# end
class UncommunicativeMethodArgName < Cop
include UncommunicativeName

def on_def(node)
return unless node.arguments?
check(node, node.arguments, min: min_length)
end
alias on_defs on_def

private

def min_length
cop_config['MinArgNameLength']
end
end
end
end
end
2 changes: 2 additions & 0 deletions manual/cops.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,8 @@ In the following section you find all available cops:
* [Naming/HeredocDelimiterNaming](cops_naming.md#namingheredocdelimiternaming)
* [Naming/MethodName](cops_naming.md#namingmethodname)
* [Naming/PredicateName](cops_naming.md#namingpredicatename)
* [Naming/UncommunicativeBlockParamName](cops_naming.md#naminguncommunicativeblockparamname)
* [Naming/UncommunicativeMethodArgName](cops_naming.md#naminguncommunicativemethodargname)
* [Naming/VariableName](cops_naming.md#namingvariablename)
* [Naming/VariableNumber](cops_naming.md#namingvariablenumber)

Expand Down
84 changes: 84 additions & 0 deletions manual/cops_naming.md
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,90 @@ Exclude | `spec/**/*` | Array
* [https://github.com/bbatsov/ruby-style-guide#bool-methods-qmark](https://github.com/bbatsov/ruby-style-guide#bool-methods-qmark)
## Naming/UncommunicativeBlockParamName
Enabled by default | Supports autocorrection
--- | ---
Disabled | No
This cop makes sure block parameter names meet a configurable
level of description
### Examples
```ruby
# bad
foo { |num1, num2| num1 + num2 }

bar do |varOne, varTwo|
varOne + varTwo
end

# With `MinParamNameLength` set to number greater than 1
baz { |x, y, z| do_stuff(x, y, z) }

# good
foo { |first_num, second_num| first_num + second_num }

bar do |var_one, var_two|
var_one + var_two
end

baz { |age, height, gender| do_stuff(age, height, gender) }
```
### Configurable attributes
Name | Default value | Configurable values
--- | --- | ---
MinParamNameLength | `1` | Integer
## Naming/UncommunicativeMethodArgName
Enabled by default | Supports autocorrection
--- | ---
Disabled | No
This cop makes sure method argument names meet a configurable
level of description
### Examples
```ruby
# bad
def foo(num1, num2)
num1 + num2
end

def bar(varOne, varTwo)
varOne + varTwo
end

# With `MinArgNameLength` set to number greater than 1
def baz(x, y, z)
do_stuff(x, y, z)
end

# good
def foo(first_num, second_num)
first_num + second_num
end

def bar(var_one, var_two)
var_one + var_two
end

def baz(age_x, height_y, gender_z)
do_stuff(age_x, height_y, gender_z)
end
```

### Configurable attributes

Name | Default value | Configurable values
--- | --- | ---
MinArgNameLength | `3` | Integer

## Naming/VariableName

Enabled by default | Supports autocorrection
Expand Down
64 changes: 64 additions & 0 deletions spec/rubocop/cop/naming/uncommunicative_block_param_name_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# frozen_string_literal: true

describe RuboCop::Cop::Naming::UncommunicativeBlockParamName, :config do
subject(:cop) { described_class.new(config) }

let(:cop_config) { { 'MinParamNameLength' => 2 } }

it 'does not register for block without parameters' do
expect_no_offenses(<<-RUBY.strip_indent)
something do
do_stuff
end
RUBY
end

it 'does not register for brace block without parameters' do
expect_no_offenses(<<-RUBY.strip_indent)
something { do_stuff }
RUBY
end

it 'does not register offense for valid parameter names' do
expect_no_offenses(<<-RUBY.strip_indent)
something { |foo, bar| do_stuff }
RUBY
end

it 'registers offense when param ends in number' do
expect_offense(<<-RUBY.strip_indent)
something { |foo1, bar| do_stuff }
^^^^ Do not end block parameter with a number.
RUBY
end

it 'registers offense when param is less than minimum length' do
expect_offense(<<-RUBY.strip_indent)
something do |x|
^ Block parameter must be longer than 2 characters.
do_stuff
end
RUBY
end

it 'registers offense when param contains uppercase characters' do
expect_offense(<<-RUBY.strip_indent)
something { |number_One| do_stuff }
^^^^^^^^^^ Only use lowercase characters for block parameter.
RUBY
end

it 'can register multiple offenses in one block' do
inspect_source(<<-RUBY.strip_indent)
something do |y, num1, oFo|
do_stuff
end
RUBY
expect(cop.offenses.size).to eq(3)
expect(cop.messages).to eq [
'Block parameter must be longer than 2 characters.',
'Do not end block parameter with a number.',
'Only use lowercase characters for block parameter.'
]
end
end
Loading

0 comments on commit 3f65be3

Please sign in to comment.