Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[Fix #3167] Add VariableNumber cop (#3416)
  • Loading branch information
sooyang authored and bbatsov committed Aug 20, 2016
1 parent 344156a commit af0bc67
Show file tree
Hide file tree
Showing 8 changed files with 422 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -8,6 +8,7 @@
* [#3360](https://github.com/bbatsov/rubocop/issues/3360): Add `RequireForNonPublicMethods` configuration option to `Style/DocumentationMethod` cop. ([@drenmi][])
* Add new `Rails/SafeNavigation` cop to convert `try!` to `&.`. ([@rrosenblum][])
* [#3415](https://github.com/bbatsov/rubocop/pull/3415): Add new `Rails/NotNullColumn` cop. ([@pocke][])
* [#3167](https://github.com/bbatsov/rubocop/issues/3167): Add new `Style/VariableNumber` cop. ([@sooyang][])

### Bug fixes

Expand Down
7 changes: 7 additions & 0 deletions config/default.yml
Expand Up @@ -1048,6 +1048,13 @@ Style/VariableName:
- snake_case
- camelCase

Style/VariableNumber:
EnforcedStyle: normalcase
SupportedStyles:
- snake_case
- normalcase
- non_integer

Style/WhileUntilModifier:
MaxLineLength: 80

Expand Down
4 changes: 4 additions & 0 deletions config/enabled.yml
Expand Up @@ -912,6 +912,10 @@ Style/VariableName:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#snake-case-symbols-methods-vars'
Enabled: true

Style/VariableNumber:
Description: 'Use the configured style when numbering variables.'
Enabled: true

Style/WhenThen:
Description: 'Use when x then ... for one-line cases.'
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#one-line-cases'
Expand Down
2 changes: 2 additions & 0 deletions lib/rubocop.rb
Expand Up @@ -56,6 +56,7 @@
require 'rubocop/cop/mixin/classish_length' # relies on code_length
require 'rubocop/cop/mixin/configurable_enforced_style'
require 'rubocop/cop/mixin/configurable_naming'
require 'rubocop/cop/mixin/configurable_numbering'
require 'rubocop/cop/mixin/def_node'
require 'rubocop/cop/mixin/documentation_comment'
require 'rubocop/cop/mixin/empty_lines_around_body'
Expand Down Expand Up @@ -371,6 +372,7 @@
require 'rubocop/cop/style/unneeded_percent_q'
require 'rubocop/cop/style/variable_interpolation'
require 'rubocop/cop/style/variable_name'
require 'rubocop/cop/style/variable_number'
require 'rubocop/cop/style/when_then'
require 'rubocop/cop/style/while_until_do'
require 'rubocop/cop/style/while_until_modifier'
Expand Down
52 changes: 52 additions & 0 deletions lib/rubocop/cop/mixin/configurable_numbering.rb
@@ -0,0 +1,52 @@
# encoding: utf-8
# frozen_string_literal: true

module RuboCop
module Cop
# This module provides functionality for checking if numbering match the
# configured EnforcedStyle.
module ConfigurableNumbering
include ConfigurableEnforcedStyle

SNAKE_CASE = /^@{0,2}[-_a-z]+[_\D]*(_\d)*[!?=]?$/
NORMAL_CASE = /^@{0,2}-{0,1}_{0,1}[a-zA-Z\d]*[_\D]*[!?=]?$/
NON_INTEGER = /^@{0,2}[-_a-z]+[_\D]*[!?=]?$/

def check_name(node, name, name_range)
return if operator?(name)

if valid_name?(node, name)
correct_style_detected
else
add_offense(node, name_range, message(style))
end
end

def valid_name?(node, name)
pattern =
case style
when :snake_case
SNAKE_CASE
when :normalcase
NORMAL_CASE
when :non_integer
NON_INTEGER
end
name.match(pattern) || class_emitter_method?(node, name)
end

# A class emitter method is a singleton method in a class/module, where
# the method has the same name as a class defined in the class/module.
def class_emitter_method?(node, name)
return false unless node.parent && node.defs_type?
# a class emitter method may be defined inside `def self.included`,
# `def self.extended`, etc.
node = node.parent while node.parent.defs_type?

node.parent.each_child_node(:class).any? do |c|
c.loc.name.is?(name.to_s)
end
end
end
end
end
6 changes: 3 additions & 3 deletions lib/rubocop/cop/style/braces_around_hash_parameters.rb
Expand Up @@ -39,13 +39,13 @@ def check(arg, args)
end

def check_context_dependent(arg, args)
braces_around_2nd_from_end = args.length > 1 && args[-2].hash_type?
braces_around_second_from_end = args.length > 1 && args[-2].hash_type?
if braces?(arg)
unless braces_around_2nd_from_end
unless braces_around_second_from_end
add_offense(arg.parent, arg.source_range,
format(MSG, 'Redundant'))
end
elsif braces_around_2nd_from_end
elsif braces_around_second_from_end
add_offense(arg.parent, arg.source_range, format(MSG, 'Missing'))
end
end
Expand Down
79 changes: 79 additions & 0 deletions lib/rubocop/cop/style/variable_number.rb
@@ -0,0 +1,79 @@
# encoding: utf-8
# frozen_string_literal: true

module RuboCop
module Cop
module Style
# This cop makes sure that all numbered variables use the
# configured style, snake_case, normalcase or non_integer,
# for their numbering.
#
# @example
# "EnforcedStyle => 'snake_case'"
#
# # bad
#
# variable1 = 1
#
# # good
#
# variable_1 = 1
#
# @example
# "EnforcedStyle => 'normalcase'"
#
# # bad
#
# variable_1 = 1
#
# # good
#
# variable1 = 1
#
# @example
# "EnforcedStyle => 'non_integer'"
#
# #bad
#
# variable1 = 1
#
# variable_1 = 1
#
# #good
#
# variableone = 1
#
# variable_one = 1
#
class VariableNumber < Cop
include ConfigurableNumbering

def on_lvasgn(node)
name, = *node
check_name(node, name, node.loc.name)
end

def on_ivasgn(node)
name, = *node
check_name(node, name, node.loc.name)
end

def on_cvasgn(node)
name, = *node
check_name(node, name, node.loc.name)
end

def on_arg(node)
name, = *node
check_name(node, name, node.loc.name)
end

private

def message(style)
format('Use %s for variable numbers.', style)
end
end
end
end
end

0 comments on commit af0bc67

Please sign in to comment.