nielsm-metric_fu 0.9.1 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. data/HISTORY +38 -0
  2. data/README +1 -154
  3. data/Rakefile +9 -2
  4. data/TODO +3 -3
  5. data/lib/base/base_template.rb +146 -0
  6. data/lib/base/configuration.rb +207 -0
  7. data/lib/base/generator.rb +160 -0
  8. data/lib/base/graph.rb +37 -0
  9. data/lib/{metric_fu → base}/md5_tracker.rb +0 -0
  10. data/lib/base/report.rb +100 -0
  11. data/lib/{metric_fu → generators}/churn.rb +26 -23
  12. data/lib/generators/flay.rb +34 -0
  13. data/lib/generators/flog.rb +140 -0
  14. data/lib/generators/rcov.rb +87 -0
  15. data/lib/generators/reek.rb +37 -0
  16. data/lib/generators/roodi.rb +31 -0
  17. data/lib/generators/saikuro.rb +208 -0
  18. data/lib/generators/stats.rb +43 -0
  19. data/lib/graphs/flay_grapher.rb +34 -0
  20. data/lib/graphs/flog_grapher.rb +37 -0
  21. data/lib/graphs/rcov_grapher.rb +34 -0
  22. data/lib/graphs/reek_grapher.rb +44 -0
  23. data/lib/graphs/roodi_grapher.rb +34 -0
  24. data/lib/metric_fu.rb +24 -3
  25. data/lib/templates/awesome/awesome_template.rb +30 -0
  26. data/lib/templates/awesome/churn.html.erb +19 -0
  27. data/lib/templates/awesome/default.css +75 -0
  28. data/lib/templates/awesome/flay.html.erb +27 -0
  29. data/lib/templates/awesome/flog.html.erb +46 -0
  30. data/lib/templates/awesome/index.html.erb +28 -0
  31. data/lib/templates/awesome/layout.html.erb +27 -0
  32. data/lib/templates/awesome/rcov.html.erb +36 -0
  33. data/lib/templates/awesome/reek.html.erb +34 -0
  34. data/lib/templates/awesome/roodi.html.erb +21 -0
  35. data/lib/templates/awesome/saikuro.html.erb +71 -0
  36. data/lib/templates/awesome/stats.html.erb +41 -0
  37. data/lib/templates/{churn.html.erb → standard/churn.html.erb} +13 -4
  38. data/lib/templates/{default.css → standard/default.css} +20 -1
  39. data/lib/templates/{flay.html.erb → standard/flay.html.erb} +13 -9
  40. data/lib/templates/standard/flog.html.erb +53 -0
  41. data/lib/templates/standard/index.html.erb +38 -0
  42. data/lib/templates/standard/rcov.html.erb +43 -0
  43. data/lib/templates/standard/reek.html.erb +42 -0
  44. data/lib/templates/{roodi.html.erb → standard/roodi.html.erb} +11 -8
  45. data/lib/templates/standard/saikuro.html.erb +84 -0
  46. data/lib/templates/standard/standard_template.rb +26 -0
  47. data/lib/templates/standard/stats.html.erb +55 -0
  48. data/spec/base/base_template_spec.rb +161 -0
  49. data/spec/base/configuration_spec.rb +303 -0
  50. data/spec/base/generator_spec.rb +181 -0
  51. data/spec/{md5_tracker_spec.rb → base/md5_tracker_spec.rb} +1 -1
  52. data/spec/base/report_spec.rb +139 -0
  53. data/spec/generators/churn_spec.rb +152 -0
  54. data/spec/generators/flay_spec.rb +104 -0
  55. data/spec/generators/flog_spec.rb +219 -0
  56. data/spec/generators/reek_spec.rb +60 -0
  57. data/spec/generators/saikuro_spec.rb +58 -0
  58. data/spec/generators/stats_spec.rb +74 -0
  59. data/spec/graphs/flog_grapher_spec.rb +15 -0
  60. data/spec/resources/saikuro/app/controllers/sessions_controller.rb_cyclo.html +10 -0
  61. data/spec/resources/saikuro/app/controllers/users_controller.rb_cyclo.html +16 -0
  62. data/spec/resources/saikuro/index_cyclo.html +155 -0
  63. data/spec/resources/saikuro_sfiles/thing.rb_cyclo.html +10 -0
  64. data/spec/spec.opts +8 -0
  65. data/spec/spec_helper.rb +24 -7
  66. data/tasks/metric_fu.rake +22 -0
  67. data/vendor/_fonts/monaco.ttf +0 -0
  68. data/{lib/metric_fu → vendor}/saikuro/saikuro.rb +0 -0
  69. metadata +84 -66
  70. data/lib/metric_fu/base.rb +0 -160
  71. data/lib/metric_fu/flay.rb +0 -17
  72. data/lib/metric_fu/flog.rb +0 -129
  73. data/lib/metric_fu/reek.rb +0 -17
  74. data/lib/metric_fu/roodi.rb +0 -17
  75. data/lib/tasks/churn.rake +0 -9
  76. data/lib/tasks/coverage.rake +0 -54
  77. data/lib/tasks/flay.rake +0 -6
  78. data/lib/tasks/flog.rake +0 -69
  79. data/lib/tasks/metric_fu.rake +0 -24
  80. data/lib/tasks/metric_fu.rb +0 -6
  81. data/lib/tasks/railroad.rake +0 -39
  82. data/lib/tasks/reek.rake +0 -6
  83. data/lib/tasks/roodi.rake +0 -7
  84. data/lib/tasks/saikuro.rake +0 -35
  85. data/lib/tasks/stats.rake +0 -14
  86. data/lib/templates/flog.html.erb +0 -38
  87. data/lib/templates/flog_page.html.erb +0 -25
  88. data/lib/templates/reek.html.erb +0 -30
  89. data/spec/base_spec.rb +0 -57
  90. data/spec/churn_spec.rb +0 -117
  91. data/spec/config_spec.rb +0 -110
  92. data/spec/flay_spec.rb +0 -19
  93. data/spec/flog_spec.rb +0 -208
  94. data/spec/reek_spec.rb +0 -26
@@ -1,160 +0,0 @@
1
- require 'erb'
2
- module MetricFu
3
-
4
- TEMPLATE_DIR = File.join(File.dirname(__FILE__), '..', 'templates')
5
- BASE_DIRECTORY = ENV['CC_BUILD_ARTIFACTS'] || 'tmp/metric_fu'
6
- RAILS = File.exist?("config/environment.rb")
7
-
8
- if RAILS
9
- CODE_DIRS = ['app', 'lib']
10
- DEFAULT_METRICS = [:coverage, :churn, :flog, :flay, :reek, :roodi, :stats, :saikuro ]
11
- else
12
- CODE_DIRS = ['lib']
13
- DEFAULT_METRICS = [:coverage, :churn, :flog, :flay, :reek, :roodi, :saikuro ]
14
- end
15
-
16
- module Base
17
-
18
- ######################################################################
19
- # Base class for report Generators
20
- #
21
- class Generator
22
-
23
- def initialize(options={})
24
- @base_dir = self.class.metric_dir
25
- end
26
-
27
- def self.metric_dir
28
- File.join(BASE_DIRECTORY, template_name)
29
- end
30
-
31
- def self.template_name
32
- self.to_s.split('::').last.downcase
33
- end
34
-
35
- def self.generate_report(options={})
36
- FileUtils.mkdir_p(metric_dir, :verbose => false) unless File.directory?(metric_dir)
37
- self.new(options).generate_report
38
- end
39
-
40
- def save_html(content, file='index.html')
41
- open("#{@base_dir}/#{file}", "w") do |f|
42
- f.puts content
43
- end
44
- end
45
-
46
- def generate_report
47
- save_html(generate_html)
48
- end
49
-
50
- def generate_html
51
- analyze
52
- html = ERB.new(File.read(template_file)).result(binding)
53
- end
54
-
55
- def template_name
56
- self.class.template_name
57
- end
58
-
59
- def template_file
60
- File.join(MetricFu::TEMPLATE_DIR, "#{template_name}.html.erb")
61
- end
62
-
63
- ########################
64
- # Template methods
65
-
66
- def inline_css(css)
67
- open(File.join(MetricFu::TEMPLATE_DIR, css)) { |f| f.read }
68
- end
69
-
70
- def link_to_filename(name, line = nil)
71
- filename = File.expand_path(name)
72
- if PLATFORM['darwin']
73
- %{<a href="txmt://open/?url=file://#{filename}&line=#{line}">#{name}:#{line}</a>}
74
- else
75
- %{<a href="file://#{filename}">#{name}:#{line}</a>}
76
- end
77
- end
78
-
79
- def cycle(first_value, second_value, iteration)
80
- return first_value if iteration % 2 == 0
81
- return second_value
82
- end
83
- end
84
- end
85
-
86
- class << self
87
- # The Configuration instance used to configure the Rails environment
88
- def configuration
89
- @@configuration ||= Configuration.new
90
- end
91
-
92
- def churn
93
- configuration.churn
94
- end
95
-
96
- def coverage
97
- configuration.coverage
98
- end
99
-
100
- def flay
101
- configuration.flay
102
- end
103
-
104
- def flog
105
- configuration.flog
106
- end
107
-
108
- def metrics
109
- configuration.metrics
110
- end
111
-
112
- def open_in_browser?
113
- PLATFORM['darwin'] && !ENV['CC_BUILD_ARTIFACTS']
114
- end
115
-
116
- def saikuro
117
- configuration.saikuro
118
- end
119
-
120
- def reek
121
- configuration.reek
122
- end
123
-
124
- def roodi
125
- configuration.roodi
126
- end
127
-
128
- end
129
-
130
- class Configuration
131
- attr_accessor :churn, :coverage, :flay, :flog, :metrics, :reek, :roodi, :saikuro
132
- def initialize
133
- raise "Use config.churn instead of MetricFu::CHURN_OPTIONS" if defined? ::MetricFu::CHURN_OPTIONS
134
- raise "Use config.flog[:dirs_to_flog] instead of MetricFu::DIRECTORIES_TO_FLOG" if defined? ::MetricFu::DIRECTORIES_TO_FLOG
135
- raise "Use config.saikuro instead of MetricFu::SAIKURO_OPTIONS" if defined? ::MetricFu::SAIKURO_OPTIONS
136
- reset
137
- end
138
-
139
- def self.run()
140
- yield MetricFu.configuration
141
- end
142
-
143
- def reset
144
- @churn = {}
145
- @coverage = { :test_files => ['test/**/*_test.rb', 'spec/**/*_spec.rb'],
146
- :rcov_opts => ["--sort coverage", "--html", "--rails", "--exclude /gems/,/Library/,spec"] }
147
- @flay = { :dirs_to_flay => CODE_DIRS}
148
- @flog = { :dirs_to_flog => CODE_DIRS}
149
- @reek = { :dirs_to_reek => CODE_DIRS}
150
- @roodi = { :dirs_to_roodi => CODE_DIRS}
151
- @metrics = DEFAULT_METRICS
152
- @saikuro = {}
153
- end
154
-
155
- def saikuro=(options)
156
- raise "saikuro need to be a Hash" unless options.is_a?(Hash)
157
- @saikuro = options
158
- end
159
- end
160
- end
@@ -1,17 +0,0 @@
1
- module MetricFu
2
-
3
- def self.generate_flay_report
4
- Flay.generate_report
5
- system("open #{Flay.metric_dir}/index.html") if open_in_browser?
6
- end
7
-
8
- class Flay < Base::Generator
9
-
10
- def analyze
11
- files_to_flay = MetricFu.flay[:dirs_to_flay].map{|dir| Dir[File.join(dir, "**/*.rb")] }
12
- output = `flay #{files_to_flay.join(" ")}`
13
- @matches = output.chomp.split("\n\n").map{|m| m.split("\n ") }
14
- end
15
-
16
- end
17
- end
@@ -1,129 +0,0 @@
1
- module MetricFu
2
-
3
- def self.generate_flog_report
4
- Flog::Generator.generate_report
5
- system("open #{Flog::Generator.metric_dir}/index.html") if open_in_browser?
6
- end
7
-
8
- module Flog
9
- class Generator < Base::Generator
10
- def generate_report
11
- @base_dir = self.class.metric_dir
12
- pages = []
13
- flog_results.each do |filename|
14
- page = Base.parse(open(filename, "r") { |f| f.read })
15
- if page
16
- page.filename = filename
17
- pages << page
18
- end
19
- end
20
- generate_pages(pages)
21
- end
22
-
23
- def generate_pages(pages)
24
- pages.each do |page|
25
- unless MetricFu::MD5Tracker.file_already_counted?(page.filename)
26
- generate_page(page)
27
- end
28
- end
29
- save_html(ERB.new(File.read(template_file)).result(binding))
30
- end
31
-
32
- def generate_page(page)
33
- save_html(page.to_html, page.path)
34
- end
35
-
36
- def flog_results
37
- Dir.glob("#{@base_dir}/**/*.txt")
38
- end
39
-
40
- def self.template_name
41
- "flog"
42
- end
43
- end
44
-
45
- SCORE_FORMAT = "%0.2f"
46
-
47
- class Base
48
- METHOD_LINE_REGEX = /([A-Za-z]+#.*):\s\((\d+\.\d+)\)/
49
- OPERATOR_LINE_REGEX = /\s+(\d+\.\d+):\s(.*)$/
50
-
51
- class << self
52
-
53
- def parse(text)
54
- score = text[/\w+ = (\d+\.\d+)/, 1]
55
- return nil unless score
56
- page = Page.new(score)
57
-
58
- text.each_line do |method_line|
59
- if match = method_line.match(METHOD_LINE_REGEX)
60
- page.scanned_methods << ScannedMethod.new(match[1], match[2])
61
- end
62
-
63
- if match = method_line.match(OPERATOR_LINE_REGEX)
64
- return if page.scanned_methods.empty?
65
- page.scanned_methods.last.operators << Operator.new(match[1], match[2])
66
- end
67
- end
68
- page
69
- end
70
-
71
- end
72
- end
73
-
74
- class Page < MetricFu::Base::Generator
75
- attr_accessor :filename, :score, :scanned_methods
76
-
77
- def initialize(score, scanned_methods = [])
78
- @score = score.to_f
79
- @scanned_methods = scanned_methods
80
- end
81
-
82
- def path
83
- @path ||= File.basename(filename, ".txt") + '.html'
84
- end
85
-
86
- def to_html
87
- ERB.new(File.read(template_file)).result(binding)
88
- end
89
-
90
- def average_score
91
- return 0 if scanned_methods.length == 0
92
- sum = 0
93
- scanned_methods.each do |m|
94
- sum += m.score
95
- end
96
- sum / scanned_methods.length
97
- end
98
-
99
- def highest_score
100
- scanned_methods.inject(0) do |highest, m|
101
- m.score > highest ? m.score : highest
102
- end
103
- end
104
-
105
- def template_name
106
- 'flog_page'
107
- end
108
- end
109
-
110
- class Operator
111
- attr_accessor :score, :operator
112
-
113
- def initialize(score, operator)
114
- @score = score.to_f
115
- @operator = operator
116
- end
117
- end
118
-
119
- class ScannedMethod
120
- attr_accessor :name, :score, :operators
121
-
122
- def initialize(name, score, operators = [])
123
- @name = name
124
- @score = score.to_f
125
- @operators = operators
126
- end
127
- end
128
- end
129
- end
@@ -1,17 +0,0 @@
1
- module MetricFu
2
-
3
- def self.generate_reek_report
4
- Reek.generate_report
5
- system("open #{Reek.metric_dir}/index.html") if open_in_browser?
6
- end
7
-
8
- class Reek < Base::Generator
9
-
10
- def analyze
11
- files_to_reek = MetricFu.reek[:dirs_to_reek].map{|dir| Dir[File.join(dir, "**/*.rb")] }
12
- output = `reek #{files_to_reek.join(" ")}`
13
- @matches = output.chomp.split("\n\n").map{|m| m.split("\n") }
14
- end
15
-
16
- end
17
- end
@@ -1,17 +0,0 @@
1
- module MetricFu
2
-
3
- def self.generate_roodi_report
4
- MetricFu::Roodi.generate_report
5
- system("open #{Roodi.metric_dir}/index.html") if open_in_browser?
6
- end
7
-
8
- class Roodi < Base::Generator
9
-
10
- def analyze
11
- files_to_analyze = MetricFu.roodi[:dirs_to_roodi].map{|dir| Dir[File.join(dir, "**/*.rb")] }
12
- output = `roodi #{files_to_analyze.join(" ")}`
13
- @matches = output.chomp.split("\n").map{|m| m.split(" - ") }
14
- end
15
-
16
- end
17
- end
data/lib/tasks/churn.rake DELETED
@@ -1,9 +0,0 @@
1
- require File.join(File.dirname(__FILE__), '../metric_fu/churn')
2
-
3
- namespace :metrics do
4
-
5
- desc "Which files change the most"
6
- task :churn do
7
- MetricFu.generate_churn_report
8
- end
9
- end
@@ -1,54 +0,0 @@
1
- require 'fileutils'
2
-
3
- begin
4
- require 'rcov'
5
- require 'rcov/rcovtask'
6
- require 'spec/rake/spectask'
7
-
8
- namespace :metrics do
9
-
10
- COVERAGE_DIR = File.join(MetricFu::BASE_DIRECTORY, 'coverage')
11
- COVERAGE_DATA_FILE = File.join(MetricFu::BASE_DIRECTORY, 'coverage.data')
12
- SPEC_HTML_FILE = File.join(MetricFu::BASE_DIRECTORY, 'specs.html')
13
-
14
- namespace :coverage do
15
- rcov_output = COVERAGE_DIR
16
-
17
- desc "Delete aggregate coverage data."
18
- task(:clean) { rm_f("rcov_tmp", :verbose => false) }
19
-
20
- desc "RCov task to generate report"
21
- Rcov::RcovTask.new(:do => :clean) do |t|
22
- FileUtils.mkdir_p(MetricFu::BASE_DIRECTORY) unless File.directory?(MetricFu::BASE_DIRECTORY)
23
- t.test_files = FileList[*MetricFu.coverage[:test_files]]
24
- t.rcov_opts = MetricFu.coverage[:rcov_opts]
25
- t.output_dir = COVERAGE_DIR
26
- # this line is a fix for Rails 2.1 relative loading issues
27
- t.libs << 'test'
28
- end
29
- # TODO not sure what this improves but it requires the diff-lcs gem
30
- # http://github.com/indirect/metric_fu/commit/b9c1cf75f09d5b531b388cd01661eb16b5126968#diff-1
31
- # Spec::Rake::SpecTask.new(:do => :clean) do |t|
32
- # FileUtils.mkdir_p(MetricFu::BASE_DIRECTORY) unless File.directory?(MetricFu::BASE_DIRECTORY)
33
- # t.ruby_opts = ['-rtest/unit']
34
- # t.spec_files = FileList['test/**/*_test.rb', 'spec/**/*spec.rb']
35
- # t.spec_opts = ["--format", "html:#{SPEC_HTML_FILE}", "--diff"]
36
- # t.rcov = true
37
- # t.rcov_opts = ["--sort coverage", "--html", "--rails", "--exclude /gems/,/Library/"]
38
- # t.rcov_dir = COVERAGE_DIR
39
- # end
40
- end
41
-
42
- desc "Generate and open coverage report"
43
- task :coverage => ['coverage:do'] do
44
- system("open #{COVERAGE_DIR}/index.html") if MetricFu.open_in_browser?
45
- end
46
- end
47
- rescue LoadError
48
- if RUBY_PLATFORM =~ /java/
49
- puts 'running in jruby - rcov tasks not available'
50
- else
51
- puts 'sudo gem install rcov # if you want the rcov tasks'
52
-
53
- end
54
- end
data/lib/tasks/flay.rake DELETED
@@ -1,6 +0,0 @@
1
- namespace :metrics do
2
- desc "Generate code duplication report with flay"
3
- task :flay do
4
- MetricFu.generate_flay_report
5
- end
6
- end
data/lib/tasks/flog.rake DELETED
@@ -1,69 +0,0 @@
1
- begin
2
-
3
- def flog(output, directory)
4
- metric_dir = MetricFu::Flog::Generator.metric_dir
5
- Dir.glob("#{directory}/**/*.rb").each do |filename|
6
- output_dir = "#{metric_dir}/#{filename.split("/")[0..-2].join("/")}"
7
- mkdir_p(output_dir, :verbose => false) unless File.directory?(output_dir)
8
- if MetricFu::MD5Tracker.file_changed?(filename, metric_dir)
9
- `flog #{filename} > #{metric_dir}/#{filename.split('.')[0]}.txt`
10
- end
11
- end
12
- end
13
-
14
- namespace :metrics do
15
-
16
- task :flog => ['flog:all'] do
17
- end
18
-
19
- namespace :flog do
20
- desc "Delete aggregate flog data."
21
- task(:clean) { rm_rf(MetricFu::Flog.metric_dir, :verbose => false) }
22
-
23
- desc "Flog code in app/models"
24
- task :models do
25
- flog "models", "app/models"
26
- end
27
-
28
- desc "Flog code in app/controllers"
29
- task :controllers do
30
- flog "controllers", "app/controllers"
31
- end
32
-
33
- desc "Flog code in app/helpers"
34
- task :helpers do
35
- flog "helpers", "app/helpers"
36
- end
37
-
38
- desc "Flog code in lib"
39
- task :lib do
40
- flog "lib", "lib"
41
- end
42
-
43
- desc "Generate a flog report from specified directories"
44
- task :custom do
45
- MetricFu::flog[:dirs_to_flog].each { |directory| flog(directory, directory) }
46
- MetricFu.generate_flog_report
47
- end
48
-
49
- desc "Generate and open flog report"
50
- if MetricFu::RAILS
51
- task :all => [:models, :controllers, :helpers, :lib] do
52
- MetricFu.generate_flog_report
53
- end
54
- else
55
- task :all => [:custom] do
56
- MetricFu.generate_flog_report
57
- end
58
- end
59
-
60
- end
61
-
62
- end
63
- rescue LoadError
64
- if RUBY_PLATFORM =~ /java/
65
- puts 'running in jruby - flog tasks not available'
66
- else
67
- puts 'sudo gem install flog # if you want the flog tasks'
68
- end
69
- end