analdiffist 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -2
- data/Gemfile.lock +12 -10
- data/README.md +1 -0
- data/VERSION +1 -1
- data/analdiffist.gemspec +32 -8
- data/bin/analdiffist +4 -91
- data/lib/anal_diffist.rb +79 -0
- data/lib/analdiffist/diff_set.rb +30 -0
- data/lib/analdiffist/flog_parser.rb +55 -0
- data/lib/analdiffist/reek_metrics.rb +4 -0
- data/lib/analdiffist/reek_parser.rb +39 -0
- data/lib/analdiffist/standard_diffist.rb +64 -0
- data/lib/analdiffist/target_finder.rb +17 -0
- data/lib/analdiffist/text_based_diffist.rb +46 -0
- data/spec/fixtures/other_smelly_file.rb +16 -0
- data/spec/fixtures/smelly_file.rb +16 -0
- data/spec/lib/analdiffist/diff_set_spec.rb +83 -0
- data/spec/lib/analdiffist/flog_parser_spec.rb +18 -0
- data/spec/lib/analdiffist/reek_metrics_spec.rb +5 -0
- data/spec/lib/analdiffist/reek_parser_spec.rb +35 -0
- data/spec/lib/analdiffist/standard_diffist_spec.rb +21 -0
- data/spec/lib/analdiffist/target_finder_spec.rb +32 -0
- data/spec/spec_helper.rb +1 -2
- metadata +29 -5
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
+
ZenTest (4.5.0)
|
5
|
+
autotest (4.4.6)
|
6
|
+
ZenTest (>= 4.4.1)
|
4
7
|
diff-lcs (1.1.2)
|
5
8
|
flog (2.5.1)
|
6
9
|
ruby_parser (~> 2.0)
|
@@ -11,19 +14,18 @@ GEM
|
|
11
14
|
git (>= 1.2.5)
|
12
15
|
rake
|
13
16
|
rake (0.8.7)
|
14
|
-
rcov (0.9.9)
|
15
17
|
reek (1.2.8)
|
16
18
|
ruby2ruby (~> 1.2)
|
17
19
|
ruby_parser (~> 2.0)
|
18
20
|
sexp_processor (~> 3.0)
|
19
|
-
rspec (2.
|
20
|
-
rspec-core (~> 2.
|
21
|
-
rspec-expectations (~> 2.
|
22
|
-
rspec-mocks (~> 2.
|
23
|
-
rspec-core (2.
|
24
|
-
rspec-expectations (2.
|
21
|
+
rspec (2.5.0)
|
22
|
+
rspec-core (~> 2.5.0)
|
23
|
+
rspec-expectations (~> 2.5.0)
|
24
|
+
rspec-mocks (~> 2.5.0)
|
25
|
+
rspec-core (2.5.1)
|
26
|
+
rspec-expectations (2.5.0)
|
25
27
|
diff-lcs (~> 1.1.2)
|
26
|
-
rspec-mocks (2.
|
28
|
+
rspec-mocks (2.5.0)
|
27
29
|
ruby2ruby (1.2.5)
|
28
30
|
ruby_parser (~> 2.0)
|
29
31
|
sexp_processor (~> 3.0)
|
@@ -35,9 +37,9 @@ PLATFORMS
|
|
35
37
|
ruby
|
36
38
|
|
37
39
|
DEPENDENCIES
|
40
|
+
autotest
|
38
41
|
bundler (~> 1.0.0)
|
39
42
|
flog
|
40
43
|
jeweler (~> 1.5.2)
|
41
|
-
rcov
|
42
44
|
reek
|
43
|
-
rspec (~> 2.
|
45
|
+
rspec (~> 2.5.0)
|
data/README.md
CHANGED
@@ -2,6 +2,7 @@ analdiffist
|
|
2
2
|
============
|
3
3
|
|
4
4
|
A professional twice over: an analyst and a diffist.
|
5
|
+
[http://www.youtube.com/watch?v=UrIpPqcln6Y](http://www.youtube.com/watch?v=UrIpPqcln6Y)
|
5
6
|
|
6
7
|
analdiffist uses [flog](http://ruby.sadi.st/Flog.html) and [reek](https://github.com/kevinrutherford/reek/wiki) to analyze ruby code.
|
7
8
|
Given two git refs (for example *master* and *feature-branch*), it will show you any differences in code metrics introduced between the refs.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/analdiffist.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{analdiffist}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Adam Pearson", "Dave Foley"]
|
12
|
-
s.date = %q{2011-
|
12
|
+
s.date = %q{2011-04-08}
|
13
13
|
s.default_executable = %q{analdiffist}
|
14
14
|
s.description = %q{A tool for comparing the complexity and code smells between two git revisions}
|
15
15
|
s.email = %q{davidmfoley@gmail.com}
|
@@ -29,6 +29,22 @@ Gem::Specification.new do |s|
|
|
29
29
|
"VERSION",
|
30
30
|
"analdiffist.gemspec",
|
31
31
|
"bin/analdiffist",
|
32
|
+
"lib/anal_diffist.rb",
|
33
|
+
"lib/analdiffist/diff_set.rb",
|
34
|
+
"lib/analdiffist/flog_parser.rb",
|
35
|
+
"lib/analdiffist/reek_metrics.rb",
|
36
|
+
"lib/analdiffist/reek_parser.rb",
|
37
|
+
"lib/analdiffist/standard_diffist.rb",
|
38
|
+
"lib/analdiffist/target_finder.rb",
|
39
|
+
"lib/analdiffist/text_based_diffist.rb",
|
40
|
+
"spec/fixtures/other_smelly_file.rb",
|
41
|
+
"spec/fixtures/smelly_file.rb",
|
42
|
+
"spec/lib/analdiffist/diff_set_spec.rb",
|
43
|
+
"spec/lib/analdiffist/flog_parser_spec.rb",
|
44
|
+
"spec/lib/analdiffist/reek_metrics_spec.rb",
|
45
|
+
"spec/lib/analdiffist/reek_parser_spec.rb",
|
46
|
+
"spec/lib/analdiffist/standard_diffist_spec.rb",
|
47
|
+
"spec/lib/analdiffist/target_finder_spec.rb",
|
32
48
|
"spec/spec_helper.rb"
|
33
49
|
]
|
34
50
|
s.homepage = %q{http://github.com/radamant/analdiffist}
|
@@ -37,6 +53,14 @@ Gem::Specification.new do |s|
|
|
37
53
|
s.rubygems_version = %q{1.5.2}
|
38
54
|
s.summary = %q{A professional twice over: an analyst and a diffist.}
|
39
55
|
s.test_files = [
|
56
|
+
"spec/fixtures/other_smelly_file.rb",
|
57
|
+
"spec/fixtures/smelly_file.rb",
|
58
|
+
"spec/lib/analdiffist/diff_set_spec.rb",
|
59
|
+
"spec/lib/analdiffist/flog_parser_spec.rb",
|
60
|
+
"spec/lib/analdiffist/reek_metrics_spec.rb",
|
61
|
+
"spec/lib/analdiffist/reek_parser_spec.rb",
|
62
|
+
"spec/lib/analdiffist/standard_diffist_spec.rb",
|
63
|
+
"spec/lib/analdiffist/target_finder_spec.rb",
|
40
64
|
"spec/spec_helper.rb"
|
41
65
|
]
|
42
66
|
|
@@ -46,25 +70,25 @@ Gem::Specification.new do |s|
|
|
46
70
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
47
71
|
s.add_runtime_dependency(%q<reek>, [">= 0"])
|
48
72
|
s.add_runtime_dependency(%q<flog>, [">= 0"])
|
49
|
-
s.add_development_dependency(%q<rspec>, ["~> 2.
|
73
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.5.0"])
|
50
74
|
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
51
75
|
s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
|
52
|
-
s.add_development_dependency(%q<
|
76
|
+
s.add_development_dependency(%q<autotest>, [">= 0"])
|
53
77
|
else
|
54
78
|
s.add_dependency(%q<reek>, [">= 0"])
|
55
79
|
s.add_dependency(%q<flog>, [">= 0"])
|
56
|
-
s.add_dependency(%q<rspec>, ["~> 2.
|
80
|
+
s.add_dependency(%q<rspec>, ["~> 2.5.0"])
|
57
81
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
58
82
|
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
59
|
-
s.add_dependency(%q<
|
83
|
+
s.add_dependency(%q<autotest>, [">= 0"])
|
60
84
|
end
|
61
85
|
else
|
62
86
|
s.add_dependency(%q<reek>, [">= 0"])
|
63
87
|
s.add_dependency(%q<flog>, [">= 0"])
|
64
|
-
s.add_dependency(%q<rspec>, ["~> 2.
|
88
|
+
s.add_dependency(%q<rspec>, ["~> 2.5.0"])
|
65
89
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
66
90
|
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
67
|
-
s.add_dependency(%q<
|
91
|
+
s.add_dependency(%q<autotest>, [">= 0"])
|
68
92
|
end
|
69
93
|
end
|
70
94
|
|
data/bin/analdiffist
CHANGED
@@ -1,94 +1,7 @@
|
|
1
1
|
#! /usr/bin/env ruby
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'anal_diffist'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
stashed = try_to_stash
|
9
|
-
|
10
|
-
ref = get_refs_to_diff current_branch
|
11
|
-
|
12
|
-
file_1 = analyze_ref(ref[0])
|
13
|
-
file_2 = analyze_ref(ref[1])
|
14
|
-
|
15
|
-
begin
|
16
|
-
echo_exec "git checkout #{current_branch}" if current_branch != ref[1]
|
17
|
-
rescue Exception
|
18
|
-
end
|
19
|
-
|
20
|
-
if stashed
|
21
|
-
echo "unstashing"
|
22
|
-
echo_exec "git stash apply"
|
23
|
-
end
|
24
|
-
|
25
|
-
diff file_1, file_2
|
26
|
-
end
|
27
|
-
|
28
|
-
def get_current_branch
|
29
|
-
current_branch_raw = echo_exec "git branch --no-color"
|
30
|
-
lines = current_branch_raw.split("\n")
|
31
|
-
current_branch_line = lines.detect{|x| x[0] == '*'}
|
32
|
-
current_branch = current_branch_line.split(' ')[1]
|
33
|
-
end
|
34
|
-
|
35
|
-
def get_refs_to_diff current_branch
|
36
|
-
[ ARGV[0] || "origin/master", ARGV[1] || current_branch]
|
37
|
-
end
|
38
|
-
|
39
|
-
def analyze_ref ref_name
|
40
|
-
file = get_file_name ref_name
|
41
|
-
begin
|
42
|
-
echo_exec "git checkout #{ref_name}"
|
43
|
-
do_analytics file, ref_name
|
44
|
-
rescue Exception
|
45
|
-
end
|
46
|
-
|
47
|
-
file
|
48
|
-
end
|
49
|
-
|
50
|
-
def get_file_name ref_name
|
51
|
-
|
52
|
-
File.join(Dir.tmpdir, "#{ref_name.gsub('/', '_')}-analytics.txt")
|
53
|
-
end
|
54
|
-
|
55
|
-
def do_analytics dest_filename, ref_name
|
56
|
-
puts 'writing analytics to ' + dest_filename
|
57
|
-
reek_result = `reek -q app lib`
|
58
|
-
flog_result = `flog -g app lib`
|
59
|
-
File.open(dest_filename, 'w') do |f|
|
60
|
-
f.write"--- Analytics for #{ref_name} ---\n\n"
|
61
|
-
|
62
|
-
f.write"\n\n--- FLOG ---\n\n"
|
63
|
-
f.write clean_up_flog(flog_result)
|
64
|
-
|
65
|
-
f.write"\n\n--- REEK ---\n\n"
|
66
|
-
f.write reek_result
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def clean_up_flog(flog_result)
|
71
|
-
flog_result.gsub(/:[0-9]+$/, '')
|
72
|
-
end
|
73
|
-
|
74
|
-
def echo s
|
75
|
-
puts s
|
76
|
-
end
|
77
|
-
|
78
|
-
def echo_exec command
|
79
|
-
puts command
|
80
|
-
result = `#{command}`
|
81
|
-
puts result
|
82
|
-
result
|
83
|
-
end
|
84
|
-
|
85
|
-
def try_to_stash
|
86
|
-
result = echo_exec "git stash"
|
87
|
-
!(result =~ /No local changes to save/)
|
88
|
-
end
|
89
|
-
|
90
|
-
def diff f1, f2
|
91
|
-
echo_exec "git diff --color=always -U0 -- '#{f1}' '#{f2}'"
|
92
|
-
end
|
93
|
-
|
94
|
-
main
|
5
|
+
start_ref = ARGV[0]
|
6
|
+
end_ref = ARGV[1]
|
7
|
+
AnalDiffist::Anal.new.run(start_ref, end_ref)
|
data/lib/anal_diffist.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
module AnalDiffist
|
2
|
+
require 'analdiffist/target_finder'
|
3
|
+
require 'analdiffist/reek_metrics'
|
4
|
+
require 'analdiffist/reek_parser'
|
5
|
+
require 'analdiffist/flog_parser'
|
6
|
+
require 'analdiffist/diff_set'
|
7
|
+
require 'analdiffist/text_based_diffist'
|
8
|
+
require 'analdiffist/standard_diffist'
|
9
|
+
|
10
|
+
class Diffist
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'tmpdir'
|
14
|
+
class Anal < Diffist
|
15
|
+
def initialize
|
16
|
+
@diffist = AnalDiffist::StandardDiffist.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def run(start_ref, end_ref)
|
20
|
+
current_branch = get_current_branch
|
21
|
+
stashed = try_to_stash
|
22
|
+
|
23
|
+
ref = get_refs_to_diff current_branch, start_ref, end_ref
|
24
|
+
puts "\nAnaldiffizing: #{ref.join(" -> ")}"
|
25
|
+
analyze_ref(ref[0])
|
26
|
+
analyze_ref(ref[1])
|
27
|
+
|
28
|
+
begin
|
29
|
+
if current_branch != ref[1]
|
30
|
+
puts " checking out original revision: #{current_branch}"
|
31
|
+
checkout_revision current_branch
|
32
|
+
end
|
33
|
+
rescue Exception
|
34
|
+
end
|
35
|
+
|
36
|
+
if stashed
|
37
|
+
puts "unstashing"
|
38
|
+
`git stash apply`
|
39
|
+
end
|
40
|
+
|
41
|
+
@diffist.report_results
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_current_branch
|
45
|
+
current_branch_raw = `git branch --no-color`
|
46
|
+
lines = current_branch_raw.split("\n")
|
47
|
+
current_branch_line = lines.detect{|x| x[0] == '*'}
|
48
|
+
current_branch = current_branch_line.split(' ')[1]
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_refs_to_diff current_branch, start_ref, end_ref
|
52
|
+
[ start_ref || "origin/master", end_ref || current_branch]
|
53
|
+
end
|
54
|
+
|
55
|
+
def analyze_ref ref_name
|
56
|
+
begin
|
57
|
+
checkout_revision ref_name
|
58
|
+
puts " analyzing revision: #{ref_name}"
|
59
|
+
@diffist.do_analytics ref_name
|
60
|
+
rescue Exception
|
61
|
+
puts "Error in analyze_ref: " + $!.to_s
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
def checkout_revision ref_name
|
67
|
+
puts " checking out revision: #{ref_name}"
|
68
|
+
`git checkout -q #{ref_name}`
|
69
|
+
end
|
70
|
+
|
71
|
+
def try_to_stash
|
72
|
+
result = `git stash`
|
73
|
+
stashed = !(result =~ /No local changes to save/)
|
74
|
+
puts "stashed local uncommitted changes" if stashed
|
75
|
+
stashed
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module AnalDiffist
|
2
|
+
class DiffSet
|
3
|
+
def initialize before, after
|
4
|
+
@before = before
|
5
|
+
@after = after
|
6
|
+
end
|
7
|
+
|
8
|
+
def added_problems
|
9
|
+
compare(@after, @before)
|
10
|
+
end
|
11
|
+
|
12
|
+
def removed_problems
|
13
|
+
compare(@before, @after)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def compare(a,b)
|
18
|
+
#TODO: move this comparison into the class?
|
19
|
+
a.map do |problem|
|
20
|
+
matching_problem = b.detect {|problem2| [problem.type, problem.context] == [problem2.type, problem2.context] }
|
21
|
+
|
22
|
+
problem.diff(matching_problem)
|
23
|
+
|
24
|
+
end.reject {|x| x.nil?}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class ScoreDiffSet
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'flog'
|
2
|
+
module AnalDiffist
|
3
|
+
class FlogParser
|
4
|
+
def initialize paths, threshold = 10.0
|
5
|
+
@paths = paths
|
6
|
+
@flog_threshold = threshold
|
7
|
+
end
|
8
|
+
|
9
|
+
def problems
|
10
|
+
f = Flog.new
|
11
|
+
f.flog(@paths)
|
12
|
+
problems = []
|
13
|
+
f.each_by_score{|class_method, score, ignore_for_now| problems << FlogProblem.new(class_method, score)}
|
14
|
+
problems.select {|p| p.score >= @flog_threshold}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class FlogProblem
|
19
|
+
attr_accessor :context, :score
|
20
|
+
def initialize class_method, score
|
21
|
+
@context = class_method || '(none)'
|
22
|
+
@score = score
|
23
|
+
end
|
24
|
+
|
25
|
+
def type
|
26
|
+
'flog score'
|
27
|
+
end
|
28
|
+
|
29
|
+
def diff other
|
30
|
+
return self if other.nil?
|
31
|
+
return nil if other.score >= score
|
32
|
+
FlogDiff.new(@context, other.score, score)
|
33
|
+
end
|
34
|
+
|
35
|
+
def description
|
36
|
+
"Flog score: #{score}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
class FlogDiff
|
40
|
+
attr_accessor :context, :score
|
41
|
+
def initialize context, previous_score, current_score
|
42
|
+
@context = context
|
43
|
+
@current_score = current_score
|
44
|
+
@previous_score = previous_score
|
45
|
+
end
|
46
|
+
|
47
|
+
def score
|
48
|
+
(@current_score - @previous_score).round(1)
|
49
|
+
end
|
50
|
+
|
51
|
+
def description
|
52
|
+
"Flog: #{@current_score.round(1)} (+#{(@current_score - @previous_score).round(1)})"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'reek'
|
2
|
+
module AnalDiffist
|
3
|
+
class ReekParser
|
4
|
+
attr_accessor :problems
|
5
|
+
|
6
|
+
def initialize(paths)
|
7
|
+
examiner = Reek::Examiner.new(paths)
|
8
|
+
@problems = examiner.smells.map {|smell| ReekProblem.new(smell)}
|
9
|
+
end
|
10
|
+
|
11
|
+
def diff(previous)
|
12
|
+
AnalDiffist::DiffSet.new(previous.problems, self.problems)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class ReekProblem
|
17
|
+
def initialize smell
|
18
|
+
@smell = smell
|
19
|
+
end
|
20
|
+
|
21
|
+
def type
|
22
|
+
@smell.subclass.to_s || ''
|
23
|
+
end
|
24
|
+
|
25
|
+
def context
|
26
|
+
@smell.location["context"]
|
27
|
+
end
|
28
|
+
|
29
|
+
def diff other
|
30
|
+
self if other.nil?
|
31
|
+
end
|
32
|
+
def score
|
33
|
+
1
|
34
|
+
end
|
35
|
+
def description
|
36
|
+
"Reek: #{type}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module AnalDiffist
|
2
|
+
class StandardDiffist
|
3
|
+
def initialize options = {}
|
4
|
+
@targets = options[:targets] || AnalDiffist::TargetFinder.new
|
5
|
+
@reporter = options[:reporter] || AnalDiffist::StdOutReporter.new
|
6
|
+
@parsers = options[:parsers] || [FlogParser, ReekParser]
|
7
|
+
|
8
|
+
@revisions = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def do_analytics name
|
12
|
+
#puts 'analyzing ' + name
|
13
|
+
#puts @revisions.inspect
|
14
|
+
@revisions << ProblemSet.new(name, @parsers, @targets)
|
15
|
+
#puts @revisions.inspect
|
16
|
+
end
|
17
|
+
|
18
|
+
def report_results
|
19
|
+
#puts @revisions.inspect
|
20
|
+
before = @revisions[0]
|
21
|
+
after = @revisions[1]
|
22
|
+
diff = DiffSet.new(before.problems, after.problems)
|
23
|
+
|
24
|
+
@reporter.report(diff, before.name, after.name)
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
class ProblemSet
|
31
|
+
attr_accessor :problems, :name
|
32
|
+
def initialize name, parsers, targets
|
33
|
+
@name = name
|
34
|
+
@problems = []
|
35
|
+
parsers.each do |parser|
|
36
|
+
parser_instance = parser.new(targets.targets)
|
37
|
+
problems = parser_instance.problems
|
38
|
+
@problems += (problems || [])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class StdOutReporter
|
45
|
+
def report diff, from_rev, to_rev
|
46
|
+
puts "\n\nAnaldifference between revisions: \n #{from_rev}\n #{to_rev}"
|
47
|
+
puts "\nAdded:\n"
|
48
|
+
puts describe(diff.added_problems)
|
49
|
+
puts "\nRemoved:\n"
|
50
|
+
puts describe(diff.removed_problems)
|
51
|
+
puts "\n\n"
|
52
|
+
end
|
53
|
+
|
54
|
+
def describe(problems)
|
55
|
+
by_context = problems.group_by {|prob| prob.context}
|
56
|
+
results = []
|
57
|
+
by_context.keys.sort.each do |k|
|
58
|
+
results << " #{k}"
|
59
|
+
results << by_context[k].map {|p| " #{p.description}"}.join("\n")
|
60
|
+
end.collect
|
61
|
+
results.join("\n")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module AnalDiffist
|
2
|
+
class TargetFinder
|
3
|
+
def initialize
|
4
|
+
end
|
5
|
+
def targets
|
6
|
+
@targets = []
|
7
|
+
@targets << "lib" if Dir.exists?("lib")
|
8
|
+
@targets << "app" if Dir.exists?("app")
|
9
|
+
@targets
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
targets.join(' ')
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
|
2
|
+
module AnalDiffist
|
3
|
+
class TextBasedDiffist
|
4
|
+
def initialize
|
5
|
+
@targets = AnalDiffist::TargetFinder.new
|
6
|
+
@files = []
|
7
|
+
end
|
8
|
+
def report_results
|
9
|
+
puts 'results:'
|
10
|
+
diff @files[0], @files[1]
|
11
|
+
end
|
12
|
+
|
13
|
+
def do_analytics ref_name
|
14
|
+
dest_filename = get_file_name ref_name
|
15
|
+
|
16
|
+
puts
|
17
|
+
puts 'collecting reek'
|
18
|
+
reek_result = `reek -q #{@targets}`
|
19
|
+
puts 'collecting flog'
|
20
|
+
flog_result = `flog -g #{@targets}`
|
21
|
+
File.open(dest_filename, 'w') do |f|
|
22
|
+
puts 'writing analytics to ' + dest_filename
|
23
|
+
f.write"--- Analytics for #{ref_name} ---\n\n"
|
24
|
+
|
25
|
+
f.write"\n\n--- FLOG ---\n\n"
|
26
|
+
f.write clean_up_flog(flog_result)
|
27
|
+
|
28
|
+
f.write"\n\n--- REEK ---\n\n"
|
29
|
+
f.write reek_result
|
30
|
+
end
|
31
|
+
|
32
|
+
@files << dest_filename
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_file_name ref_name
|
36
|
+
File.join(Dir.tmpdir, "#{ref_name.gsub('/', '_')}-analytics.txt")
|
37
|
+
end
|
38
|
+
|
39
|
+
def clean_up_flog(flog_result)
|
40
|
+
flog_result.gsub(/:[0-9]+$/, '')
|
41
|
+
end
|
42
|
+
def diff f1, f2
|
43
|
+
puts `git diff --color=always -U0 -- '#{f1}' '#{f2}'`
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'diffing two files' do
|
4
|
+
context 'single problem added' do
|
5
|
+
before do
|
6
|
+
@diff = AnalDiffist::DiffSet.new([], [test_problem('foo', 'bar')])
|
7
|
+
end
|
8
|
+
it 'should find a new reek' do
|
9
|
+
added_problems = @diff.added_problems
|
10
|
+
added_problems.length.should == 1
|
11
|
+
added_problems.first.type.should == 'foo'
|
12
|
+
added_problems.first.context == 'bar'
|
13
|
+
end
|
14
|
+
it 'should not have any removed reeks' do
|
15
|
+
@diff.removed_problems.should == []
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'single problem removed' do
|
20
|
+
before do
|
21
|
+
@diff = AnalDiffist::DiffSet.new( [test_problem('foo', 'bar')], [])
|
22
|
+
end
|
23
|
+
it 'should find a removed reek' do
|
24
|
+
removed_problems = @diff.removed_problems
|
25
|
+
removed_problems.length.should == 1
|
26
|
+
removed_problems.first.type.should == 'foo'
|
27
|
+
removed_problems.first.context == 'bar'
|
28
|
+
end
|
29
|
+
it 'should not have any added reeks' do
|
30
|
+
@diff.added_problems.should == []
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'one removed, one added, one remains' do
|
35
|
+
before do
|
36
|
+
before = [test_problem('foo', 'bar'), test_problem('removed', 'removed')]
|
37
|
+
after = [test_problem('foo', 'bar'), test_problem('added', 'added')]
|
38
|
+
@diff = AnalDiffist::DiffSet.new(before, after)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should find a removed reek' do
|
42
|
+
removed_problems = @diff.removed_problems
|
43
|
+
removed_problems.length.should == 1
|
44
|
+
removed_problems.first.type.should == 'removed'
|
45
|
+
removed_problems.first.context == 'removed'
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should find an added problem' do
|
49
|
+
added_problems = @diff.added_problems
|
50
|
+
added_problems.length.should == 1
|
51
|
+
added_problems.first.type.should == 'added'
|
52
|
+
added_problems.first.context == 'added'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'when scores change' do
|
57
|
+
before do
|
58
|
+
before = [AnalDiffist::FlogProblem.new('bar', 7.1)]
|
59
|
+
after = [AnalDiffist::FlogProblem.new('bar', 8.5)]
|
60
|
+
@diff = AnalDiffist::DiffSet.new(before, after)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should identify as added' do
|
64
|
+
added_problems = @diff.added_problems
|
65
|
+
added_problems.length.should == 1
|
66
|
+
added_problems.first.score.round(1).should == 1.4
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_problem type, context, score = 1
|
71
|
+
smell = double("fake problem")
|
72
|
+
smell.stub(:subclass) {type}
|
73
|
+
smell.stub(:location) {context}
|
74
|
+
return AnalDiffist::ReekProblem.new(smell)
|
75
|
+
|
76
|
+
double('fake problem').tap do |p|
|
77
|
+
p.stub(:type) {type}
|
78
|
+
p.stub(:context) {context}
|
79
|
+
p.stub(:score) {score}
|
80
|
+
p.stub(:diff) {p}
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AnalDiffist::FlogParser do
|
4
|
+
context 'analyzing a class' do
|
5
|
+
before do
|
6
|
+
file_parser = get_parser_for('smelly_file.rb')
|
7
|
+
@problems = file_parser.problems
|
8
|
+
end
|
9
|
+
def get_parser_for(fixture_file)
|
10
|
+
file_name = File.join(File.dirname(__FILE__), '../../fixtures/', fixture_file)
|
11
|
+
AnalDiffist::FlogParser.new(file_name, 1.0)
|
12
|
+
end
|
13
|
+
it 'should have an entry for the test method with a non zero score' do
|
14
|
+
duplication = @problems.detect {|p| p.context == 'SmellyFile#duplication'}
|
15
|
+
duplication.score.should > 0
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AnalDiffist::ReekParser do
|
4
|
+
context 'a smelly file' do
|
5
|
+
before do
|
6
|
+
smelly_file_parser = get_parser_for('smelly_file.rb')
|
7
|
+
@problems = smelly_file_parser.problems
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'has a duplication warning for the duplication method' do
|
11
|
+
smells = get_smells_for('SmellyFile#duplication')
|
12
|
+
smells[0].type.should == 'DuplicateMethodCall'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should have some results' do
|
16
|
+
@problems.length.should > 0
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'creates a diff' do
|
20
|
+
smelly_file_parser = get_parser_for('smelly_file.rb')
|
21
|
+
other_smelly_file_parser = get_parser_for('other_smelly_file.rb')
|
22
|
+
diff = smelly_file_parser.diff(other_smelly_file_parser)
|
23
|
+
diff.should be
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_smells_for context
|
27
|
+
@problems.select {|reek| reek.context == context}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_parser_for(fixture_file)
|
32
|
+
file_name = File.join(File.dirname(__FILE__), '../../fixtures/', fixture_file)
|
33
|
+
AnalDiffist::ReekParser.new([file_name])
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AnalDiffist::StandardDiffist do
|
4
|
+
class FakeParser
|
5
|
+
def problems
|
6
|
+
[]
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should work' do
|
11
|
+
@diffist = AnalDiffist::StandardDiffist.new :parsers => [FakeParser]
|
12
|
+
@diffist.do_analytics('foo')
|
13
|
+
@diffist.do_analytics('bar')
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should work!' do
|
17
|
+
@diffist = AnalDiffist::StandardDiffist.new
|
18
|
+
@diffist.do_analytics('foo')
|
19
|
+
@diffist.do_analytics('bar')
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AnalDiffist::TargetFinder do
|
4
|
+
describe "#targets" do
|
5
|
+
|
6
|
+
before { Dir.stub(:exists?){false} }
|
7
|
+
|
8
|
+
subject { AnalDiffist::TargetFinder.new.targets }
|
9
|
+
|
10
|
+
context 'when ./lib exists' do
|
11
|
+
before { Dir.stub(:exists?).with('lib'){true} }
|
12
|
+
it{should include("lib")}
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'when ./app exists' do
|
16
|
+
before { Dir.stub(:exists?).with('app'){true} }
|
17
|
+
it{should include("app")}
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#to_s" do
|
23
|
+
subject do
|
24
|
+
atf = AnalDiffist::TargetFinder.new.tap do |t|
|
25
|
+
t.stub(:targets){['analyst', 'therapist']}
|
26
|
+
end
|
27
|
+
atf.to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
it{ should == "analyst therapist"}
|
31
|
+
end
|
32
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
2
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
3
|
require 'rspec'
|
4
|
-
require '
|
5
|
-
|
4
|
+
require 'anal_diffist'
|
6
5
|
# Requires supporting files with custom matchers and macros, etc,
|
7
6
|
# in ./support/ and its subdirectories.
|
8
7
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: analdiffist
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.2.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Adam Pearson
|
@@ -11,7 +11,7 @@ autorequire:
|
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
|
14
|
-
date: 2011-
|
14
|
+
date: 2011-04-08 00:00:00 -07:00
|
15
15
|
default_executable: analdiffist
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
requirements:
|
44
44
|
- - ~>
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: 2.
|
46
|
+
version: 2.5.0
|
47
47
|
type: :development
|
48
48
|
prerelease: false
|
49
49
|
version_requirements: *id003
|
@@ -70,7 +70,7 @@ dependencies:
|
|
70
70
|
prerelease: false
|
71
71
|
version_requirements: *id005
|
72
72
|
- !ruby/object:Gem::Dependency
|
73
|
-
name:
|
73
|
+
name: autotest
|
74
74
|
requirement: &id006 !ruby/object:Gem::Requirement
|
75
75
|
none: false
|
76
76
|
requirements:
|
@@ -100,6 +100,22 @@ files:
|
|
100
100
|
- VERSION
|
101
101
|
- analdiffist.gemspec
|
102
102
|
- bin/analdiffist
|
103
|
+
- lib/anal_diffist.rb
|
104
|
+
- lib/analdiffist/diff_set.rb
|
105
|
+
- lib/analdiffist/flog_parser.rb
|
106
|
+
- lib/analdiffist/reek_metrics.rb
|
107
|
+
- lib/analdiffist/reek_parser.rb
|
108
|
+
- lib/analdiffist/standard_diffist.rb
|
109
|
+
- lib/analdiffist/target_finder.rb
|
110
|
+
- lib/analdiffist/text_based_diffist.rb
|
111
|
+
- spec/fixtures/other_smelly_file.rb
|
112
|
+
- spec/fixtures/smelly_file.rb
|
113
|
+
- spec/lib/analdiffist/diff_set_spec.rb
|
114
|
+
- spec/lib/analdiffist/flog_parser_spec.rb
|
115
|
+
- spec/lib/analdiffist/reek_metrics_spec.rb
|
116
|
+
- spec/lib/analdiffist/reek_parser_spec.rb
|
117
|
+
- spec/lib/analdiffist/standard_diffist_spec.rb
|
118
|
+
- spec/lib/analdiffist/target_finder_spec.rb
|
103
119
|
- spec/spec_helper.rb
|
104
120
|
has_rdoc: true
|
105
121
|
homepage: http://github.com/radamant/analdiffist
|
@@ -115,7 +131,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
115
131
|
requirements:
|
116
132
|
- - ">="
|
117
133
|
- !ruby/object:Gem::Version
|
118
|
-
hash:
|
134
|
+
hash: -4153762444283860543
|
119
135
|
segments:
|
120
136
|
- 0
|
121
137
|
version: "0"
|
@@ -133,4 +149,12 @@ signing_key:
|
|
133
149
|
specification_version: 3
|
134
150
|
summary: "A professional twice over: an analyst and a diffist."
|
135
151
|
test_files:
|
152
|
+
- spec/fixtures/other_smelly_file.rb
|
153
|
+
- spec/fixtures/smelly_file.rb
|
154
|
+
- spec/lib/analdiffist/diff_set_spec.rb
|
155
|
+
- spec/lib/analdiffist/flog_parser_spec.rb
|
156
|
+
- spec/lib/analdiffist/reek_metrics_spec.rb
|
157
|
+
- spec/lib/analdiffist/reek_parser_spec.rb
|
158
|
+
- spec/lib/analdiffist/standard_diffist_spec.rb
|
159
|
+
- spec/lib/analdiffist/target_finder_spec.rb
|
136
160
|
- spec/spec_helper.rb
|