module Reek # # Reports a warning that a smell has been found. # class SmellWarning include Comparable MESSAGE_KEY = 'message' SUBCLASS_KEY = 'subclass' CLASS_KEY = 'class' CONTEXT_KEY = 'context' LINES_KEY = 'lines' SOURCE_KEY = 'source' ACTIVE_KEY = 'is_active' def initialize(class_name, context, lines, message, masked, source = '', subclass_name = '', parameters = {}) @smell = { CLASS_KEY => class_name, SUBCLASS_KEY => subclass_name, MESSAGE_KEY => message, } @smell.merge!(parameters) @status = { ACTIVE_KEY => !masked } @location = { CONTEXT_KEY => context, LINES_KEY => lines, SOURCE_KEY => source } end # # Details of the smell found, including its class ({CLASS_KEY}), # subclass ({SUBCLASS_KEY}) and summary message ({MESSAGE_KEY}) # # @return [Hash{String => String}] # attr_reader :smell # # Details of the smell's location, including its context ({CONTEXT_KEY}), # the line numbers on which it occurs ({LINES_KEY}) and the source # file ({SOURCE_KEY}) # # @return [Hash{String => String, Array}] # attr_reader :location # # Details of the smell's status, including whether it is active ({ACTIVE_KEY}) # (as opposed to being masked by a config file) # # @return [Hash{String => Boolean}] # attr_reader :status def hash # :nodoc: sort_key.hash end def <=>(other) sort_key <=> other.sort_key end def eql?(other) (self <=> other) == 0 end def contains_all?(patterns) rpt = sort_key.to_s return patterns.all? {|patt| patt === rpt} end def matches?(klass, patterns) @smell.values.include?(klass.to_s) and contains_all?(patterns) end def sort_key [@location[CONTEXT_KEY], @smell[MESSAGE_KEY], smell_name] end protected :sort_key def report(format) format.gsub(/\%s/, smell_name). gsub(/\%c/, @location[CONTEXT_KEY]). gsub(/\%w/, @smell[MESSAGE_KEY]). gsub(/\%m/, @status[ACTIVE_KEY] ? '' : '(masked) ') end def report_on(report) if @status[ACTIVE_KEY] report.found_smell(self) else report.found_masked_smell(self) end end private def smell_name @smell[CLASS_KEY].gsub(/([a-z])([A-Z])/) { |sub| "#{$1} #{$2}"}.split.join(' ') end end end