Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement cop disabling #36

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 5 additions & 12 deletions lib/rubocop/markdown/preprocess.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,29 +56,22 @@ def initialize(file)
@config = Markdown.config_store.for(file)
end

# rubocop:disable Metrics/MethodLength
def call(src)
src.gsub(MD_REGEXP) do |full_match|
m = Regexp.last_match
open_backticks = m[1]
syntax = m[2]
code = m[3]
close_backticks = m[4]
markdown = m[5]
open_backticks, syntax, code, close_backticks, markdown = Regexp.last_match.captures

if markdown
# We got markdown outside of a codeblock
comment_lines(markdown)
mark_lines(markdown)
elsif ruby_codeblock?(syntax, code)
# The codeblock we parsed is assumed ruby, keep as is and append markers to backticks
"#{comment_lines(open_backticks + syntax)}\n#{code}#{comment_lines(close_backticks)}"
"#{mark_lines(open_backticks + syntax)}\n#{code}#{mark_lines(close_backticks)}"
else
# The codeblock is not relevant, comment it out
comment_lines(full_match)
mark_lines(full_match)
end
end
end
# rubocop:enable Metrics/MethodLength

private

Expand Down Expand Up @@ -117,7 +110,7 @@ def autodetect?
config["Markdown"]&.fetch("Autodetect", true)
end

def comment_lines(src)
def mark_lines(src)
src.gsub(/^/, "##{MARKER}")
end
end
Expand Down
16 changes: 15 additions & 1 deletion lib/rubocop/markdown/rubocop_ext.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ module Markdown # :nodoc:
# A list of cops that could produce offenses in commented lines
MARKDOWN_OFFENSE_COPS = %w[Lint/Syntax].freeze

DIRECTIVE_COMMENT_REGEXP = /
(<span\s+style="display:none;">)?
#{RuboCop::DirectiveComment::DIRECTIVE_COMMENT_REGEXP}
(<\/span>)?
/x.freeze

class << self
attr_accessor :config_store

Expand Down Expand Up @@ -79,10 +85,11 @@ def file_finished(file, offenses)
def offenses
@offenses ||= begin
marker_comment = "##{RuboCop::Markdown::Preprocess::MARKER}"

offenses_per_cop.flatten(1).reject do |offense|
next if RuboCop::Markdown::MARKDOWN_OFFENSE_COPS.include?(offense.cop_name)

offense.location.source_line.start_with?(marker_comment)
offense.disabled? || offense.location.source_line.start_with?(marker_comment)
end
end
end
Expand All @@ -104,3 +111,10 @@ def parse(src, *args)
super(src, *args)
end
end)

# Treat span'ed comments as the range comments, not single line comments
RuboCop::DirectiveComment.prepend(Module.new do
def single_line?
!comment.text.match?(RuboCop::Markdown::DIRECTIVE_COMMENT_REGEXP)
end
end)
95 changes: 95 additions & 0 deletions test/offense_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -366,4 +366,99 @@ class Person < ApplicationRecord
That's it.
MARKDOWN
end

def test_snippets_with_disabled_cops
assert_offense(<<~MARKDOWN)
All cops disabled

<span style="display:none;"># rubocop:disable all</span>
```ruby
def blank_method
end
```
<span style="display:none;"># rubocop:enable all</span>

All cops disabled as todos

<span style="display:none;"># rubocop:todo all</span>
```ruby
def blank_method
end
```
<span style="display:none;"># rubocop:enable all</span>

Cops disabled explicitly

<span style="display:none;"># rubocop:disable Style/EmptyMethod, Style/ArrayJoin</span>
```ruby
def blank_method
end

%w[foo bar baz] * ","
```
<span style="display:none;"># rubocop:enable Style/EmptyMethod, Style/ArrayJoin</span>

Cops disabled inside Ruby block

```ruby
# rubocop:disable all
def blank_method
end
# rubocop:enable all
```

Actually failing cop (correctable)

```ruby
%w[foo bar baz] * ","
^ Style/ArrayJoin: Favor `Array#join` over `Array#*`.
```
MARKDOWN

assert_correction(<<~MARKDOWN)
All cops disabled

<span style="display:none;"># rubocop:disable all</span>
```ruby
def blank_method
end
```
<span style="display:none;"># rubocop:enable all</span>

All cops disabled as todos

<span style="display:none;"># rubocop:todo all</span>
```ruby
def blank_method
end
```
<span style="display:none;"># rubocop:enable all</span>

Cops disabled explicitly

<span style="display:none;"># rubocop:disable Style/EmptyMethod, Style/ArrayJoin</span>
```ruby
def blank_method
end

%w[foo bar baz] * ","
```
<span style="display:none;"># rubocop:enable Style/EmptyMethod, Style/ArrayJoin</span>

Cops disabled inside Ruby block

```ruby
# rubocop:disable all
def blank_method
end
# rubocop:enable all
```

Actually failing cop (correctable)

```ruby
%w[foo bar baz].join(",")
```
MARKDOWN
end
end
84 changes: 84 additions & 0 deletions test/preprocess_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -274,4 +274,88 @@ def test_snippet_with_unclosed_backtick

assert_equal expected, subject(warn_invalid: true).call(source)
end

def test_snippets_with_disabled_cops
source = <<~SOURCE
All cops disabled

<span style="display:none;"># rubocop:disable all</span>
```ruby
def blank_method
end
```
<span style="display:none;"># rubocop:enable all</span>

All cops disabled as todos

<span style="display:none;"># rubocop:todo all</span>
```ruby
def blank_method
end
```
<span style="display:none;"># rubocop:enable all</span>

Cops disabled explicitly

<span style="display:none;"># rubocop:disable Style/EmptyMethod, Style/ArrayJoin</span>
```ruby
def blank_method
end

%w[foo bar baz] * ","
```
<span style="display:none;"># rubocop:enable Style/EmptyMethod, Style/ArrayJoin</span>

Cops disabled inside Ruby block

```ruby
# rubocop:disable all
def blank_method
end
# rubocop:enable all
```
SOURCE

expected = <<~SOURCE
#<--rubocop/md-->All cops disabled
#<--rubocop/md-->
#<--rubocop/md--><span style="display:none;"># rubocop:disable all</span>
#<--rubocop/md-->```ruby
def blank_method
end
#<--rubocop/md-->```
#<--rubocop/md--><span style="display:none;"># rubocop:enable all</span>
#<--rubocop/md-->
#<--rubocop/md-->All cops disabled as todos
#<--rubocop/md-->
#<--rubocop/md--><span style="display:none;"># rubocop:todo all</span>
#<--rubocop/md-->```ruby
def blank_method
end
#<--rubocop/md-->```
#<--rubocop/md--><span style="display:none;"># rubocop:enable all</span>
#<--rubocop/md-->
#<--rubocop/md-->Cops disabled explicitly
#<--rubocop/md-->
#<--rubocop/md--><span style="display:none;"># rubocop:disable Style/EmptyMethod, Style/ArrayJoin</span>
#<--rubocop/md-->```ruby
def blank_method
end

%w[foo bar baz] * ","
#<--rubocop/md-->```
#<--rubocop/md--><span style="display:none;"># rubocop:enable Style/EmptyMethod, Style/ArrayJoin</span>
#<--rubocop/md-->
#<--rubocop/md-->Cops disabled inside Ruby block
#<--rubocop/md-->
#<--rubocop/md-->```ruby
# rubocop:disable all
def blank_method
end
# rubocop:enable all
#<--rubocop/md-->```
SOURCE

assert_equal expected, subject.call(source)
end
end