Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions lib/checkstyle_xml_report_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
require "rexml/document"

class CheckstyleXmlReportGenerator
attr_reader :data

def initialize(data)
@data = items_grouped_by_locations(data)
end

def render
"".tap { |result| document.write(output: result, indent: 2) }
end

private

def items_grouped_by_locations(data)
data.each_with_object({}) do |item, object|
item.locations.each do |location|
file = location.file

if object[file]
object[file] << [location, item]
else
object[file] = [[location, item]]
end
end
end
end

def document
REXML::Document.new.tap do |document|
document << REXML::XMLDecl.new << checkstyle
end
end

def checkstyle
REXML::Element.new('checkstyle').tap do |checkstyle|
data.each do |filename, group|
checkstyle << file(filename, group)
end
end
end

def file(filename, group)
REXML::Element.new('file').tap do |file|
file.add_attribute 'name', File.realpath(filename)

group.each do |location, item|
file << error(item, location)
end
end
end

def error(item, location)
REXML::Element.new('error').tap do |error|
error.add_attributes 'column' => 0,
'line' => location.line,
'message' => "#{smell_message(item)} (#{smell_locations_string(item.locations)})",
'severity' => 'warning',
'source' => item.identical? ? 'IdenticalCode' : 'SimilarCode'
end
end

def smell_message(item)
match = item.identical? ? "IDENTICAL" : "Similar"
"%s code found in %p (mass%s = %d)" % [match, item.name, item.bonus, item.mass]
end

def smell_locations_string(locations)
[locations.map { |location| "#{location.file}:#{location.line}" }].join(", ")
end
end
51 changes: 36 additions & 15 deletions lib/flay.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
require "sexp_processor"
require "ruby_parser"
require "timeout"
require "checkstyle_xml_report_generator"

class File
RUBY19 = "<3".respond_to? :encoding unless defined? RUBY19 # :nodoc:
Expand All @@ -30,15 +31,16 @@ class Location < Struct.new(:file, :line, :fuzzy)

def self.default_options
{
:diff => false,
:mass => 16,
:summary => false,
:verbose => false,
:number => true,
:timeout => 10,
:liberal => false,
:fuzzy => false,
:only => nil,
:diff => false,
:mass => 16,
:summary => false,
:verbose => false,
:number => true,
:timeout => 10,
:liberal => false,
:fuzzy => false,
:only => nil,
:xml_checkstyle => nil
}
end

Expand Down Expand Up @@ -100,6 +102,10 @@ def self.parse_options args = ARGV
options[:timeout] = t.to_i
end

opts.on("-x", "--xml-checkstyle PATH", String, "Generate checkstyle XML report.") do |path|
options[:xml_checkstyle] = path
end

extensions = ["rb"] + Flay.load_plugins

opts.separator ""
Expand Down Expand Up @@ -498,14 +504,14 @@ def summary
score
end

##
# Output the report. Duh.

def report io = $stdout
only = option[:only]
def report_checkstyle_xml io, data
report = CheckstyleXmlReportGenerator.new(data).render

data = analyze only
File.write option[:xml_checkstyle], report
io.puts report
end

def report_io io, data
io.puts "Total score (lower is better) = #{self.total}"

if option[:summary] then
Expand Down Expand Up @@ -548,6 +554,21 @@ def report io = $stdout
end
end

##
# Output the report. Duh.

def report io = $stdout
only = option[:only]

data = analyze only

if option[:xml_checkstyle]
report_checkstyle_xml(io, data)
else
report_io(io, data)
end
end

def sexp_to_rb sexp
begin
require "ruby2ruby"
Expand Down