class Maximus::Lint
Parent class for all lints (inherited by children) @since 0.1.0 @attr_accessor output [Hash] result of a lint parsed by Lint#refine
Attributes
Public Class Methods
Perform a lint of relevant code
All defined lints require a “result” method @example the result method in the child class
def result @task = __method__.to_s @path ||= 'path/or/**/glob/to/files'' lint_data = JSON.parse(`some-command-line-linter`) @output[:files_inspected] ||= files_inspected(extension, delimiter, base_path_replacement) refine data_from_output end
Inherits settings from {Config#initialize} @see Config#initialize
@param opts [Hash] ({}) options passed directly to the lint @option opts [Hash] :git_files filename: file location
@see GitControl#lints_and_stats
@option opts [Array, String] :file_paths lint only specific files or directories
Accepts globs too which is used to define paths from the URL
@option opts [Config object] :config custom Maximus::Config
object @return [void] this method is used to set up instance variables
# File lib/maximus/lint.rb, line 37 def initialize(opts = {}) # Only run the config once @config = opts[:config] || Maximus::Config.new(opts) @settings = @config.settings @git_files = opts[:git_files] @path = opts[:file_paths] || @settings[:file_paths] @output = {} end
Public Instance Methods
Convert raw data into warnings, errors, conventions or refactors. Use this wisely. @param data [Hash] unfiltered lint data @return [Hash] refined lint data and all the other bells and whistles
# File lib/maximus/lint.rb, line 51 def refine(data) @task ||= '' data = parse_data(data) return puts data if data.is_a?(String) evaluate_severities(data) puts summarize if @config.is_dev? puts dev_format(data) ceiling_warning else # Because this should be returned in the format it was received @output[:raw_data] = data.to_json end @output end
Protected Instance Methods
Add severities to @output @since 0.1.5 @param data [Hash]
# File lib/maximus/lint.rb, line 127 def evaluate_severities(data) @output[:lint_warnings] = [] @output[:lint_errors] = [] @output[:lint_conventions] = [] @output[:lint_refactors] = [] @output[:lint_fatals] = [] return if data.blank? data.each do |filename, error_list| error_list.each do |message| # so that :raw_data remains unaffected message = message.clone message.delete('length') message['filename'] = filename.nil? ? '' : strip_working_dir(filename) severity = "lint_#{message['severity']}s".to_sym message.delete('severity') @output[severity] << message if @output.key?(severity) end end @output end
List all files inspected @param ext [String] extension to search for @param delimiter [String] comma or space separated @param remove [String] remove from all file names @return all_files [Array<string>] list of file names
# File lib/maximus/lint.rb, line 79 def files_inspected(ext, delimiter = ',', remove = @config.working_dir) @path.is_a?(Array) ? @path.split(delimiter) : file_list(@path, ext, remove) end
Convert the array from lines_added into spelled-out ranges This is a GitControl
helper but it's used in Lint
@see GitControl#lines_added
@see Lint#relevant_lint
@example typical output
lines_added = {changes: ['0..10', '11..14']} lines_added_to_range(lines_added) # output [0,1,2,3,4,5,6,7,8,9,10, 11,12,13,14]
@return [Hash] changes_array of spelled-out arrays of integers
# File lib/maximus/lint.rb, line 162 def lines_added_to_range(file) changes_array = file[:changes].map { |ch| ch.split("..").map(&:to_i) } changes_array.map { |e| (e[0]..e[1]).to_a }.flatten! end
Compare lint output with lines changed in commit @param lint [Hash] output lint data @param files [Hash<String: String>] filename: filepath @return [Array] lints that match the lines in commit
# File lib/maximus/lint.rb, line 87 def relevant_output(lint, files) all_files = {} files.each do |file| # sometimes data will be blank but this is good - it means no errors were raised in the lint next if lint.blank? || file.blank? || !file.is_a?(Hash) || !file.key?(:filename) lint_file = lint[file[:filename]] next if lint_file.blank? expanded = lines_added_to_range(file) revert_name = strip_working_dir(file[:filename]) all_files[revert_name] = [] lint_file.each do |l| if expanded.include?(l['line'].to_i) all_files[revert_name] << l end end # If there's nothing there, then it definitely isn't a relevant lint all_files.delete(revert_name) if all_files[revert_name].blank? end @output[:files_linted] = all_files.keys all_files end
Look for a config defined from Config#initialize @since 0.1.2 @param search_for [String] @return [String, Boolean] path to temp file
# File lib/maximus/lint.rb, line 119 def temp_config(search_for) return false if @settings.nil? @settings[search_for.to_sym].blank? ? false : @settings[search_for.to_sym] end
Private Instance Methods
If there's just too much to handle, through a warning. @param lint_length [Integer] count of how many lints @return [String] console message to display
# File lib/maximus/lint.rb, line 190 def ceiling_warning lint_length = (@output[:lint_errors].length + @output[:lint_warnings].length + @output[:lint_conventions].length + @output[:lint_refactors].length + @output[:lint_fatals].length) return unless lint_length > 100 failed_task = @task.color(:green) errors = "#{lint_length} failures.".color(:red) errormsg = [ "You wouldn't stand a chance in Rome.\nResolve thy errors and train with #{failed_task} again.", "The gods frown upon you, mortal.\n#{failed_task}. Again.", "Do not embarrass the city. Fight another day. Use #{failed_task}.", "You are without honor. Replenish it with another #{failed_task}.", "You will never claim the throne with a performance like that.", "Pompeii has been lost.", "A wise choice. Do not be discouraged from another #{failed_task}." ].sample errormsg << "\n\n" go_on = prompt "\n#{errors} Continue? (y/n) " abort errormsg unless truthy?(go_on) end
Dev display, executed only when called from command line @param errors [Hash] data from lint @return [String] console message to display
# File lib/maximus/lint.rb, line 214 def dev_format(errors = @output[:raw_data]) return if errors.blank? pretty_output = '' errors.each do |filename, error_list| filename = strip_working_dir(filename) pretty_output << "\n#{filename.color(:cyan).underline} \n" error_list.each do |message| pretty_output << severity_color(message['severity']) pretty_output << " #{message['line'].to_s.color(:blue)} #{message['linter'].color(:green)}: #{message['reason']} \n" end end pretty_output << "-----\n\n" pretty_output end
Handle data and generate relevant_output
if appropriate @since 0.1.6 @see refine
@param data [String, Hash] @return [String, Hash] String if error, Hash if success
# File lib/maximus/lint.rb, line 243 def parse_data(data) # Prevent abortive empty JSON.parse error data = '{}' if data.blank? return "Error from #{@task}: #{data}" if data.is_a?(String) && data.include?('No such') data = JSON.parse(data) if data.is_a?(String) @output[:relevant_output] = relevant_output( data, @git_files ) unless @git_files.blank? data = @output[:relevant_output] unless @settings[:commit].blank? data end
# File lib/maximus/lint.rb, line 256 def severity_color(severity) case severity when 'warning' then 'W'.color(:yellow) when 'error' then 'E'.color(:red) when 'convention' then 'C'.color(:cyan) when 'refactor' then 'R'.color(:white) when 'fatal' then 'F'.color(:magenta) else '?'.color(:blue) end end
String working directory @since 0.1.6 @param path [String] @return [String]
# File lib/maximus/lint.rb, line 234 def strip_working_dir(path) path.gsub(@config.working_dir, '') end
Send abbreviated results to console or to the log @return [String] console message to display
# File lib/maximus/lint.rb, line 172 def summarize success = @task.color(:green) success << ": " success << "[#{@output[:lint_warnings].length}]".color(:yellow) success << " [#{@output[:lint_errors].length}]".color(:red) if @task == 'rubocop' success << " [#{@output[:lint_conventions].length}]".color(:cyan) success << " [#{@output[:lint_refactors].length}]".color(:white) success << " [#{@output[:lint_fatals].length}]".color(:magenta) end success << "\n#{'Warning'.color(:red)}: #{@output[:lint_errors].length} errors found in #{@task}" if @output[:lint_errors].length > 0 success end