iain-metric_fu 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. data/HISTORY +159 -0
  2. data/MIT-LICENSE +22 -0
  3. data/Manifest +103 -0
  4. data/README +1 -0
  5. data/Rakefile +29 -0
  6. data/TODO +9 -0
  7. data/home_page/back_all.jpg +0 -0
  8. data/home_page/churn.gif +0 -0
  9. data/home_page/flay.gif +0 -0
  10. data/home_page/flog.gif +0 -0
  11. data/home_page/footer.gif +0 -0
  12. data/home_page/header.jpg +0 -0
  13. data/home_page/img09.gif +0 -0
  14. data/home_page/index.html +270 -0
  15. data/home_page/rcov.gif +0 -0
  16. data/home_page/reek.gif +0 -0
  17. data/home_page/roodi.gif +0 -0
  18. data/home_page/saikuro.gif +0 -0
  19. data/home_page/stats.gif +0 -0
  20. data/home_page/styles.css +245 -0
  21. data/home_page/title.gif +0 -0
  22. data/home_page/title_back.gif +0 -0
  23. data/lib/base/base_template.rb +146 -0
  24. data/lib/base/configuration.rb +187 -0
  25. data/lib/base/generator.rb +160 -0
  26. data/lib/base/graph.rb +38 -0
  27. data/lib/base/md5_tracker.rb +52 -0
  28. data/lib/base/report.rb +100 -0
  29. data/lib/generators/churn.rb +90 -0
  30. data/lib/generators/flay.rb +33 -0
  31. data/lib/generators/flog.rb +140 -0
  32. data/lib/generators/rcov.rb +87 -0
  33. data/lib/generators/reek.rb +37 -0
  34. data/lib/generators/roodi.rb +31 -0
  35. data/lib/generators/saikuro.rb +208 -0
  36. data/lib/generators/stats.rb +43 -0
  37. data/lib/graphs/flay_grapher.rb +35 -0
  38. data/lib/graphs/flog_grapher.rb +51 -0
  39. data/lib/graphs/grapher.rb +19 -0
  40. data/lib/graphs/rcov_grapher.rb +34 -0
  41. data/lib/graphs/reek_grapher.rb +44 -0
  42. data/lib/graphs/roodi_grapher.rb +34 -0
  43. data/lib/graphs/stats_grapher.rb +37 -0
  44. data/lib/metric_fu.rb +30 -0
  45. data/lib/templates/awesome/awesome_template.rb +30 -0
  46. data/lib/templates/awesome/churn.html.erb +19 -0
  47. data/lib/templates/awesome/css/buttons.css +82 -0
  48. data/lib/templates/awesome/css/default.css +81 -0
  49. data/lib/templates/awesome/css/integrity.css +335 -0
  50. data/lib/templates/awesome/css/reset.css +7 -0
  51. data/lib/templates/awesome/flay.html.erb +27 -0
  52. data/lib/templates/awesome/flog.html.erb +47 -0
  53. data/lib/templates/awesome/index.html.erb +28 -0
  54. data/lib/templates/awesome/js/sorttable.js +492 -0
  55. data/lib/templates/awesome/layout.html.erb +34 -0
  56. data/lib/templates/awesome/rcov.html.erb +36 -0
  57. data/lib/templates/awesome/reek.html.erb +34 -0
  58. data/lib/templates/awesome/roodi.html.erb +21 -0
  59. data/lib/templates/awesome/saikuro.html.erb +71 -0
  60. data/lib/templates/awesome/stats.html.erb +46 -0
  61. data/lib/templates/standard/churn.html.erb +31 -0
  62. data/lib/templates/standard/default.css +64 -0
  63. data/lib/templates/standard/flay.html.erb +34 -0
  64. data/lib/templates/standard/flog.html.erb +53 -0
  65. data/lib/templates/standard/index.html.erb +38 -0
  66. data/lib/templates/standard/rcov.html.erb +43 -0
  67. data/lib/templates/standard/reek.html.erb +42 -0
  68. data/lib/templates/standard/roodi.html.erb +29 -0
  69. data/lib/templates/standard/saikuro.html.erb +84 -0
  70. data/lib/templates/standard/standard_template.rb +26 -0
  71. data/lib/templates/standard/stats.html.erb +55 -0
  72. data/metric_fu.gemspec +42 -0
  73. data/spec/base/base_template_spec.rb +161 -0
  74. data/spec/base/configuration_spec.rb +300 -0
  75. data/spec/base/generator_spec.rb +181 -0
  76. data/spec/base/graph_spec.rb +24 -0
  77. data/spec/base/md5_tracker_spec.rb +57 -0
  78. data/spec/base/report_spec.rb +139 -0
  79. data/spec/generators/churn_spec.rb +152 -0
  80. data/spec/generators/flay_spec.rb +104 -0
  81. data/spec/generators/flog_spec.rb +219 -0
  82. data/spec/generators/reek_spec.rb +60 -0
  83. data/spec/generators/saikuro_spec.rb +58 -0
  84. data/spec/generators/stats_spec.rb +74 -0
  85. data/spec/graphs/flay_grapher_spec.rb +44 -0
  86. data/spec/graphs/flog_grapher_spec.rb +61 -0
  87. data/spec/graphs/grapher_spec.rb +9 -0
  88. data/spec/graphs/rcov_grapher_spec.rb +44 -0
  89. data/spec/graphs/reek_grapher_spec.rb +53 -0
  90. data/spec/graphs/roodi_grapher_spec.rb +44 -0
  91. data/spec/graphs/stats_grapher_spec.rb +60 -0
  92. data/spec/resources/saikuro/app/controllers/sessions_controller.rb_cyclo.html +10 -0
  93. data/spec/resources/saikuro/app/controllers/users_controller.rb_cyclo.html +16 -0
  94. data/spec/resources/saikuro/index_cyclo.html +155 -0
  95. data/spec/resources/saikuro_sfiles/thing.rb_cyclo.html +11 -0
  96. data/spec/resources/yml/20090630.yml +7844 -0
  97. data/spec/resources/yml/20090822.yml +8342 -0
  98. data/spec/spec.opts +8 -0
  99. data/spec/spec_helper.rb +6 -0
  100. data/tasks/metric_fu.rake +22 -0
  101. data/vendor/_fonts/monaco.ttf +0 -0
  102. data/vendor/saikuro/SAIKURO_README +142 -0
  103. data/vendor/saikuro/saikuro.rb +1219 -0
  104. metadata +251 -0
@@ -0,0 +1,245 @@
1
+ /*
2
+ Design by Metamorphosis Design
3
+ http://www.metamorphozis.com
4
+ Released for free under a Creative Commons Attribution 2.5 License
5
+ */
6
+
7
+ a:link {
8
+ color: #3886E0;
9
+ }
10
+
11
+ a:hover, {
12
+ text-decoration: underline;
13
+ color: #FF0000;
14
+ }
15
+
16
+ a:visited {
17
+ color: #3886E0;
18
+ }
19
+
20
+ *
21
+ {
22
+ border: 0;
23
+ margin: 0;
24
+ }
25
+
26
+ body
27
+ {
28
+ background: #ffffff url(back_all.jpg) repeat-x top;
29
+ font: 12px Tahoma, Arial, Helvetica, sans-serif;
30
+ color: #666666;
31
+ margin-top: 10px;
32
+ }
33
+
34
+ #main
35
+ {
36
+ margin: 0 auto;
37
+ width: 912px;
38
+ background: url(table_back.jpg) repeat-y;
39
+ }
40
+
41
+ #header
42
+ {
43
+ background: url(header.jpg) no-repeat;
44
+ width: 912px;
45
+ height: 262px;
46
+ }
47
+
48
+ #logo
49
+ {
50
+ padding-left: 40px;
51
+ text-align: left;
52
+ padding-top: 40px;
53
+ height: 40px;
54
+ }
55
+
56
+ #logo a {
57
+ text-decoration: none;
58
+ text-transform: lowercase;
59
+ font-style: italic;
60
+ font-size: 16px;
61
+ color: #000000;
62
+ font-weight: bold;
63
+ }
64
+
65
+
66
+ #logo H2 a
67
+ {
68
+ font-size: 10px;
69
+ }
70
+
71
+ #buttons
72
+ {
73
+ padding-top: 140px;
74
+ height: 40px;
75
+ padding-left: 120px;
76
+ }
77
+
78
+ #buttons li {
79
+ display: inline;
80
+ display: block;
81
+ float: left;
82
+ height: 30px;
83
+ margin-left: 1px;
84
+ text-align: center;
85
+ text-decoration: none;
86
+ color: #000000;
87
+ font-weight: bold;
88
+ font-size: 16px;
89
+ padding-top: 10px;
90
+ }
91
+
92
+ #buttons a {
93
+ display: block;
94
+ float: left;
95
+ width: 120px;
96
+ height: 30px;
97
+ margin-left: 1px;
98
+ text-align: center;
99
+ text-decoration: none;
100
+ color: #000000;
101
+ font-weight: bold;
102
+ font-size: 16px;
103
+ padding-top: 10px;
104
+
105
+ }
106
+
107
+ #buttons a:hover {
108
+ text-decoration: underline;
109
+ color: #FF0000;
110
+ }
111
+
112
+ #content
113
+ {
114
+ width: 870px;
115
+ padding: 15px;
116
+ }
117
+
118
+ #left
119
+ {
120
+ width: 580px;
121
+ padding: 10px;
122
+ }
123
+
124
+ #left H1
125
+ {
126
+ color: #99A067;
127
+ margin: 0;
128
+ padding: 0;
129
+ font-size: 24px;
130
+ }
131
+ #left H2
132
+ {
133
+ color: #99A067;
134
+ margin: 0;
135
+ padding: 0;
136
+ font-size: 18px;
137
+ padding-top: 10px;
138
+ }
139
+
140
+ #left a
141
+ {
142
+ color: #99A067;
143
+ }
144
+
145
+ #left a:hover, {
146
+ text-decoration: none;
147
+ color: #FF0000;
148
+ }
149
+
150
+ #left a:visited {
151
+ color: #99A067;
152
+ }
153
+
154
+ .small
155
+ {
156
+ margin: 15px;
157
+ padding: 5px;
158
+ border: 1px solid #99A067
159
+ }
160
+
161
+ #right
162
+ {
163
+ float: right;
164
+ width: 254px;
165
+ }
166
+
167
+ #sidebar
168
+ {
169
+ width: 254px;
170
+ }
171
+
172
+ #sidebar ul
173
+ {
174
+ margin: 0;
175
+ padding: 0;
176
+ list-style: none;
177
+ background: url(title_back.gif) no-repeat;
178
+ }
179
+
180
+ #sidebar li
181
+ {
182
+ margin-bottom: 15px;
183
+
184
+ }
185
+
186
+ #sidebar li ul {
187
+ padding: 10px;
188
+ border-top: none;
189
+ }
190
+
191
+ #sidebar li li {
192
+ margin: 0;
193
+ padding: 3px 0;
194
+ }
195
+
196
+
197
+ #sidebar li h2 {
198
+ height: 34px;
199
+ margin: 0;
200
+ padding: 10px 0 0 20px;
201
+ background: #ffffff url(title.gif) no-repeat;
202
+ font-size: 18px;
203
+ color: #000000;
204
+ }
205
+
206
+ #sidebar a:link {
207
+ text-decoration: none;
208
+ }
209
+
210
+ #sidebar a:hover {
211
+ text-decoration: underline;
212
+ }
213
+ #sidebar a:visited {
214
+ text-decoration: none;
215
+ }
216
+
217
+ #sidebar li a {
218
+ padding-left: 10px;
219
+ background: url(img09.gif) no-repeat 1px 5px;
220
+ }
221
+
222
+
223
+ #footer
224
+ {
225
+ background: url(footer.gif) repeat-x;
226
+ height: 52px;
227
+ font-size: 10px;
228
+ color: #99A067;
229
+ padding-top: 20px;
230
+ text-align: center;
231
+ border-top: #99A067 solid 5px;
232
+ }
233
+
234
+ #footer a
235
+ {
236
+ color: #99A067;
237
+ font-size: 10px;
238
+ text-decoration: none;
239
+ }
240
+ .padding
241
+ {
242
+ padding: 10px;
243
+ color:#FF0000;
244
+ font-weight: bold;
245
+ }
Binary file
Binary file
@@ -0,0 +1,146 @@
1
+ module MetricFu
2
+
3
+ # The Template class is intended as an abstract class for concrete
4
+ # template classes to subclass. It provides a variety of utility
5
+ # methods to make templating a bit easier. However, classes do not
6
+ # have to inherit from here in order to provide a template. The only
7
+ # requirement for a template class is that it provides a #write method
8
+ # to actually write out the template. See StandardTemplate for an
9
+ # example.
10
+ class Template
11
+ attr_accessor :report
12
+
13
+ private
14
+ # Creates a new erb evaluated result from the passed in section.
15
+ #
16
+ # @param section String
17
+ # The section name of
18
+ #
19
+ # @return String
20
+ # The erb evaluated string
21
+ def erbify(section)
22
+ require 'erb'
23
+ erb_doc = File.read(template(section))
24
+ ERB.new(erb_doc).result(binding)
25
+ end
26
+
27
+ # Determines whether a template file exists for a given section
28
+ # of the full template.
29
+ #
30
+ # @param section String
31
+ # The section of the template to check against
32
+ #
33
+ # @return Boolean
34
+ # Does a template file exist for this section or not?
35
+ def template_exists?(section)
36
+ File.exist?(template(section))
37
+ end
38
+
39
+ # Copies an instance variable mimicing the name of the section
40
+ # we are trying to render, with a value equal to the passed in
41
+ # constant. Allows the concrete template classes to refer to
42
+ # that instance variable from their ERB rendering
43
+ #
44
+ # @param section String
45
+ # The name of the instance variable to create
46
+ #
47
+ # @param contents Object
48
+ # The value to set as the value of the created instance
49
+ # variable
50
+ def create_instance_var(section, contents)
51
+ instance_variable_set("@#{section}", contents)
52
+ end
53
+
54
+ # Generates the filename of the template file to load and
55
+ # evaluate. In this case, the path to the template directory +
56
+ # the section name + .html.erb
57
+ #
58
+ # @param section String
59
+ # A section of the template to render
60
+ #
61
+ # @return String
62
+ # A file path
63
+ def template(section)
64
+ File.join(this_directory, section.to_s + ".html.erb")
65
+ end
66
+
67
+ # Returns the filename that the template will render into for
68
+ # a given section. In this case, the section name + '.html'
69
+ #
70
+ # @param section String
71
+ # A section of the template to render
72
+ #
73
+ # @return String
74
+ # The output filename
75
+ def output_filename(section)
76
+ section.to_s + ".html"
77
+ end
78
+
79
+ # Returns the contents of a given css file in order to
80
+ # render it inline into a template.
81
+ #
82
+ # @param css String
83
+ # The name of a css file to open
84
+ #
85
+ # @return String
86
+ # The contents of the css file
87
+ def inline_css(css)
88
+ open(File.join(this_directory, css)) { |f| f.read }
89
+ end
90
+
91
+ # Provides a link to open a file through the textmate protocol
92
+ # on Darwin, or otherwise, a simple file link.
93
+ #
94
+ # @param name String
95
+ #
96
+ # @param line Integer
97
+ # The line number to link to, if textmate is available. Defaults
98
+ # to nil
99
+ #
100
+ # @return String
101
+ # An anchor link to a textmate reference or a file reference
102
+ def link_to_filename(name, line = nil, link_content = nil)
103
+ "<a href='#{file_url(name, line)}'>#{link_content(name, line, link_content)}</a>"
104
+ end
105
+
106
+ def link_content(name, line=nil, link_content=nil) # :nodoc:
107
+ if link_content
108
+ link_content
109
+ elsif line
110
+ "#{name}:#{line}"
111
+ else
112
+ name
113
+ end
114
+ end
115
+
116
+ def file_url(name, line) # :nodoc:
117
+ filename = File.expand_path(name.gsub(/^\//, ''))
118
+ if MetricFu.configuration.platform.include?('darwin')
119
+ "txmt://open/?url=file://#{filename}" << (line ? "&line=#{line}" : "")
120
+ else
121
+ "file://#{filename}"
122
+ end
123
+ end
124
+
125
+ # Provides a brain dead way to cycle between two values during
126
+ # an iteration of some sort. Pass in the first_value, the second_value,
127
+ # and the cardinality of the iteration.
128
+ #
129
+ # @param first_value Object
130
+ #
131
+ # @param second_value Object
132
+ #
133
+ # @param iteration Integer
134
+ # The number of times through the iteration.
135
+ #
136
+ # @return Object
137
+ # The first_value if iteration is even. The second_value if
138
+ # iteration is odd.
139
+ def cycle(first_value, second_value, iteration)
140
+ return first_value if iteration % 2 == 0
141
+ return second_value
142
+ end
143
+
144
+
145
+ end
146
+ end
@@ -0,0 +1,187 @@
1
+ module MetricFu
2
+
3
+ # A list of metrics which are available in the MetricFu system.
4
+ #
5
+ # These are metrics which have been developed for the system. Of
6
+ # course, in order to use these metrics, their respective gems must
7
+ # be installed on the system.
8
+ AVAILABLE_METRICS = [:churn, :flog, :flay, :reek,
9
+ :roodi, :saikuro, :rcov]
10
+
11
+ AVAILABLE_GRAPHS = [:flog, :flay, :reek, :roodi, :rcov, :stats]
12
+
13
+ # The @@configuration class variable holds a global type configuration
14
+ # object for any parts of the system to use.
15
+ def self.configuration
16
+ @@configuration ||= Configuration.new
17
+ end
18
+
19
+ # = Configuration
20
+ #
21
+ # The Configuration class, as it sounds, provides methods for
22
+ # configuring the behaviour of MetricFu.
23
+ #
24
+ # == Customization for Rails
25
+ #
26
+ # The Configuration class checks for the presence of a
27
+ # 'config/environment.rb' file. If the file is present, it assumes
28
+ # it is running in a Rails project. If it is, it will:
29
+ #
30
+ # * Add 'app' to the @code_dirs directory to include the
31
+ # code in the app directory in the processing
32
+ # * Add :stats to the list of metrics to run to get the Rails stats
33
+ # task
34
+ #
35
+ # == Customization for CruiseControl.rb
36
+ #
37
+ # The Configuration class checks for the presence of a
38
+ # 'CC_BUILD_ARTIFACTS' environment variable. If it's found
39
+ # it will change the default output directory from the default
40
+ # "tmp/metric_fu to the directory represented by 'CC_BUILD_ARTIFACTS'
41
+ #
42
+ # == Deprications
43
+ #
44
+ # The Configuration class checks for several deprecated constants
45
+ # that were previously used to configure MetricFu. These include
46
+ # CHURN_OPTIONS, DIRECTORIES_TO_FLOG, SAIKURO_OPTIONS,
47
+ # and MetricFu::SAIKURO_OPTIONS.
48
+ #
49
+ # These have been replaced by config.churn, config.flog and
50
+ # config.saikuro respectively.
51
+ class Configuration
52
+
53
+ def initialize #:nodoc:#
54
+ reset
55
+ add_attr_accessors_to_self
56
+ add_class_methods_to_metric_fu
57
+ end
58
+
59
+ # Searches through the instance variables of the class and
60
+ # creates a class method on the MetricFu module to read the value
61
+ # of the instance variable from the Configuration class.
62
+ def add_class_methods_to_metric_fu
63
+ instance_variables.each do |name|
64
+ method_name = name[1..-1].to_sym
65
+ method = <<-EOF
66
+ def self.#{method_name}
67
+ configuration.send(:#{method_name})
68
+ end
69
+ EOF
70
+ MetricFu.module_eval(method)
71
+ end
72
+ end
73
+
74
+ # Searches through the instance variables of the class and creates
75
+ # an attribute accessor on this instance of the Configuration
76
+ # class for each instance variable.
77
+ def add_attr_accessors_to_self
78
+ instance_variables.each do |name|
79
+ method_name = name[1..-1].to_sym
80
+ MetricFu::Configuration.send(:attr_accessor, method_name)
81
+ end
82
+ end
83
+
84
+ # This allows us to have a nice syntax like:
85
+ #
86
+ # MetricFu.run do |config|
87
+ # config.base_directory = 'tmp/metric_fu'
88
+ # end
89
+ #
90
+ # See the README for more information on configuration options.
91
+ def self.run
92
+ yield MetricFu.configuration
93
+ end
94
+
95
+ # This does the real work of the Configuration class, by setting
96
+ # up a bunch of instance variables to represent the configuration
97
+ # of the MetricFu app.
98
+ def reset
99
+ @base_directory = ENV['CC_BUILD_ARTIFACTS'] || 'tmp/metric_fu'
100
+ @scratch_directory = File.join(@base_directory, 'scratch')
101
+ @output_directory = File.join(@base_directory, 'output')
102
+ @data_directory = File.join('tmp/metric_fu', '_data')
103
+ @metric_fu_root_directory = File.join(File.dirname(__FILE__),
104
+ '..', '..')
105
+ @template_directory = File.join(@metric_fu_root_directory,
106
+ 'lib', 'templates')
107
+ @template_class = AwesomeTemplate
108
+ set_metrics
109
+ set_graphs
110
+ set_code_dirs
111
+ @flay = { :dirs_to_flay => @code_dirs }
112
+ @flog = { :dirs_to_flog => @code_dirs }
113
+ @reek = { :dirs_to_reek => @code_dirs }
114
+ @roodi = { :dirs_to_roodi => @code_dirs }
115
+ @saikuro = { :output_directory => @scratch_directory + '/saikuro',
116
+ :input_directory => @code_dirs,
117
+ :cyclo => "",
118
+ :filter_cyclo => "0",
119
+ :warn_cyclo => "5",
120
+ :error_cyclo => "7",
121
+ :formater => "text"}
122
+ @churn = {}
123
+ @stats = {}
124
+ @rcov = { :test_files => ['test/**/*_test.rb',
125
+ 'spec/**/*_spec.rb'],
126
+ :rcov_opts => ["--sort coverage",
127
+ "--no-html",
128
+ "--text-coverage",
129
+ "--no-color",
130
+ "--profile",
131
+ "--rails",
132
+ "--exclude /gems/,/Library/,/usr/,spec"]}
133
+
134
+ @graph_theme = { :colors => %w(orange purple green teal red blue pink yellow black),
135
+ :marker_color => 'blue',
136
+ :background_colors => %w(white white)}
137
+
138
+ relative_font_path = [File.dirname(__FILE__), '..', '..', 'vendor', '_fonts', 'monaco.ttf']
139
+ @graph_font = File.expand_path(File.join(relative_font_path))
140
+ @graph_size = "1000x400"
141
+ @graph_title_font_size = 12
142
+ @graph_legend_box_size = 12
143
+ @graph_legend_font_size = 10
144
+ @graph_marker_font_size = 10
145
+
146
+ end
147
+
148
+ # Perform a simple check to try and guess if we're running
149
+ # against a rails app.
150
+ #
151
+ # @todo This should probably be made a bit more robust.
152
+ def rails?
153
+ @rails = File.exist?("config/environment.rb")
154
+ end
155
+
156
+ # Add the :stats task to the AVAILABLE_METRICS constant if we're
157
+ # running within rails.
158
+ def set_metrics
159
+ if rails?
160
+ @metrics = MetricFu::AVAILABLE_METRICS + [:stats]
161
+ else
162
+ @metrics = MetricFu::AVAILABLE_METRICS
163
+ end
164
+ end
165
+
166
+ def set_graphs
167
+ @graphs = MetricFu::AVAILABLE_GRAPHS
168
+ end
169
+
170
+ # Add the 'app' directory if we're running within rails.
171
+ def set_code_dirs
172
+ if rails?
173
+ @code_dirs = ['app', 'lib']
174
+ else
175
+ @code_dirs = ['lib']
176
+ end
177
+ end
178
+
179
+ def platform #:nodoc:
180
+ return RUBY_PLATFORM
181
+ end
182
+
183
+ def is_cruise_control_rb?
184
+ !!ENV['CC_BUILD_ARTIFACTS']
185
+ end
186
+ end
187
+ end