Skip to content

Commit

Permalink
Merge pull request #915 from rubocop-hq/cleanup-workaround
Browse files Browse the repository at this point in the history
Cleanup workaround
  • Loading branch information
bquorning committed Jun 1, 2020
2 parents 3254778 + dc5d6a0 commit a8d756a
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 75 deletions.
10 changes: 8 additions & 2 deletions bin/build_config
Expand Up @@ -9,9 +9,15 @@ require 'rubocop-rspec'
require 'rubocop/rspec/description_extractor'
require 'rubocop/rspec/config_formatter'

glob = File.join(__dir__, '..', 'lib', 'rubocop', 'cop', 'rspec',
glob = File.join('lib', 'rubocop', 'cop', 'rspec',
'{,capybara,factory_bot,rails}', '*.rb')
YARD.parse(Dir[glob], [])
# Due to YARD's sensitivity to file require order (as of 0.9.25),
# we have to prepend the list with our base cop, RuboCop::Cop::RSpec::Cop.
# Otherwise, cop's parent class for cops loaded before our base cop class
# are detected as RuboCop::Cop::Cop, and that complicates the detection
# of their relation with RuboCop RSpec.
rspec_cop_path = File.join('lib', 'rubocop', 'cop', 'rspec', 'cop.rb')
YARD.parse(Dir[glob].prepend(rspec_cop_path), [])

descriptions = RuboCop::RSpec::DescriptionExtractor.new(YARD::Registry.all).to_h
current_config = YAML.load_file('config/default.yml')
Expand Down
36 changes: 8 additions & 28 deletions lib/rubocop/cop/rspec/cop.rb
Expand Up @@ -2,42 +2,22 @@

module RuboCop
module Cop
WorkaroundCop = Cop.dup

# Clone of the the normal RuboCop::Cop::Cop class so we can rewrite
# the inherited method without breaking functionality
class WorkaroundCop
# Remove the Cop.inherited method to be a noop. Our RSpec::Cop
# class will invoke the inherited hook instead
class << self
undef inherited
def inherited(*) end
end

# Special case `Module#<` so that the rspec support rubocop exports
# is compatible with our subclass
def self.<(other)
other.equal?(RuboCop::Cop::Cop) || super
end
end
private_constant(:WorkaroundCop)

module RSpec
# @abstract parent class to rspec cops
# @abstract parent class to RSpec cops
#
# The criteria for whether rubocop-rspec analyzes a certain ruby file
# is configured via `AllCops/RSpec`. For example, if you want to
# customize your project to scan all files within a `test/` directory
# then you could add this to your configuration:
#
# @example configuring analyzed paths
#
# AllCops:
# RSpec:
# Patterns:
# - '_test.rb$'
# - '(?:^|/)test/'
class Cop < WorkaroundCop
# # .rubocop.yml
# # AllCops:
# # RSpec:
# # Patterns:
# # - '_test.rb$'
# # - '(?:^|/)test/'
class Cop < ::RuboCop::Cop::Cop
include RuboCop::RSpec::Language
include RuboCop::RSpec::Language::NodePattern

Expand Down
8 changes: 2 additions & 6 deletions lib/rubocop/rspec/description_extractor.rb
Expand Up @@ -21,7 +21,7 @@ def to_h

# Decorator of a YARD code object for working with documented rspec cops
class CodeObject
COP_CLASS_NAMES = %w[RuboCop::Cop RuboCop::Cop::RSpec::Cop].freeze
COP_CLASS_NAME = 'RuboCop::Cop::RSpec::Cop'
RSPEC_NAMESPACE = 'RuboCop::Cop::RSpec'

def initialize(yardoc)
Expand Down Expand Up @@ -68,11 +68,7 @@ def documented_constant
end

def cop_subclass?
# YARD superclass resolution is a bit flaky: All classes loaded before
# RuboCop::Cop::WorkaroundCop are shown as having RuboCop::Cop as
# superclass, while all the following classes are listed as having
# RuboCop::Cop::RSpec::Cop as their superclass.
COP_CLASS_NAMES.include?(yardoc.superclass.path)
yardoc.superclass.path == COP_CLASS_NAME
end

def abstract?
Expand Down
1 change: 0 additions & 1 deletion spec/rubocop/cop/rspec/cop_spec.rb
Expand Up @@ -20,7 +20,6 @@
end

let(:fake_cop) do
stub_const('RuboCop::RSpec', Module.new)
# rubocop:disable Style/ClassAndModuleChildren
# rubocop:disable RSpec/LeakyConstantDeclaration
class RuboCop::RSpec::FakeCop < described_class
Expand Down
16 changes: 12 additions & 4 deletions spec/rubocop/rspec/description_extractor_spec.rb
Expand Up @@ -42,11 +42,19 @@ def bar
YARD::Registry.all
end

let(:temp_class) do
temp = RuboCop::Cop::Cop.dup
temp.class_exec do
class << self
undef inherited
def inherited(*) end
end
end
temp
end

def stub_cop_const(name)
stub_const(
"RuboCop::Cop::RSpec::#{name}",
Class.new(RuboCop::Cop.const_get(:WorkaroundCop))
)
stub_const("RuboCop::Cop::RSpec::#{name}", Class.new(temp_class))
end

before do
Expand Down
55 changes: 21 additions & 34 deletions tasks/cops_documentation.rake
Expand Up @@ -85,8 +85,7 @@ task generate_cops_documentation: :yard_for_generate_documentation do
h3('Configurable attributes') + to_table(header, content)
end

# rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength
def configurable_values(pars, name)
def configurable_values(pars, name) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
case name
when /^Enforced/
supported_style_name = RuboCop::Cop::Util.to_supported_styles(name)
Expand All @@ -110,7 +109,6 @@ task generate_cops_documentation: :yard_for_generate_documentation do
end
end
end
# rubocop:enable Metrics/CyclomaticComplexity,Metrics/MethodLength

def to_table(header, content)
table = [
Expand All @@ -121,8 +119,7 @@ task generate_cops_documentation: :yard_for_generate_documentation do
table.join("\n") + "\n"
end

# rubocop:disable Metrics/MethodLength
def format_table_value(val)
def format_table_value(val) # rubocop:disable Metrics/MethodLength
value =
case val
when Array
Expand All @@ -136,20 +133,19 @@ task generate_cops_documentation: :yard_for_generate_documentation do
end
value.gsub("#{Dir.pwd}/", '').rstrip
end
# rubocop:enable Metrics/MethodLength

def cop_urls(config, cop)
rubocop_version = Gem::Version.new(RuboCop::Version::STRING)

# Since Rubocop v0.75.0 and above, MessageAnnotator#new changed from:
# Since RuboCop v0.75.0 and above, MessageAnnotator#new changed from:
# def initialize(config, cop_config, options)
# to:
# def initialize(config, cop_name, cop_config, options)
#
# Since this library has a loose Rubocop dependency, we select the
# Since this library has a loose RuboCop dependency, we select the
# right arguments based on the installed version.
#
# TODO: When Rubocop < 0.75 is no longer supported, remove the second half
# TODO: When RuboCop < 0.75 is no longer supported, remove the second half
# of this condition.

if rubocop_version >= Gem::Version.new('0.75.0')
Expand All @@ -172,30 +168,29 @@ task generate_cops_documentation: :yard_for_generate_documentation do
content
end

# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/MethodLength
def print_cops_of_department(cops, department, config)
selected_cops = cops_of_department(cops, department).select do |cop|
cop.to_s.start_with?('RuboCop::Cop::RSpec')
def selected_cops(cops, department)
cops_of_department(cops, department.to_sym).select do |cop|
cop.name.start_with?('RuboCop::Cop::RSpec') &&
cop.name != 'RuboCop::Cop::RSpec::Cop'
end
end

def print_cops_of_department(cops, department, config) # rubocop:disable Metrics/MethodLength
selected_cops = selected_cops(cops, department)
return if selected_cops.empty?

content = +"# #{department}\n"
selected_cops.each do |cop|
content << print_cop_with_doc(cop, config)
end
content = [
"# #{department}\n",
*selected_cops.map { |cop| print_cop_with_doc(cop, config) }
].join
file_name = "#{Dir.pwd}/manual/cops_#{department.downcase}.md"
File.open(file_name, 'w') do |file|
puts "* generated #{file_name}"
file.write(content.strip + "\n")
file.write(content)
end
end
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/MethodLength

# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/MethodLength
def print_cop_with_doc(cop, config)
def print_cop_with_doc(cop, config) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
t = config.for_cop(cop)
non_display_keys = %w[Description Enabled StyleGuide Reference]
pars = t.reject { |k| non_display_keys.include? k }
Expand All @@ -209,15 +204,9 @@ task generate_cops_documentation: :yard_for_generate_documentation do
end
cops_body(config, cop, description, examples_object, pars)
end
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/MethodLength

# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/MethodLength
def table_of_content_for_department(cops, department)
selected_cops = cops_of_department(cops, department.to_sym).select do |cop|
cop.to_s.start_with?('RuboCop::Cop::RSpec')
end
selected_cops = selected_cops(cops, department)
return if selected_cops.empty?

type_title = department[0].upcase + department[1..-1]
Expand All @@ -230,8 +219,6 @@ task generate_cops_documentation: :yard_for_generate_documentation do

content
end
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/MethodLength

def print_table_of_contents(cops)
path = "#{Dir.pwd}/manual/cops.md"
Expand All @@ -254,7 +241,7 @@ task generate_cops_documentation: :yard_for_generate_documentation do
.map(&:to_s)
.sort
.map { |department| table_of_content_for_department(cops, department) }
.reject(&:nil?)
.compact
.join("\n")
end

Expand Down

0 comments on commit a8d756a

Please sign in to comment.