alexrothenberg-metric_fu 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/HISTORY +119 -0
  2. data/MIT-LICENSE +22 -0
  3. data/Manifest.txt +25 -0
  4. data/README +1 -0
  5. data/Rakefile +46 -0
  6. data/TODO +14 -0
  7. data/lib/base/base_template.rb +134 -0
  8. data/lib/base/configuration.rb +187 -0
  9. data/lib/base/generator.rb +156 -0
  10. data/lib/base/md5_tracker.rb +52 -0
  11. data/lib/base/report.rb +100 -0
  12. data/lib/generators/churn.rb +86 -0
  13. data/lib/generators/flay.rb +33 -0
  14. data/lib/generators/flog.rb +131 -0
  15. data/lib/generators/rcov.rb +80 -0
  16. data/lib/generators/reek.rb +36 -0
  17. data/lib/generators/roodi.rb +30 -0
  18. data/lib/generators/saikuro.rb +216 -0
  19. data/lib/generators/stats.rb +43 -0
  20. data/lib/metric_fu.rb +20 -0
  21. data/lib/templates/standard/churn.html.erb +30 -0
  22. data/lib/templates/standard/default.css +64 -0
  23. data/lib/templates/standard/flay.html.erb +33 -0
  24. data/lib/templates/standard/flog.html.erb +52 -0
  25. data/lib/templates/standard/index.html.erb +38 -0
  26. data/lib/templates/standard/rcov.html.erb +42 -0
  27. data/lib/templates/standard/reek.html.erb +41 -0
  28. data/lib/templates/standard/roodi.html.erb +28 -0
  29. data/lib/templates/standard/saikuro.html.erb +83 -0
  30. data/lib/templates/standard/standard_template.rb +26 -0
  31. data/lib/templates/standard/stats.html.erb +54 -0
  32. data/spec/base/base_template_spec.rb +140 -0
  33. data/spec/base/configuration_spec.rb +303 -0
  34. data/spec/base/generator_spec.rb +182 -0
  35. data/spec/base/md5_tracker_spec.rb +57 -0
  36. data/spec/base/report_spec.rb +139 -0
  37. data/spec/generators/churn_spec.rb +152 -0
  38. data/spec/generators/flay_spec.rb +101 -0
  39. data/spec/generators/flog_spec.rb +200 -0
  40. data/spec/generators/reek_spec.rb +59 -0
  41. data/spec/generators/saikuro_spec.rb +63 -0
  42. data/spec/generators/stats_spec.rb +74 -0
  43. data/spec/spec_helper.rb +28 -0
  44. data/tasks/metric_fu.rake +15 -0
  45. data/tasks/railroad.rake +39 -0
  46. data/vendor/saikuro/saikuro.rb +1214 -0
  47. metadata +113 -0
@@ -0,0 +1,200 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ describe Flog do
3
+ before :each do
4
+ @text = <<-HERE
5
+ 157.9: flog total
6
+ 11.3: flog/method average
7
+
8
+ 34.8: UsersController#create
9
+ 9.2: branch
10
+ 6.8: current_user
11
+ 5.2: assignment
12
+ 3.4: role
13
+ 3.0: render
14
+ 3.0: ==
15
+ 2.8: flash
16
+ 1.6: after_create_page
17
+ 1.6: params
18
+ 1.5: activate!
19
+ 1.5: errors
20
+ 1.4: login
21
+ 1.4: redirect_to
22
+ 1.4: []
23
+ 1.3: empty?
24
+ 1.3: save
25
+ 1.2: new
26
+ 24.2: UsersController#authorize_user
27
+ 4.8: branch
28
+ 4.7: current_user
29
+ 3.6: params
30
+ 3.2: []
31
+ 2.6: ==
32
+ 1.5: role
33
+ 1.5: to_i
34
+ 1.5: id
35
+ 1.4: new_session_path
36
+ 1.3: include?
37
+ 1.2: assignment
38
+ 1.2: flash
39
+ 1.2: redirect_to
40
+ 16.4: UsersController#thank_you
41
+ 4.0: assignment
42
+ 3.3: params
43
+ 2.9: []
44
+ 2.7: redirect_to
45
+ 2.4: branch
46
+ 1.5: new_session_path
47
+ 1.4: flash
48
+ 1.4: activate!
49
+ 1.3: can_activate?
50
+ 1.2: find_by_id
51
+ 14.2: UsersController#update
52
+ 3.2: params
53
+ 2.8: []
54
+ 2.6: assignment
55
+ 1.4: login
56
+ 1.4: flash
57
+ 1.4: redirect_to
58
+ 1.3: render
59
+ 1.2: branch
60
+ 1.2: update_attributes
61
+ 1.2: find_by_id
62
+ 12.5: UsersController#sanitize_params
63
+ 3.9: assignment
64
+ 3.6: branch
65
+ 3.0: current_user
66
+ 1.6: params
67
+ 1.5: role
68
+ 1.4: []
69
+ 1.3: include?
70
+ 1.3: ==
71
+ 1.2: reject!
72
+ 10.6: UsersController#users_have_changed
73
+ 3.9: assignment
74
+ 2.6: branch
75
+ 1.6: params
76
+ 1.5: refresh_from_external
77
+ 1.4: find_by_id
78
+ 1.4: []
79
+ 1.2: split
80
+ 1.2: each
81
+ 1.2: head
82
+ 10.0: UsersController#after_create_page
83
+ 3.0: current_user
84
+ 2.6: id
85
+ 2.4: branch
86
+ 1.5: role
87
+ 1.3: login
88
+ 1.3: ==
89
+ 8.4: UsersController#add_primary_site
90
+ 2.4: assignment
91
+ 1.6: params
92
+ 1.4: []
93
+ 1.4: new
94
+ 1.2: find_by_id
95
+ 1.2: all
96
+ 1.2: render
97
+ 7.7: UsersController#none
98
+ 3.3: before_filter
99
+ 1.1: private
100
+ 1.1: caches_page
101
+ 1.1: after_filter
102
+ 1.1: skip_before_filter
103
+ 7.2: UsersController#destroy
104
+ 1.8: params
105
+ 1.6: []
106
+ 1.4: find_by_id
107
+ 1.2: destroy
108
+ 1.2: redirect_to
109
+ 5.9: UsersController#edit
110
+ 2.4: assignment
111
+ 1.6: params
112
+ 1.4: []
113
+ 1.2: all
114
+ 1.2: find_by_id
115
+ 2.7: UsersController#signup
116
+ 1.2: render
117
+ 1.2: assignment
118
+ 1.2: new
119
+ 1.7: UsersController#new
120
+ 1.2: assignment
121
+ 1.2: new
122
+ 1.7: UsersController#index
123
+ 1.2: assignment
124
+ 1.2: all
125
+ HERE
126
+ end
127
+
128
+ describe "parse method" do
129
+ before :each do
130
+ MetricFu::Configuration.run {}
131
+ File.stub!(:directory?).and_return(true)
132
+ flog = MetricFu::Flog.new('base_dir')
133
+ @flog_page = flog.parse(@text)
134
+ end
135
+
136
+ it "should find the total score" do
137
+ @flog_page.score.should == 157.9
138
+ end
139
+
140
+ it "should find the average score" do
141
+ @flog_page.average_score.should == 11.3
142
+ end
143
+
144
+ it "should find the scanned method score" do
145
+ @flog_page.scanned_methods.first.score.should == 34.8
146
+ end
147
+
148
+ it "should find the scanned method name" do
149
+ @flog_page.scanned_methods.first.name.should == "UsersController#create"
150
+ end
151
+
152
+ it "should find the scanned method opperators names" do
153
+ @flog_page.scanned_methods.first.operators.first.operator.should == "branch"
154
+ end
155
+
156
+ it "should find the scanned method opperators scores" do
157
+ @flog_page.scanned_methods.first.operators.first.score.should == 9.2
158
+ end
159
+
160
+ it "should find the name of the method even if namespaced" do
161
+ text = <<-HERE
162
+ 157.9: flog total
163
+ 11.3: flog/method average
164
+
165
+ 34.8: SomeNamespace::UsersController#create
166
+ HERE
167
+ flog = MetricFu::Flog.new('base_dir')
168
+ flog_page = flog.parse(text)
169
+ flog_page.scanned_methods.first.name.should == "SomeNamespace::UsersController#create"
170
+ end
171
+ end
172
+
173
+ describe "to_h function" do
174
+ before :each do
175
+ MetricFu::Configuration.run {}
176
+ File.stub!(:directory?).and_return(true)
177
+ flog = MetricFu::Flog.new('base_dir')
178
+ flog.should_receive(:open).and_return(@text)
179
+ Dir.should_receive(:glob).and_return(["tmp/metric_fu/scratch/flog/app/controllers/user_controller.txt"])
180
+ flog.analyze
181
+ @flog_hash = flog.to_h
182
+ end
183
+
184
+ it "should put the total in the hash" do
185
+ @flog_hash[:flog][:total].should == 157.9
186
+ end
187
+
188
+ it "should put the average in the hash" do
189
+ @flog_hash[:flog][:average].should == 11.3
190
+ end
191
+
192
+ it "should put pages into the hash" do
193
+ @flog_hash[:flog][:pages].first[:scanned_methods].first[:score].should == 34.8
194
+ end
195
+
196
+ it "should put the filename into the hash" do
197
+ @flog_hash[:flog][:pages].first[:path].should == "/app/controllers/user_controller.rb"
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,59 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Reek do
4
+ describe "analyze method" do
5
+ before :each do
6
+ @lines = <<-HERE
7
+ "app/controllers/activity_reports_controller.rb" -- 4 warnings:
8
+ ActivityReportsController#authorize_user calls current_user.primary_site_ids multiple times (Duplication)
9
+ ActivityReportsController#authorize_user calls params[id] multiple times (Duplication)
10
+ ActivityReportsController#authorize_user calls params[primary_site_id] multiple times (Duplication)
11
+ ActivityReportsController#authorize_user has approx 6 statements (Long Method)
12
+
13
+ "app/controllers/application.rb" -- 1 warnings:
14
+ ApplicationController#start_background_task/block/block is nested (Nested Iterators)
15
+
16
+ "app/controllers/link_targets_controller.rb" -- 1 warnings:
17
+ LinkTargetsController#authorize_user calls current_user.role multiple times (Duplication)
18
+
19
+ "app/controllers/newline_controller.rb" -- 1 warnings:
20
+ NewlineController#some_method calls current_user.<< "new line\n" multiple times (Duplication)
21
+ HERE
22
+ MetricFu::Configuration.run {}
23
+ File.stub!(:directory?).and_return(true)
24
+ reek = MetricFu::Reek.new
25
+ reek.instance_variable_set(:@output, @lines)
26
+ @matches = reek.analyze
27
+ end
28
+
29
+ it "should find the code smell's method name" do
30
+ smell = @matches.first[:code_smells].first
31
+ smell[:method].should == "ActivityReportsController#authorize_user"
32
+ end
33
+
34
+ it "should find the code smell's type" do
35
+ smell = @matches[1][:code_smells].first
36
+ smell[:type].should == "Nested Iterators"
37
+ end
38
+
39
+ it "should find the code smell's message" do
40
+ smell = @matches[1][:code_smells].first
41
+ smell[:message].should == "is nested"
42
+ end
43
+
44
+ it "should find the code smell's type" do
45
+ smell = @matches.first
46
+ smell[:file_path].should == "app/controllers/activity_reports_controller.rb"
47
+ end
48
+
49
+ it "should NOT insert nil smells into the array when there's a newline in the method call" do
50
+ @matches.last[:code_smells].should == @matches.last[:code_smells].compact
51
+ @matches.last.should == {:file_path=>"app/controllers/newline_controller.rb",
52
+ :code_smells=>[{:type=>"Duplication",
53
+ :method=>"\"",
54
+ :message=>"multiple times"}]}
55
+ # Note: hopefully a temporary solution until I figure out how to deal with newlines in the method call more effectively -Jake 5/11/2009
56
+ end
57
+ end
58
+
59
+ end
@@ -0,0 +1,63 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Saikuro do
4
+ describe "to_h method" do
5
+ before :all do
6
+ MetricFu::Configuration.run {}
7
+ File.stub!(:directory?).and_return(true)
8
+ saikuro = MetricFu::Saikuro.new
9
+ saikuro.stub!(:metric_directory).and_return(File.join(File.dirname(__FILE__), "..", "resources", "saikuro"))
10
+ saikuro.analyze
11
+ @output = saikuro.to_h
12
+ end
13
+
14
+ it "should find the filename of a file" do
15
+ @output[:saikuro][:files].first[:filename].should == 'users_controller.rb'
16
+ end
17
+
18
+ it "should find the name of the classes" do
19
+ @output[:saikuro][:classes].first[:name].should == "UsersController"
20
+ @output[:saikuro][:classes][1][:name].should == "SessionsController"
21
+ end
22
+
23
+ it "should put the most complex method first" do
24
+ @output[:saikuro][:methods].first[:name].should == "UsersController#create"
25
+ @output[:saikuro][:methods].first[:complexity].should == 4
26
+ end
27
+
28
+ it "should find the complexity of a method" do
29
+ @output[:saikuro][:methods].first[:complexity].should == 4
30
+ end
31
+
32
+ it "should find the lines of a method" do
33
+ @output[:saikuro][:methods].first[:lines].should == 15
34
+ end
35
+ end
36
+
37
+ describe "emit method" do
38
+ it "should format the directories" do
39
+ MetricFu::Configuration.run {}
40
+ File.stub!(:directory?).and_return(true)
41
+ saikuro = MetricFu::Saikuro.new
42
+
43
+ MetricFu.saikuro[:input_directory] = ["app", "lib"]
44
+
45
+ File.stub!(:dirname).and_return('..')
46
+ File.stub!(:expand_path)
47
+
48
+ saikuro.should_receive(:sh).with(/"app \| lib"/)
49
+
50
+ saikuro.emit
51
+ end
52
+ end
53
+
54
+ describe Saikuro::SFile do
55
+ describe "getting elements from a Saikuro result file" do
56
+ it "should parse nested START/END sections" do
57
+ path = File.join(File.dirname(__FILE__), "..", "resources", "saikuro_sfiles", "thing.rb_cyclo.html")
58
+ sfile = Saikuro::SFile.new path
59
+ sfile.elements.map { |e| e.complexity }.sort.should eql(["0","0","2"])
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,74 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Stats do
4
+ describe "emit method" do
5
+ it "should gather the raw data" do
6
+ MetricFu::Configuration.run {}
7
+ File.stub!(:directory?).and_return(true)
8
+ stats = MetricFu::Stats.new
9
+ stats.should_receive(:`).with("rake stats > tmp/metric_fu/scratch/stats/stats.txt")
10
+ stats.emit
11
+ end
12
+ end
13
+
14
+ describe "analyze method" do
15
+ before :each do
16
+ @lines = <<-HERE.gsub(/^\s*/, "")
17
+ +----------------------+-------+-------+---------+---------+-----+-------+
18
+ | Name | Lines | LOC | Classes | Methods | M/C | LOC/M |
19
+ +----------------------+-------+-------+---------+---------+-----+-------+
20
+ | Controllers | 470 | 382 | 7 | 53 | 7 | 5 |
21
+ | Helpers | 128 | 65 | 0 | 6 | 0 | 8 |
22
+ | Models | 351 | 285 | 9 | 31 | 3 | 7 |
23
+ | Libraries | 305 | 183 | 2 | 30 | 15 | 4 |
24
+ | Model specs | 860 | 719 | 0 | 2 | 0 | 357 |
25
+ | View specs | 0 | 0 | 0 | 0 | 0 | 0 |
26
+ | Controller specs | 1570 | 1308 | 1 | 10 | 10 | 128 |
27
+ | Helper specs | 191 | 172 | 0 | 0 | 0 | 0 |
28
+ | Library specs | 31 | 27 | 0 | 0 | 0 | 0 |
29
+ +----------------------+-------+-------+---------+---------+-----+-------+
30
+ | Total | 3906 | 3141 | 19 | 132 | 6 | 21 |
31
+ +----------------------+-------+-------+---------+---------+-----+-------+
32
+ Code LOC: 915 Test LOC: 2226 Code to Test Ratio: 1:2.4
33
+
34
+ HERE
35
+ MetricFu::Configuration.run {}
36
+ File.stub!(:directory?).and_return(true)
37
+ stats = MetricFu::Stats.new
38
+ File.should_receive(:open).and_return(mock("file", :read => @lines))
39
+ @results = stats.analyze
40
+ end
41
+
42
+ it "should get code Lines Of Code" do
43
+ @results[:codeLOC].should == 915
44
+ end
45
+
46
+ it "should get test Lines Of Code" do
47
+ @results[:testLOC].should == 2226
48
+ end
49
+
50
+ it "should get code to test ratio" do
51
+ @results[:code_to_test_ratio].should == 2.4
52
+ end
53
+
54
+ it "should get data on models" do
55
+ model_data = @results[:lines].find {|line| line[:name] == "Models"}
56
+ model_data[:classes].should == 9
57
+ model_data[:methods].should == 31
58
+ model_data[:loc].should == 285
59
+ model_data[:lines].should == 351
60
+ model_data[:methods_per_class].should == 3
61
+ model_data[:loc_per_method].should == 7
62
+ end
63
+ end
64
+
65
+ describe "to_h method" do
66
+ it "should put things into a hash" do
67
+ MetricFu::Configuration.run {}
68
+ File.stub!(:directory?).and_return(true)
69
+ stats = MetricFu::Stats.new
70
+ stats.instance_variable_set(:@stats, "the_stats")
71
+ stats.to_h[:stats].should == "the_stats"
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+ require 'date'
4
+
5
+ require File.join(File.dirname(__FILE__), '/../lib/metric_fu.rb')
6
+ include MetricFu
7
+
8
+ Mystat = <<-EOF
9
+ (in /Users/gmcinnes/Documents/projects/NeerBeer/src/Web)
10
+ +----------------------+-------+-------+---------+---------+-----+-------+
11
+ | Name | Lines | LOC | Classes | Methods | M/C | LOC/M |
12
+ +----------------------+-------+-------+---------+---------+-----+-------+
13
+ | Controllers | 893 | 405 | 16 | 41 | 2 | 7 |
14
+ | Helpers | 569 | 352 | 0 | 52 | 0 | 4 |
15
+ | Models | 1758 | 453 | 26 | 48 | 1 | 7 |
16
+ | Libraries | 2507 | 1320 | 19 | 175 | 9 | 5 |
17
+ | Model specs | 2285 | 965 | 0 | 1 | 0 | 963 |
18
+ | View specs | 821 | 654 | 0 | 2 | 0 | 325 |
19
+ | Controller specs | 1144 | 871 | 0 | 9 | 0 | 94 |
20
+ | Helper specs | 652 | 465 | 0 | 1 | 0 | 463 |
21
+ | Library specs | 1456 | 1141 | 8 | 14 | 1 | 79 |
22
+ +----------------------+-------+-------+---------+---------+-----+-------+
23
+ | Total | 12085 | 6626 | 69 | 343 | 4 | 17 |
24
+ +----------------------+-------+-------+---------+---------+-----+-------+
25
+ Code LOC: 2530 Test LOC: 4096 Code to Test Ratio: 1:1.6
26
+
27
+ EOF
28
+
@@ -0,0 +1,15 @@
1
+ require 'rake'
2
+ namespace :metrics do
3
+ desc "Generate all metrics reports"
4
+ task :all do
5
+ MetricFu::Configuration.run {}
6
+ MetricFu.metrics.each {|metric| MetricFu.report.add(metric) }
7
+ MetricFu.report.save_output(MetricFu.report.to_yaml,
8
+ MetricFu.base_directory,
9
+ 'report.yml')
10
+ MetricFu.report.save_templatized_report
11
+ if MetricFu.report.open_in_browser?
12
+ MetricFu.report.show_in_browser(MetricFu.output_directory)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,39 @@
1
+ namespace :metrics do
2
+
3
+ RAILROAD_DIR = File.join(MetricFu::BASE_DIRECTORY, 'railroad')
4
+ RAILROAD_FILE = File.join(RAILROAD_DIR, 'index.html')
5
+
6
+ task :railroad => ['railroad:all'] do
7
+ end
8
+
9
+ namespace :railroad do
10
+
11
+ desc "Create all railroad reports"
12
+ task :all => [:models, :controllers, :aasm] do
13
+ #system("open #{RAILROAD_INDEX}") if PLATFORM['darwin']
14
+ end
15
+
16
+ desc "Create a railroad models report"
17
+ task :models do
18
+ #mkdir_p(RAILROAD_DIR) unless File.directory?(RAILROAD_DIR)
19
+ `railroad -M -a -m -l -v | neato -Tpng > #{File.join(MetricFu::BASE_DIRECTORY,'model-diagram.png')}`
20
+ #`echo "<a href=\"railroad/models.png\">Model diagram</a><br />" >> #{RAILROAD_FILE}`
21
+ end
22
+
23
+ desc "Create a railroad controllers report"
24
+ task :controllers do
25
+ #mkdir_p(RAILROAD_DIR) unless File.directory?(RAILROAD_DIR)
26
+ `railroad -C -l -v | neato -Tpng > #{File.join(MetricFu::BASE_DIRECTORY,'controller-diagram.png')}`
27
+ #`echo "<a href=\"railroad/controllers.png\">Controller diagram</a><br />" >> #{RAILROAD_FILE}`
28
+ end
29
+
30
+ desc "Create a railroad acts_as_state_machine report"
31
+ task :aasm do
32
+ #mkdir_p(RAILROAD_DIR) unless File.directory?(RAILROAD_DIR)
33
+ `railroad -A -l -v | neato -Tpng > #{File.join(MetricFu::BASE_DIRECTORY,'aasm-diagram.png')}`
34
+ #`echo "<a href=\"railroad/aasm.png\">State machine diagram</a><br />" >> #{RAILROAD_FILE}`
35
+ end
36
+
37
+ end
38
+
39
+ end