diff --git a/CHANGELOG.md b/CHANGELOG.md index d8e8b6ae2364..b453b548e018 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,10 @@ ## master (unreleased) +### New features + * New cop `FileName` makes sure that source files have snake_case names. ([@bbatsov][]) +* [#743](https://github.com/bbatsov/rubocop/issues/743): `SingleLineMethods` cop does auto-correction. ([@jonas054][]) ### Changes diff --git a/lib/rubocop/cop/style/single_line_methods.rb b/lib/rubocop/cop/style/single_line_methods.rb index 78fe4411b882..e39588b890c1 100644 --- a/lib/rubocop/cop/style/single_line_methods.rb +++ b/lib/rubocop/cop/style/single_line_methods.rb @@ -23,9 +23,46 @@ def check(node, _method_name, _args, body) empty_body = body.nil? if start_line == end_line && !(allow_empty? && empty_body) + @body = body add_offence(node, :expression) end end + + def autocorrect(node) + body = @body + eol_comment = processed_source.comments.find do |c| + c.loc.line == node.loc.expression.line + end + @corrections << lambda do |corrector| + if body.type == :begin + body.children.each do |part| + break_line_before(part.loc.expression, node, corrector, 1) + end + else + break_line_before(body.loc.expression, node, corrector, 1) + end + + break_line_before(node.loc.end, node, corrector, 0) + + move_comment(eol_comment, node, corrector) if eol_comment + end + end + + def break_line_before(range, node, corrector, indent_steps) + corrector.insert_before(range, + "\n" + ' ' * (node.loc.keyword.column + + indent_steps * + IndentationWidth:: + CORRECT_INDENTATION)) + end + + def move_comment(eol_comment, node, corrector) + text = eol_comment.loc.expression.source + corrector.insert_before(node.loc.expression, + text + "\n" + + ' ' * node.loc.keyword.column) + corrector.remove(eol_comment.loc.expression) + end end end end diff --git a/spec/rubocop/cli_spec.rb b/spec/rubocop/cli_spec.rb index 87a574e15222..054d3a01f20a 100644 --- a/spec/rubocop/cli_spec.rb +++ b/spec/rubocop/cli_spec.rb @@ -48,6 +48,33 @@ def abs(path) 'end'].join("\n") + "\n") end + it 'can correct single line methods' do + create_file('example.rb', ['# encoding: utf-8', + 'def func1; do_something end # comment', + 'def func2() do_1; do_2; end']) + expect(cli.run(%w(--auto-correct --format offences))).to eq(1) + expect(IO.read('example.rb')).to eq(['# encoding: utf-8', + '# comment', + 'def func1;', + ' do_something', + 'end', + 'def func2', + ' do_1;', + ' do_2;', + 'end', + ''].join("\n")) + expect($stdout.string).to eq(['', + '6 TrailingWhitespace', + '4 Semicolon', + '2 EmptyLineBetweenDefs', + '2 SingleLineMethods', + '1 DefWithParentheses', + '--', + '15 Total', + '', + ''].join("\n")) + end + # In this example, the auto-correction (changing "raise" to "fail") # creates a new problem (alignment of parameters), which is also # corrected automatically. diff --git a/spec/rubocop/cop/style/single_line_methods_spec.rb b/spec/rubocop/cop/style/single_line_methods_spec.rb index 17dda818120e..bfe74d780b5a 100644 --- a/spec/rubocop/cop/style/single_line_methods_spec.rb +++ b/spec/rubocop/cop/style/single_line_methods_spec.rb @@ -49,4 +49,42 @@ 'end']) expect(cop.offences).to be_empty end + + it 'auto-corrects def with semicolon after method name' do + corrected = autocorrect_source(cop, + [' def some_method; body end # Cmnt']) + expect(corrected).to eq [' # Cmnt', + ' def some_method; ', + ' body ', + ' end '].join("\n") + end + + it 'auto-corrects defs with parentheses after method name' do + corrected = autocorrect_source(cop, [' def self.some_method() body end']) + expect(corrected).to eq [' def self.some_method() ', + ' body ', + ' end'].join("\n") + end + + it 'auto-corrects def with argument in parentheses' do + corrected = autocorrect_source(cop, [' def some_method(arg) body end']) + expect(corrected).to eq [' def some_method(arg) ', + ' body ', + ' end'].join("\n") + end + + it 'auto-corrects def with argument and no parentheses' do + corrected = autocorrect_source(cop, [' def some_method arg; body end']) + expect(corrected).to eq [' def some_method arg; ', + ' body ', + ' end'].join("\n") + end + + it 'auto-corrects def with semicolon before end' do + corrected = autocorrect_source(cop, [' def some_method; b1; b2; end']) + expect(corrected).to eq [' def some_method; ', + ' b1; ', + ' b2; ', + ' end'].join("\n") + end end