tasks/cops_documentation.rake in rubocop-minitest-0.9.0 vs tasks/cops_documentation.rake in rubocop-minitest-0.10.0

- old
+ new

@@ -15,82 +15,92 @@ cops.with_department(department).sort! end def cops_body(config, cop, description, examples_objects, pars) content = h2(cop.cop_name) - content << properties(config, cop) + content << required_ruby_version(cop) + content << properties(cop.new(config)) content << "#{description}\n" content << examples(examples_objects) if examples_objects.count.positive? content << configurations(pars) content << references(config, cop) content end def examples(examples_object) examples_object.each_with_object(h3('Examples').dup) do |example, content| + content << "\n" unless content.end_with?("\n\n") content << h4(example.name) unless example.name == '' content << code_example(example) end end + def required_ruby_version(cop) + return '' unless cop.respond_to?(:required_minimum_ruby_version) + + "NOTE: Required Ruby version: #{cop.required_minimum_ruby_version}\n\n" + end + # rubocop:disable Metrics/MethodLength - def properties(config, cop) + def properties(cop_instance) header = [ 'Enabled by default', 'Safe', 'Supports autocorrection', 'VersionAdded', 'VersionChanged' ] - config = config.for_cop(cop) - safe_auto_correct = config.fetch('SafeAutoCorrect', true) - autocorrect = if cop.new.support_autocorrect? - "Yes #{'(Unsafe)' unless safe_auto_correct}" + autocorrect = if cop_instance.support_autocorrect? + "Yes#{' (Unsafe)' unless cop_instance.safe_autocorrect?}" else 'No' end + cop_config = cop_instance.cop_config content = [[ - config.fetch('Enabled') ? 'Enabled' : 'Disabled', - config.fetch('Safe', true) ? 'Yes' : 'No', + cop_status(cop_config.fetch('Enabled')), + cop_config.fetch('Safe', true) ? 'Yes' : 'No', autocorrect, - config.fetch('VersionAdded', '-'), - config.fetch('VersionChanged', '-') + cop_config.fetch('VersionAdded', '-'), + cop_config.fetch('VersionChanged', '-') ]] to_table(header, content) + "\n" end # rubocop:enable Metrics/MethodLength def h2(title) content = +"\n" - content << "## #{title}\n" + content << "== #{title}\n" content << "\n" content end def h3(title) content = +"\n" - content << "### #{title}\n" + content << "=== #{title}\n" content << "\n" content end def h4(title) - content = +"#### #{title}\n" + content = +"==== #{title}\n" content << "\n" content end def code_example(ruby_code) - content = +"```ruby\n" - content << ruby_code.text - .gsub('@good', '# good').gsub('@bad', '# bad').strip - content << "\n```\n" + content = +"[source,ruby]\n----\n" + content << ruby_code.text.gsub('@good', '# good') + .gsub('@bad', '# bad').strip + content << "\n----\n" content end def configurations(pars) return '' if pars.empty? header = ['Name', 'Default value', 'Configurable values'] - configs = pars.each_key.reject { |key| key.start_with?('Supported') } + configs = pars + .each_key + .reject { |key| key.start_with?('Supported') } + .reject { |key| key.start_with?('AllowMultipleStyles') } content = configs.map do |name| configurable = configurable_values(pars, name) default = format_table_value(pars[name]) [name, default, configurable] end @@ -104,12 +114,10 @@ when /^Enforced/ supported_style_name = RuboCop::Cop::Util.to_supported_styles(name) format_table_value(pars[supported_style_name]) when 'IndentationWidth' 'Integer' - when 'Database' - format_table_value(pars['SupportedDatabases']) else case pars[name] when String 'String' when Integer @@ -127,15 +135,18 @@ end # rubocop:enable Metrics/CyclomaticComplexity,Metrics/MethodLength def to_table(header, content) table = [ - header.join(' | '), - Array.new(header.size, '---').join(' | ') - ] - table.concat(content.map { |c| c.join(' | ') }) - table.join("\n") + "\n" + '|===', + "| #{header.join(' | ')}\n\n" + ].join("\n") + marked_contents = content.map do |plain_content| + plain_content.map { |c| "| #{c}" }.join("\n") + end + table << marked_contents.join("\n\n") + table << "\n|===\n" end def format_table_value(val) value = case val @@ -144,120 +155,140 @@ '`[]`' else val.map { |config| format_table_value(config) }.join(', ') end else - "`#{val.nil? ? '<none>' : val}`" + wrap_backtick(val.nil? ? '<none>' : val) end value.gsub("#{Dir.pwd}/", '').rstrip end + def wrap_backtick(value) + if value.is_a?(String) + # Use `+` to prevent text like `**/*.gemspec` from being bold. + value.start_with?('*') ? "`+#{value}+`" : "`#{value}`" + else + "`#{value}`" + end + end + def references(config, cop) cop_config = config.for_cop(cop) urls = RuboCop::Cop::MessageAnnotator.new( config, cop.name, cop_config, {} ).urls return '' if urls.empty? content = h3('References') - content << urls.map { |url| "* [#{url}](#{url})" }.join("\n") + content << urls.map { |url| "* #{url}" }.join("\n") content << "\n" content end + # rubocop:disable Metrics/AbcSize 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::Minitest') end return if selected_cops.empty? - content = +"# #{department}\n" + selected_cops = cops_of_department(cops, department) + content = +"= #{department}\n" selected_cops.each do |cop| content << print_cop_with_doc(cop, config) end - file_name = "#{Dir.pwd}/manual/cops_#{department.downcase}.md" + file_name = "#{Dir.pwd}/docs/modules/ROOT/pages/cops_#{department.downcase}.adoc" File.open(file_name, 'w') do |file| puts "* generated #{file_name}" file.write(content.strip + "\n") end end + # rubocop:enable Metrics/AbcSize def print_cop_with_doc(cop, config) t = config.for_cop(cop) non_display_keys = %w[ Description Enabled StyleGuide Reference Safe SafeAutoCorrect VersionAdded VersionChanged ] pars = t.reject { |k| non_display_keys.include? k } description = 'No documentation' examples_object = [] - YARD::Registry.all(:class).detect do |code_object| - next unless RuboCop::Cop::Badge.for(code_object.to_s) == cop.badge - + cop_code(cop) do |code_object| description = code_object.docstring unless code_object.docstring.blank? examples_object = code_object.tags('example') end cops_body(config, cop, description, examples_object, pars) end + def cop_code(cop) + YARD::Registry.all(:class).detect do |code_object| + next unless RuboCop::Cop::Badge.for(code_object.to_s) == cop.badge + + yield code_object + end + end + # rubocop:disable Metrics/AbcSize 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::Minitest') end return if selected_cops.empty? type_title = department[0].upcase + department[1..-1] - filename = "cops_#{department.downcase}.md" - content = +"#### Department [#{type_title}](#{filename})\n\n" - selected_cops.each do |cop| + filename = "cops_#{department.downcase}.adoc" + content = +"= Department xref:#{filename}[#{type_title}]\n\n" + cops_of_department(cops, department.to_sym).each do |cop| anchor = cop.cop_name.sub('/', '').downcase - content << "* [#{cop.cop_name}](#{filename}##{anchor})\n" + content << "* xref:#{filename}##{anchor}[#{cop.cop_name}]\n" end content end # rubocop:enable Metrics/AbcSize def print_table_of_contents(cops) - path = "#{Dir.pwd}/manual/cops.md" + path = "#{Dir.pwd}/docs/modules/ROOT/pages/cops.adoc" original = File.read(path) - content = +"<!-- START_COP_LIST -->\n" + content = +"// START_COP_LIST\n\n" content << table_contents(cops) - content << "\n<!-- END_COP_LIST -->" + content << "\n// END_COP_LIST" - content = if original.empty? - content - else - original.sub( - /<!-- START_COP_LIST -->.+<!-- END_COP_LIST -->/m, content - ) - end + content = original.sub( + %r{// START_COP_LIST.+// END_COP_LIST}m, content + ) File.write(path, content) end def table_contents(cops) cops .departments .map(&:to_s) .sort .map { |department| table_of_content_for_department(cops, department) } - .reject(&:nil?) + .compact .join("\n") end - def assert_manual_synchronized + def cop_status(status) + return 'Disabled' unless status + + status == 'pending' ? 'Pending' : 'Enabled' + end + + def assert_docs_synchronized # Do not print diff and yield whether exit code was zero - sh('git diff --quiet manual') do |outcome, _| + sh('git diff --quiet docs') do |outcome, _| return if outcome # Output diff before raising error - sh('GIT_PAGER=cat git diff manual') + sh('GIT_PAGER=cat git diff docs') - warn 'The manual directory is out of sync. ' \ + warn 'The docs directory is out of sync. ' \ 'Run `rake generate_cops_documentation` and commit the results.' exit! end end @@ -270,10 +301,10 @@ print_cops_of_department(cops, department, config) end print_table_of_contents(cops) - assert_manual_synchronized if ENV['CI'] == 'true' + assert_docs_synchronized if ENV['CI'] == 'true' ensure RuboCop::ConfigLoader.default_configuration = nil end main