# frozen_string_literal: true require "erb" require "cgi" require "fileutils" require "digest/sha1" require "time" require "json" module DeprecationsDetector module Formatters module HTML class Formatter def format(result, output_path: DeprecationsDetector::Main.output_path) public_r = './public/*' Dir[File.join(File.dirname(__FILE__), public_r)].each do |path| FileUtils.cp_r(path, asset_output_path(output_path)) end File.open(File.join(output_path, "index.html"), "wb") do |file| file.puts template("layout").result(binding) end puts output_message(result, output_path) end def output_message(result, output_path) "Coverage report generated for #{result.count} files to #{output_path}." end def asset_output_path(output_path) return @asset_output_path if defined?(@asset_output_path) && @asset_output_path @asset_output_path = File.join(output_path, "assets", DeprecationsDetector::VERSION) FileUtils.mkdir_p(@asset_output_path) @asset_output_path end private # Returns the an erb instance for the template of given name def template(name) ERB.new(File.read(File.join(File.dirname(__FILE__), "views", "#{name}.erb"))) end def assets_path(name) File.join("./assets", DeprecationsDetector::VERSION, name) end # Returns the html for the given source_file def formatted_source_file(source_file) template("source_file").result(binding) rescue Encoding::CompatibilityError => e puts "Encoding problems with file #{filename(source_file)}. Simplecov/ERB can't handle non ASCII characters in filenames. Error: #{e.message}." end def readfile(source_file) load_source(filename(source_file)) end def load_source(file_name) lines = [] # The default encoding is UTF-8 File.open(file_name, "rb:UTF-8") do |file| line = file.gets # Check for shbang if /\A#!/.match?(line) lines << line line = file.gets end return lines unless line check_magic_comment(file, line) lines.concat([line], file.readlines) end lines end def check_magic_comment(file, line) # Check for encoding magic comment # Encoding magic comment must be placed at first line except for shbang if (match = /\A#\s*(?:-\*-)?\s*(?:en)?coding:\s*(\S+)\s*(?:-\*-)?\s*\z/.match(line)) file.set_encoding(match[1], "UTF-8") end end def grouped(files) groups = files.group_by do |file_name, lines| lines.map do |line, examples| examples.map { |example| example[:deprecation_message] } end end.keys.flatten.uniq grouped = {} grouped_files = [] groups.each do |deprecation_message| grouped[deprecation_message] = files.select { |source_file, lines| lines.detect { |line, examples| examples.detect { |example| example[:deprecation_message] == deprecation_message } } } grouped_files += grouped[deprecation_message].keys end if !groups.empty? && !(other_files = files.reject { |source_file| grouped_files.include?(source_file) }).empty? grouped["Ungrouped"] = other_files end arr = grouped.map do |deprecation_message, objects| [ deprecation_message, -objects.to_a.sum { |file, lines| lines.sum { |line, examples| examples.count } } ] end.sort_by { |group| group[1] }.to_h.keys[0..6] # filter just the 6 most frequent deprecations arr.map { |k| [k, grouped[k]] }.to_h end # Returns a table containing the given source files def formatted_file_list(title, source_files) title_id = title.gsub(/^[^a-zA-Z]+/, "").gsub(/[^a-zA-Z0-9\-\_]/, "") # Silence a warning by using the following variable to assign to itself: # "warning: possibly useless use of a variable in void context" # The variable is used by ERB via binding. title_id = title_id template("file_list").result(binding) end def coverage_css_class(covered_percent) if covered_percent > 90 "green" elsif covered_percent > 80 "yellow" else "red" end end def strength_css_class(covered_strength) if covered_strength > 1 "green" elsif covered_strength == 1 "yellow" else "red" end end def filename(source_file) source_file.first.to_s end # Return a (kind of) unique id for the source file given. Uses SHA1 on path for the id def id(source_file) Digest::SHA1.hexdigest(filename(source_file)) end def timeago(time) "#{time.iso8601}" end def shortened_filename(source_file) filename(source_file).sub(Dir.pwd, '.').gsub(%r{^./}, "") end def link_to_source_file(source_file) %(#{shortened_filename source_file}) end end end end end