analdiffist 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|