Skip to content

Commit 43a2322

Browse files
committed
Merge pull request m4i#19 from nicollis/master
Added auto correct with -a flag
2 parents e996dd6 + 0d1dc2b commit 43a2322

File tree

6 files changed

+136
-2
lines changed

6 files changed

+136
-2
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Or install it yourself as:
2525
Usage: rubocop-git [options] [[commit] commit]
2626
-c, --config FILE Specify configuration file
2727
-r, --require FILE Require Ruby file
28+
-a, --auto-correct Auto-correct offenses
2829
-d, --debug Display debug info
2930
-D, --display-cop-names Display cop names in offense messages
3031
--cached git diff --cached

lib/rubocop/git.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
require 'rubocop/git/version'
22
require 'rubocop'
3+
require 'tempfile'
4+
require 'fileutils'
35

46
module RuboCop
57
module Git
@@ -15,5 +17,6 @@ module Git
1517
autoload :Runner, 'rubocop/git/runner'
1618
autoload :StyleChecker, 'rubocop/git/style_checker'
1719
autoload :StyleGuide, 'rubocop/git/style_guide'
20+
autoload :RuboComment, 'rubocop/git/rubo_comment'
1821
end
1922
end

lib/rubocop/git/cli.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ def option_parser
3535
require file
3636
end
3737

38+
opt.on('-a', '--auto-correct', 'Auto-correct offenses.') do
39+
@options.rubocop[:auto_correct] = true
40+
end
41+
3842
opt.on('-d', '--debug', 'Display debug info') do
3943
@options.rubocop[:debug] = true
4044
end

lib/rubocop/git/patch.rb

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@ class Patch
44
RANGE_INFORMATION_LINE = /^@@ .+\+(?<line_number>\d+),/
55
MODIFIED_LINE = /^\+(?!\+|\+)/
66
NOT_REMOVED_LINE = /^[^-]/
7+
PATCH_INFO_LINE = /\+([0-9,]+)/
78

89
def initialize(body)
910
@body = body || ''
11+
@changes = []
1012
end
1113

1214
def additions
1315
line_number = 0
1416

15-
lines.each_with_index.inject([]) do |additions, (content, patch_position)|
17+
lines.each_with_index.inject(@changes) do |additions, (content, patch_position)|
1618
case content
1719
when RANGE_INFORMATION_LINE
1820
line_number = Regexp.last_match[:line_number].to_i
@@ -27,6 +29,31 @@ def additions
2729
end
2830
end
2931

32+
# maps out additions line numbers to indicate start and end of code changes
33+
# [[5,7], [11,11]] indicates changes from line 5, 6, 7 and then
34+
# another one at 11
35+
def additions_map
36+
if @changes.empty?
37+
self.additions
38+
end
39+
40+
map = []
41+
starting_line = ending_line = 0
42+
43+
@changes.each do |addition|
44+
if starting_line == 0
45+
starting_line = ending_line = addition.line_number
46+
elsif addition.line_number == ( ending_line + 1 )
47+
ending_line = addition.line_number
48+
else # this row is not part of the last rows "group"
49+
map.push([starting_line, ending_line])
50+
starting_line = ending_line = addition.line_number
51+
end
52+
end
53+
map.push([starting_line, ending_line])
54+
map
55+
end
56+
3057
private
3158

3259
def lines

lib/rubocop/git/rubo_comment.rb

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
module RuboCop::Git
2+
class RuboComment
3+
RUBOCOP_DISABLE = "# rubocop:disable all\n"
4+
RUBOCOP_ENABLE = "# rubocop:enable all\n"
5+
WHITE_SPACE = /^\s*/
6+
7+
def initialize(files)
8+
@edit_map = {}
9+
@files = files
10+
end
11+
12+
# adds rubocop enable and disabled comments to files
13+
# making sure only edited lines are processed by rubocop
14+
def add_comments
15+
@files.each do |file|
16+
patch_info = Patch.new(file.patch).additions_map
17+
temp_file = Tempfile.new('temp')
18+
19+
line_count = edited_line_count = current_patch = 0
20+
in_patch = false
21+
edit_locations = []
22+
23+
begin
24+
File.open(file.filename, "r").each_line do |line|
25+
line_count += 1
26+
edited_line_count += 1
27+
28+
if line_count == patch_info[current_patch].first
29+
temp_file.puts generate_spaces(line) + RUBOCOP_ENABLE
30+
in_patch = true
31+
edit_locations.push edited_line_count
32+
edited_line_count += 1
33+
34+
elsif in_patch && patch_info[current_patch].last + 1 == line_count
35+
temp_file.puts generate_spaces(line) + RUBOCOP_DISABLE
36+
in_patch = false
37+
edit_locations.push edited_line_count
38+
edited_line_count += 1
39+
current_patch += 1 unless (current_patch + 1) >= patch_info.size
40+
41+
elsif line_count == 1 #adds disable at top of file
42+
temp_file.puts generate_spaces(line) + RUBOCOP_DISABLE
43+
edit_locations.push edited_line_count
44+
edited_line_count += 1
45+
46+
end
47+
temp_file.puts line
48+
end
49+
50+
temp_file.close
51+
FileUtils.mv(temp_file.path, file.filename)
52+
@edit_map[file.filename] = edit_locations
53+
ensure
54+
temp_file.close
55+
temp_file.unlink
56+
end
57+
end
58+
end
59+
60+
# removes all added comments that where added from add_comments
61+
def remove_comments
62+
@files.each do |file|
63+
temp_file = Tempfile.new('temp')
64+
line_count = 0
65+
66+
begin
67+
File.open(file.filename, "r").each_line do |line|
68+
line_count += 1
69+
temp_file.puts line unless @edit_map[file.filename].find_index line_count
70+
end
71+
72+
temp_file.close
73+
FileUtils.mv(temp_file.path, file.filename)
74+
ensure
75+
temp_file.close
76+
temp_file.unlink
77+
end
78+
end
79+
end
80+
81+
private
82+
83+
# generates whitespaces to make en/disable comments match line indent
84+
# preventing rubocop errors
85+
def generate_spaces(line)
86+
whitespaces = ""
87+
WHITE_SPACE.match(line).to_s.split('').size.times { whitespaces << " " }
88+
whitespaces
89+
end
90+
91+
end
92+
end

lib/rubocop/git/runner.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,15 @@ def run(options)
99

1010
@options = options
1111
@files = DiffParser.parse(git_diff(options))
12+
rubo_comment = RuboComment.new(@files)
13+
14+
#adds comments to files and reparses diff after changes are made
15+
rubo_comment.add_comments
16+
@files = DiffParser.parse(git_diff(options))
1217

1318
display_violations($stdout)
19+
#removes comments after rubocop processing
20+
rubo_comment.remove_comments
1421

1522
exit(1) if violations.any?
1623
end
@@ -45,7 +52,7 @@ def git_diff(options)
4552
def display_violations(io)
4653
formatter = RuboCop::Formatter::ClangStyleFormatter.new(io)
4754
formatter.started(nil)
48-
55+
4956
violations.map do |violation|
5057
offenses = violation.offenses
5158
offenses = offenses.reject(&:disabled?) if offenses.first.respond_to?(:disabled?)

0 commit comments

Comments
 (0)