Skip to content

Commit

Permalink
New cop Style/FirstParameterIndentation
Browse files Browse the repository at this point in the history
Add a cop that checks the indentation of the first parameter
in a method call. Part of solution for rubocop#1144.
  • Loading branch information
jonas054 committed Feb 1, 2015
1 parent 9c01850 commit 5526f81
Show file tree
Hide file tree
Showing 8 changed files with 352 additions and 15 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* Add autocorrect to `RedundantException`. ([@mattjmcnaughton][])
* [#1571](https://github.com/bbatsov/rubocop/pull/1571): New cop `StructInheritance` checks for inheritance from Struct.new. ([@mmozuras][])
* [#1575](https://github.com/bbatsov/rubocop/issues/1575): New cop `DuplicateMethods` points out duplicate method name in class and module. ([@d4rk5eed][])
* [#1144](https://github.com/bbatsov/rubocop/issues/1144): New cop `FirstParameterIndentation` checks the indentation of the first parameter in a method call. ([@jonas054][])

### Changes

Expand All @@ -23,7 +24,6 @@
* [#1565](https://github.com/bbatsov/rubocop/issues/1565): Let `--fail-level A` cause exit with error if all offenses are auto-corrected. ([@jonas054][])
* [#1309](https://github.com/bbatsov/rubocop/issues/1309): Add argument handling to `MultilineBlockLayout`. ([@lumeet][])


### Bugs fixed

* [#1553](https://github.com/bbatsov/rubocop/pull/1553): Fix bug where `Style/EmptyLinesAroundAccessModifier` interfered with `Style/EmptyLinesAroundBlockBody` when there is and access modifier at the beginning of a block. ([@volkert][])
Expand Down
15 changes: 15 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,21 @@ Style/FileName:
# excludes here.
Exclude: []

Style/FirstParameterIndentation:
EnforcedStyle: special_for_inner_method_call_in_parentheses
SupportedStyles:
# The first parameter should always be indented one step more than the
# preceding line.
- consistent
# The first parameter should normally be indented one step more than the
# preceding line, but if it's a parameter for a method call that is itself
# a parameter in a method call, then the inner parameter should be indented
# relative to the inner method.
- special_for_inner_method_call
# Same as special_for_inner_method_call except that the special rule only
# applies if the outer method call encloses its arguments in parentheses.
- special_for_inner_method_call_in_parentheses

# Checks use of for or each in multiline loops.
Style/For:
EnforcedStyle: each
Expand Down
4 changes: 4 additions & 0 deletions config/enabled.yml
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,10 @@ Style/FileName:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#snake-case-files'
Enabled: true

Style/FirstParameterIndentation:
Description: 'Checks the indentation of the first parameter in a method call.'
Enabled: true

Style/FlipFlop:
Description: 'Checks for flip flops'
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-flip-flops'
Expand Down
1 change: 1 addition & 0 deletions lib/rubocop.rb
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@
require 'rubocop/cop/style/even_odd'
require 'rubocop/cop/style/extra_spacing'
require 'rubocop/cop/style/file_name'
require 'rubocop/cop/style/first_parameter_indentation'
require 'rubocop/cop/style/flip_flop'
require 'rubocop/cop/style/for'
require 'rubocop/cop/style/format_string'
Expand Down
81 changes: 81 additions & 0 deletions lib/rubocop/cop/style/first_parameter_indentation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# encoding: utf-8

module RuboCop
module Cop
module Style
# This cop checks the indentation of the first parameter in a method call.
# Parameters after the first one are checked by Style/AlignParameters, not
# by this cop.
#
# @example
#
# # bad
# some_method(
# first_param,
# second_param)
#
# # good
# some_method(
# first_param,
# second_param)
class FirstParameterIndentation < Cop
include AutocorrectAlignment
include ConfigurableEnforcedStyle

def on_send(node)
_receiver, method_name, *args = *node
return if args.empty?
return if operator?(method_name)

base_indentation = if special_inner_call_indentation?(node)
base_range(node, args.first).column
else
node.loc.expression.source_line =~ /\S/
end
check_alignment([args.first],
base_indentation + configured_indentation_width)
end

private

def message(arg_node)
send_node = arg_node.parent
base = if special_inner_call_indentation?(send_node)
text = base_range(send_node, arg_node).source.strip
.sub(/\n.*/, '')
.chomp('(')
"`#{text}`"
else
'the previous line'
end
format('Indent the first parameter one step more than %s.', base)
end

def special_inner_call_indentation?(node)
return false if style == :consistent

parent = node.parent
return false unless parent
return false unless parent.send_type?

_receiver, method_name, *_args = *parent
# :[]= is a send node, but we want to treat it as an assignment.
return false if method_name == :[]=

return false if !parentheses?(parent) &&
style == :special_for_inner_method_call_in_parentheses

# The node must begin inside the parent, otherwise node is the first
# part of a chained method call.
node.loc.expression.begin_pos > parent.loc.expression.begin_pos
end

def base_range(send_node, arg_node)
Parser::Source::Range.new(processed_source.buffer,
send_node.loc.expression.begin_pos,
arg_node.loc.expression.begin_pos)
end
end
end
end
end
9 changes: 3 additions & 6 deletions spec/rubocop/cli_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1875,8 +1875,7 @@ def interrupt
])
expect(cli.run(['--format', 'emacs', 'example.rb'])).to eq(1)
expect($stdout.string)
.to eq(
["#{abs('example.rb')}:3:81: C: Line is too long. [95/80]",
.to eq(["#{abs('example.rb')}:3:81: C: Line is too long. [95/80]",
''].join("\n"))
end

Expand All @@ -1890,8 +1889,7 @@ def interrupt
])
expect(cli.run(['--format', 'emacs', 'example.rb'])).to eq(1)
expect($stdout.string)
.to eq(
["#{abs('example.rb')}:3:81: C: Line is too long. [95/80]",
.to eq(["#{abs('example.rb')}:3:81: C: Line is too long. [95/80]",
''].join("\n"))
end
end
Expand Down Expand Up @@ -2468,8 +2466,7 @@ def interrupt
' Max: 100'
])
expect(cli.run(%w(--format simple example))).to eq(1)
expect($stdout.string).to eq(
['== example/lib/example1.rb ==',
expect($stdout.string).to eq(['== example/lib/example1.rb ==',
'C: 2: 81: Line is too long. [90/80]',
'',
'2 files inspected, 1 offense detected',
Expand Down
Loading

0 comments on commit 5526f81

Please sign in to comment.