lib/flay.rb in flay-2.4.0 vs lib/flay.rb in flay-2.5.0
- old
+ new
@@ -13,12 +13,20 @@
alias :binread :read unless RUBY19
end
end
class Flay
- VERSION = "2.4.0" # :nodoc:
+ VERSION = "2.5.0" # :nodoc:
+ class Item < Struct.new(:structural_hash, :name, :bonus, :mass, :locations)
+ alias identical? bonus
+ end
+
+ class Location < Struct.new(:file, :line, :fuzzy)
+ alias fuzzy? fuzzy
+ end
+
##
# Returns the default options.
def self.default_options
{
@@ -28,10 +36,11 @@
:verbose => false,
:number => true,
:timeout => 10,
:liberal => false,
:fuzzy => false,
+ :only => nil,
}
end
##
# Process options in +args+, defaulting to +ARGV+.
@@ -72,10 +81,14 @@
opts.on('-v', '--verbose', "Verbose. Show progress processing files.") do
options[:verbose] = true
end
+ opts.on('-o', '--only NODE', String, "Only show matches on NODE type.") do |s|
+ options[:only] = s.to_sym
+ end
+
opts.on('-d', '--diff', "Diff Mode. Display N-Way diff for ruby.") do
options[:diff] = true
end
opts.on('-s', '--summary', "Summarize. Show flay score per file only.") do
@@ -202,18 +215,43 @@
end
##
# Prune, find identical nodes, and update masses.
- def analyze
+ def analyze filter = nil
self.prune
self.hashes.each do |hash,nodes|
identical[hash] = nodes[1..-1].all? { |n| n == nodes.first }
end
update_masses
+
+ sorted = masses.sort_by { |h,m|
+ [-m,
+ hashes[h].first.file,
+ hashes[h].first.line,
+ hashes[h].first.first.to_s]
+ }
+
+ sorted.map { |hash, mass|
+ nodes = hashes[hash]
+
+ next unless nodes.first.first == filter if filter
+
+ same = identical[hash]
+ node = nodes.first
+ n = nodes.size
+ bonus = "*#{n}" if same
+
+ locs = nodes.sort_by { |x| [x.file, x.line] }.each_with_index.map { |x, i|
+ extra = :fuzzy if x.modified?
+ Location[x.file, x.line, extra]
+ }
+
+ Item[hash, node.first, bonus, mass, locs]
+ }.compact
end
##
# Reset total and recalculate the masses for all nodes in +hashes+.
@@ -425,73 +463,52 @@
end
##
# Output the report. Duh.
- def report prune = nil
- analyze
+ def report io = $stdout
+ only = option[:only]
- puts "Total score (lower is better) = #{self.total}"
+ data = analyze only
+ io.puts "Total score (lower is better) = #{self.total}"
+
if option[:summary] then
- puts
+ io.puts
self.summary.sort_by { |_,v| -v }.each do |file, score|
- puts "%8.2f: %s" % [score, file]
+ io.puts "%8.2f: %s" % [score, file]
end
return
end
- count = 0
- sorted = masses.sort_by { |h,m|
- [-m,
- hashes[h].first.file,
- hashes[h].first.line,
- hashes[h].first.first.to_s]
- }
- sorted.each do |hash, mass|
- nodes = hashes[hash]
- next unless nodes.first.first == prune if prune
- puts
+ data.each_with_index do |item, count|
+ prefix = "%d) " % (count + 1) if option[:number]
- same = identical[hash]
- node = nodes.first
- n = nodes.size
- match, bonus = if same then
- ["IDENTICAL", "*#{n}"]
- else
- ["Similar", ""]
- end
+ match = item.identical? ? "IDENTICAL" : "Similar"
- if option[:number] then
- count += 1
+ io.puts
+ io.puts "%s%s code found in %p (mass%s = %d)" %
+ [prefix, match, item.name, item.bonus, item.mass]
- puts "%d) %s code found in %p (mass%s = %d)" %
- [count, match, node.first, bonus, mass]
- else
- puts "%s code found in %p (mass%s = %d)" %
- [match, node.first, bonus, mass]
+ item.locations.each_with_index do |loc, i|
+ loc_prefix = "%s: " % (?A.ord + i).chr if option[:diff]
+ extra = " (FUZZY)" if loc.fuzzy?
+ io.puts " %s%s:%d%s" % [loc_prefix, loc.file, loc.line, extra]
end
- nodes.sort_by { |x| [x.file, x.line] }.each_with_index do |x, i|
- if option[:diff] then
- c = (?A.ord + i).chr
- extra = " (FUZZY)" if x.modified?
- puts " #{c}: #{x.file}:#{x.line}#{extra}"
- else
- extra = " (FUZZY)" if x.modified?
- puts " #{x.file}:#{x.line}#{extra}"
- end
- end
-
if option[:diff] then
- puts
+ io.puts
+
+ nodes = hashes[item.structural_hash]
+
sources = nodes.map do |s|
msg = "sexp_to_#{File.extname(s.file).sub(/./, '')}"
self.respond_to?(msg) ? self.send(msg, s) : sexp_to_rb(s)
end
- puts n_way_diff(*sources)
+
+ io.puts n_way_diff(*sources)
end
end
end
def sexp_to_rb sexp