metric_fu 4.2.1 → 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/.metrics +19 -1
  2. data/.travis.yml +2 -2
  3. data/Gemfile +2 -1
  4. data/HISTORY.md +24 -0
  5. data/README.md +60 -1
  6. data/TODO.md +1 -0
  7. data/bin/mf-saikuro +8 -0
  8. data/checksum/metric_fu-4.3.0.gem.sha512 +1 -0
  9. data/gemfiles/Gemfile.travis +9 -0
  10. data/lib/metric_fu.rb +1 -1
  11. data/lib/metric_fu/cli/client.rb +2 -2
  12. data/lib/metric_fu/cli/helper.rb +3 -3
  13. data/lib/metric_fu/cli/parser.rb +37 -16
  14. data/lib/metric_fu/configuration.rb +9 -1
  15. data/lib/metric_fu/constantize.rb +57 -0
  16. data/lib/metric_fu/data_structures/line_numbers.rb +19 -3
  17. data/lib/metric_fu/data_structures/location.rb +8 -3
  18. data/lib/metric_fu/formatter.rb +24 -0
  19. data/lib/metric_fu/formatter/html.rb +91 -0
  20. data/lib/metric_fu/formatter/yaml.rb +18 -0
  21. data/lib/metric_fu/initial_requires.rb +0 -1
  22. data/lib/metric_fu/io.rb +69 -0
  23. data/lib/metric_fu/load_files.rb +5 -2
  24. data/lib/metric_fu/logging/mf_debugger.rb +23 -0
  25. data/lib/metric_fu/metrics/base_template.rb +10 -4
  26. data/lib/metric_fu/metrics/cane/cane.rb +2 -1
  27. data/lib/metric_fu/metrics/cane/cane_bluff_grapher.rb +10 -9
  28. data/lib/metric_fu/metrics/cane/cane_gchart_grapher.rb +25 -0
  29. data/lib/metric_fu/metrics/flay/flay_bluff_grapher.rb +10 -9
  30. data/lib/metric_fu/metrics/flay/flay_gchart_grapher.rb +14 -11
  31. data/lib/metric_fu/metrics/flog/flog_bluff_grapher.rb +11 -10
  32. data/lib/metric_fu/metrics/flog/flog_gchart_grapher.rb +22 -15
  33. data/lib/metric_fu/metrics/generator.rb +10 -10
  34. data/lib/metric_fu/metrics/graph.rb +2 -2
  35. data/lib/metric_fu/metrics/hotspots/analysis/scoring_strategies.rb +3 -3
  36. data/lib/metric_fu/metrics/hotspots/hotspot.rb +4 -3
  37. data/lib/metric_fu/metrics/hotspots/hotspot_analyzer.rb +19 -10
  38. data/lib/metric_fu/metrics/hotspots/hotspots.rb +1 -1
  39. data/lib/metric_fu/metrics/hotspots/template_awesome/hotspots.html.erb +45 -45
  40. data/lib/metric_fu/metrics/rails_best_practices/rails_best_practices_bluff_grapher.rb +10 -9
  41. data/lib/metric_fu/metrics/rails_best_practices/rails_best_practices_gchart_grapher.rb +21 -15
  42. data/lib/metric_fu/metrics/rcov/rcov.rb +1 -1
  43. data/lib/metric_fu/metrics/rcov/rcov_bluff_grapher.rb +10 -9
  44. data/lib/metric_fu/metrics/rcov/rcov_gchart_grapher.rb +13 -8
  45. data/lib/metric_fu/metrics/reek/reek_bluff_grapher.rb +9 -13
  46. data/lib/metric_fu/metrics/reek/reek_gchart_grapher.rb +22 -17
  47. data/lib/metric_fu/metrics/roodi/roodi_bluff_grapher.rb +10 -9
  48. data/lib/metric_fu/metrics/roodi/roodi_gchart_grapher.rb +14 -11
  49. data/lib/metric_fu/metrics/saikuro/saikuro.rb +5 -34
  50. data/lib/metric_fu/metrics/stats/stats.rb +2 -1
  51. data/lib/metric_fu/metrics/stats/stats_bluff_grapher.rb +11 -10
  52. data/lib/metric_fu/metrics/stats/stats_gchart_grapher.rb +21 -14
  53. data/lib/metric_fu/reporter.rb +37 -0
  54. data/lib/metric_fu/reporting/graphs/engines/bluff.rb +20 -0
  55. data/lib/metric_fu/reporting/graphs/engines/gchart.rb +41 -3
  56. data/lib/metric_fu/reporting/graphs/grapher.rb +9 -2
  57. data/lib/metric_fu/reporting/result.rb +51 -0
  58. data/lib/metric_fu/reporting/templates/awesome/awesome_template.rb +8 -8
  59. data/lib/metric_fu/run.rb +34 -39
  60. data/lib/metric_fu/version.rb +1 -1
  61. data/lib/metric_fu_requires.rb +50 -33
  62. data/metric_fu.gemspec +30 -39
  63. data/spec/cli/helper_spec.rb +15 -0
  64. data/spec/metric_fu/configuration_spec.rb +40 -2
  65. data/spec/metric_fu/formatter/html_spec.rb +134 -0
  66. data/spec/metric_fu/formatter/yaml_spec.rb +59 -0
  67. data/spec/metric_fu/formatter_spec.rb +49 -0
  68. data/spec/metric_fu/metrics/base_template_spec.rb +23 -23
  69. data/spec/metric_fu/metrics/cane/cane_spec.rb +2 -2
  70. data/spec/metric_fu/metrics/churn/churn_spec.rb +1 -1
  71. data/spec/metric_fu/metrics/flay/flay_spec.rb +4 -4
  72. data/spec/metric_fu/metrics/flog/flog_spec.rb +7 -7
  73. data/spec/metric_fu/metrics/generator_spec.rb +21 -21
  74. data/spec/metric_fu/metrics/graph_spec.rb +9 -9
  75. data/spec/metric_fu/metrics/hotspots/hotspots_spec.rb +1 -1
  76. data/spec/metric_fu/metrics/rcov/rcov_spec.rb +8 -8
  77. data/spec/metric_fu/metrics/reek/reek_spec.rb +1 -1
  78. data/spec/metric_fu/metrics/saikuro/saikuro_spec.rb +5 -5
  79. data/spec/metric_fu/metrics/stats/stats_spec.rb +4 -4
  80. data/spec/metric_fu/reporter_spec.rb +41 -0
  81. data/spec/metric_fu/reporting/graphs/engines/gchart_spec.rb +7 -7
  82. data/spec/metric_fu/reporting/result_spec.rb +51 -0
  83. data/spec/run_spec.rb +167 -27
  84. data/spec/spec_helper.rb +1 -0
  85. data/spec/support/matcher_create_file.rb +7 -2
  86. data/spec/support/matcher_create_files.rb +41 -0
  87. data/spec/support/suite.rb +32 -0
  88. metadata +27 -6
  89. data/lib/metric_fu/reporting/report.rb +0 -111
  90. data/spec/metric_fu/reporting/report_spec.rb +0 -148
@@ -1,11 +1,18 @@
1
1
  module MetricFu
2
2
  class Grapher
3
- def initialize
3
+ attr_accessor :output_directory
4
+
5
+ def initialize(opts = {})
4
6
  self.class.require_graphing_gem
7
+ self.output_directory = opts[:output_directory]
8
+ end
9
+
10
+ def output_directory
11
+ @output_directory || MetricFu.output_directory
5
12
  end
6
13
 
7
14
  def self.require_graphing_gem
8
15
  # to be overridden by charting engines
9
16
  end
10
17
  end
11
- end
18
+ end
@@ -0,0 +1,51 @@
1
+ module MetricFu
2
+
3
+ # MetricFu.result memoizes access to a Result object, that will be
4
+ # used throughout the lifecycle of the MetricFu app.
5
+ def self.result
6
+ @result ||= Result.new
7
+ end
8
+
9
+ # = Result
10
+ #
11
+ # The Result class is responsible for one thing:
12
+ #
13
+ # It tracks the results generated by each metric used in this test run.
14
+ class Result
15
+
16
+ # Renders the result of the result_hash into a yaml serialization
17
+ # ready for writing out to a file.
18
+ #
19
+ # @return YAML
20
+ # A YAML object containing the results of the result generation
21
+ # process
22
+ def as_yaml
23
+ result_hash.to_yaml
24
+ end
25
+
26
+ def per_file_data
27
+ @per_file_data ||= {}
28
+ end
29
+
30
+ def result_hash #:nodoc:
31
+ @result_hash ||= {}
32
+ end
33
+
34
+ # Adds a hash from a passed result, produced by one of the Generator
35
+ # classes to the aggregate result_hash managed by this hash.
36
+ #
37
+ # @param result_type Hash
38
+ # The hash to add to the aggregate result_hash
39
+ def add(result_type)
40
+ mf_debug "result requested #{result_type}"
41
+ clazz = MetricFu.const_get(result_type.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase })
42
+ mf_debug "result class found #{clazz}"
43
+ metric_options = MetricFu.send(result_type)
44
+ inst = clazz.new(metric_options)
45
+
46
+ result_hash.merge!(inst.generate_result)
47
+
48
+ inst.per_file_info(per_file_data) if inst.respond_to?(:per_file_info)
49
+ end
50
+ end
51
+ end
@@ -11,22 +11,22 @@ class AwesomeTemplate < MetricFu::Template
11
11
 
12
12
  # Copy Bluff javascripts to output directory
13
13
  Dir[File.join(template_directory, '..', 'javascripts', '*')].each do |f|
14
- FileUtils.copy(f, File.join(MetricFu.output_directory, File.basename(f)))
14
+ FileUtils.cp(f, File.join(self.output_directory, File.basename(f)))
15
15
  end
16
16
 
17
17
  @metrics = {}
18
- report.each_pair do |section, contents|
18
+ result.each_pair do |section, contents|
19
19
  if template_exists?(section)
20
20
  create_instance_var(section, contents)
21
21
  @metrics[section] = contents
22
22
  create_instance_var(:per_file_data, per_file_data)
23
- mf_debug "Generating html for section #{section} with #{template(section)} for report #{report.class}"
23
+ mf_debug "Generating html for section #{section} with #{template(section)} for result #{result.class}"
24
24
  @html = erbify(section)
25
25
  html = erbify('layout')
26
26
  fn = output_filename(section)
27
- MetricFu.report.save_output(html, MetricFu.output_directory, fn)
27
+ formatter.write_template(html, fn)
28
28
  else
29
- mf_debug "no template for section #{section} with #{template(section)} for report #{report.class}"
29
+ mf_debug "no template for section #{section} with #{template(section)} for result #{result.class}"
30
30
  end
31
31
  end
32
32
 
@@ -35,9 +35,9 @@ class AwesomeTemplate < MetricFu::Template
35
35
  @html = erbify('index')
36
36
  html = erbify('layout')
37
37
  fn = output_filename('index')
38
- MetricFu.report.save_output(html, MetricFu.output_directory, fn)
38
+ formatter.write_template(html, fn)
39
39
  else
40
- mf_debug "no template for section index for report #{report.class}"
40
+ mf_debug "no template for section index for result #{result.class}"
41
41
  end
42
42
 
43
43
  write_file_data
@@ -101,7 +101,7 @@ class AwesomeTemplate < MetricFu::Template
101
101
  end
102
102
  out << "<table></body></html>"
103
103
 
104
- MetricFu.report.save_output(out, MetricFu.output_directory, fn)
104
+ formatter.write_template(out, fn)
105
105
  end
106
106
  end
107
107
  def template_directory
@@ -6,61 +6,38 @@ module MetricFu
6
6
  load_user_configuration
7
7
  end
8
8
  def run(options={})
9
- disable_metrics(options)
10
- run_reports
11
- save_reports
12
- save_graphs
13
- display_results
9
+ configure_run(options)
10
+ measure
11
+ display_results if options[:open]
14
12
  end
15
13
 
16
14
  # ensure :hotspots runs last
17
15
  def report_metrics(metrics=MetricFu.metrics)
18
- MetricFu.configuration.metrics -= [ :hotspots ]
19
- MetricFu.configuration.metrics += [ :hotspots ]
16
+ MetricFu.configuration.metrics.sort_by! {|x| x == :hotspots ? 1 : 0 }
20
17
  MetricFu.configuration.metrics
21
18
  end
22
- def run_reports
19
+ def measure
20
+ reporter.start
23
21
  report_metrics.each {|metric|
24
- mf_log "** STARTING METRIC #{metric}"
25
- MetricFu.report.add(metric)
26
- mf_log "** ENDING METRIC #{metric}"
27
- }
28
- end
29
- def save_reports
30
- mf_log "** SAVING REPORTS"
31
- mf_debug "** SAVING REPORT YAML OUTPUT TO #{MetricFu.base_directory}"
32
- MetricFu.report.save_output(MetricFu.report.as_yaml,
33
- MetricFu.base_directory,
34
- "report.yml")
35
- mf_debug "** SAVING REPORT DATA OUTPUT TO #{MetricFu.data_directory}"
36
- MetricFu.report.save_output(MetricFu.report.as_yaml,
37
- MetricFu.data_directory,
38
- "#{Time.now.strftime("%Y%m%d")}.yml")
39
- mf_debug "** SAVING TEMPLATIZED REPORT"
40
- MetricFu.report.save_templatized_report
41
- end
42
- def save_graphs
43
- mf_log "** GENERATING GRAPHS"
44
- mf_debug "** PREPARING TO GRAPH"
45
- MetricFu.graphs.each {|graph|
46
- mf_debug "** Graphing #{graph} with #{MetricFu.graph_engine}"
47
- MetricFu.graph.add(graph, MetricFu.graph_engine)
22
+ reporter.start_metric(metric)
23
+ MetricFu.result.add(metric)
24
+ reporter.finish_metric(metric)
48
25
  }
49
- mf_debug "** GENERATING GRAPH"
50
- MetricFu.graph.generate
26
+ reporter.finish
51
27
  end
52
28
  def display_results
53
- if MetricFu.report.open_in_browser?
54
- mf_debug "** OPENING IN BROWSER FROM #{MetricFu.output_directory}"
55
- MetricFu.report.show_in_browser(MetricFu.output_directory)
56
- end
57
- mf_log "** COMPLETE"
29
+ reporter.display_results
58
30
  end
59
31
  private
60
32
  def load_user_configuration
61
33
  file = File.join(Dir.pwd, '.metrics')
62
34
  load file if File.exist?(file)
63
35
  end
36
+ # Updates configuration based on runtime options.
37
+ def configure_run(options)
38
+ disable_metrics(options)
39
+ configure_formatters(options)
40
+ end
64
41
  def disable_metrics(options)
65
42
  return if options.size == 0
66
43
  report_metrics.each do |metric|
@@ -74,5 +51,23 @@ module MetricFu
74
51
  end
75
52
  end
76
53
  end
54
+ def configure_formatters(options)
55
+ # Configure from command line if any.
56
+ if options[:format]
57
+ MetricFu.formatters.clear # Command-line format takes precedence.
58
+ Array(options[:format]).each do |format, o|
59
+ MetricFu.configuration.add_formatter(format, o)
60
+ end
61
+ end
62
+ # If no formatters specified, use defaults.
63
+ if MetricFu.configuration.formatters.empty?
64
+ Array(MetricFu::Formatter::DEFAULT).each do |format, o|
65
+ MetricFu.configuration.add_formatter(format, o)
66
+ end
67
+ end
68
+ end
69
+ def reporter
70
+ Reporter.new(MetricFu.configuration.formatters)
71
+ end
77
72
  end
78
73
  end
@@ -1,3 +1,3 @@
1
1
  module MetricFu
2
- VERSION = "4.2.1"
2
+ VERSION = "4.3.0"
3
3
  end
@@ -1,46 +1,63 @@
1
+ # Used to find which version, if any, of a gem to use when running command-line tools
1
2
  module MetricFu
2
3
  module MetricVersion
3
4
  extend self
4
- def reek
5
- ['= 1.3.1']
6
- end
7
- def flog
8
- ['= 3.2.2']
9
- end
10
- def flay
11
- ['= 2.0.1']
12
- end
13
- def churn
14
- ['= 0.0.28']
15
- end
16
- def roodi
17
- ['>= 2.2.1']
18
- end
19
- def rails_best_practices
20
- ['= 1.13.2']
21
- end
22
5
 
23
- def ruby2ruby
24
- ['~> 2.0', '>= 2.0.2']
25
- end
26
- def ruby_parser
27
- ['~> 3.0', '>= 3.1.1']
6
+ # @return [Array] rcov version if running rcov
7
+ # Rcov is not a dependency in the gemspec
8
+ # but is available to be shelled out
9
+ def rcov
10
+ ['~> 0.8']
28
11
  end
29
- def sexp_processor
30
- ['~> 4.0']
12
+
13
+ # @example MetricFu::MetricVersion.flog will return the gem version of Flog to require
14
+ # @return [nil] when the metric_fu gem dependency isn't specified
15
+ # @return [Array] represenation of the metric_fu gem dependency if specified
16
+ # in the gemspec.
17
+ # Will raise method missing if :version_for is falsy
18
+ # @see gems
19
+ def method_missing(method,*args,&block)
20
+ if (gem_version = version_for(method.to_s))
21
+ gem_version != [] ? gem_version : nil
22
+ else
23
+ super
24
+ end
31
25
  end
32
- def parallel
33
- ['= 0.6.2']
26
+
27
+ private
28
+
29
+ # Generates and returns an abstract syntax tree from the gemspec
30
+ # @return [Sexp]
31
+ def ast
32
+ require 'ruby_parser'
33
+ parser = RubyParser.new
34
+ parser.parse(gemspec)
34
35
  end
35
36
 
36
- def rcov
37
- ['~> 0.8']
37
+
38
+ # Uses the ast to find all the specified runtime dependencies and their version requirements
39
+ # @return Array<Array<gem_name,gem_version>>, where gem_name is a string and gem_version is an Array
40
+ def gems
41
+ @gems ||= ast.find{|node| node[0] == :iter}.
42
+ find{|node| node[0] == :block}. # in the specification block
43
+ select{|node| node[0] == :call }. # select all the methods
44
+ select{|node| node[2] == :add_runtime_dependency }. # that are :add_runtime_dependency
45
+ map{|node| [ # return a mapped array of
46
+ node[3][1].downcase.sub('metric_fu-',''), # the downcased gem name (with any metric_fu- prefix removed)
47
+ Array(Array(node[4])[1..-1]).map{|node|node[1]} # and an Array of the specified gem version(s)
48
+ ]}
38
49
  end
39
- def saikuro
40
- ['>= 1.1.1.0']
50
+
51
+ # @return Array<String> where the strings are valid gem version requires
52
+ # The Array is empty if no gem version is specified
53
+ def version_for(gem_name)
54
+ node = gems.find{|node|node[0] == gem_name.downcase} # find the gem in the ast with the given downcased name
55
+ node && node[1] # if found, return its version specification
41
56
  end
42
- def cane
43
- ['= 2.5.2']
57
+
58
+ # Read in the contents of the gemspec
59
+ def gemspec
60
+ File.read(File.expand_path('../../metric_fu.gemspec', __FILE__))
44
61
  end
45
62
  end
46
63
  end
@@ -25,45 +25,36 @@ Gem::Specification.new do |s|
25
25
  s.extra_rdoc_files = ["HISTORY.md", "CONTRIBUTING.md", "TODO.md", "MIT-LICENSE"]
26
26
  s.rdoc_options = ["--main", "README.md"]
27
27
 
28
- {
29
- # metric dependencies
30
- "flay" => MetricFu::MetricVersion.flay,
31
- "churn" => MetricFu::MetricVersion.churn,
32
- "flog" => MetricFu::MetricVersion.flog,
33
- "reek" => MetricFu::MetricVersion.reek,
34
- "cane" => MetricFu::MetricVersion.cane,
35
- # specifying gem dependencies for
36
- # flay, churn, flog, reek, and cane
37
- "ruby_parser" => MetricFu::MetricVersion.ruby_parser,
38
- "sexp_processor" => MetricFu::MetricVersion.sexp_processor,
39
- # reek
40
- "ruby2ruby" => MetricFu::MetricVersion.ruby2ruby,
41
- # cane
42
- "parallel" => MetricFu::MetricVersion.parallel,
28
+ # metric dependencies
29
+ s.add_runtime_dependency 'flay', ['= 2.0.1']
30
+ s.add_runtime_dependency 'churn', ['= 0.0.28']
31
+ s.add_runtime_dependency 'flog', ['= 3.2.2']
32
+ s.add_runtime_dependency 'reek', ['= 1.3.1']
33
+ s.add_runtime_dependency 'cane', ['= 2.5.2']
34
+ # specifying gem dependencies for
35
+ # flay, churn, flog, reek, and cane
36
+ s.add_runtime_dependency 'ruby_parser', ['~> 3.0', '>= 3.1.1']
37
+ s.add_runtime_dependency 'sexp_processor', ['~> 4.0']
38
+ # reek only
39
+ s.add_runtime_dependency 'ruby2ruby', ['~> 2.0', '>= 2.0.2']
40
+ # cane only
41
+ s.add_runtime_dependency 'parallel', ['= 0.6.2']
43
42
  # required by main, a churn dependency
44
- "fattr" => ["= 2.2.1"],
45
- "arrayfields" => ["= 4.7.4"],
46
- "map" => ["= 6.2.0"],
47
- "rails_best_practices" => MetricFu::MetricVersion.rails_best_practices,
48
- "japgolly-Saikuro" => MetricFu::MetricVersion.saikuro,
49
- "metric_fu-roodi" => MetricFu::MetricVersion.roodi,
50
- #
51
- # other dependencies
52
- # ruby version identification
53
- 'redcard' => [],
54
- # syntax highlighting
55
- "coderay" => [],
56
- # default graphing libraries
57
- "bluff" => [],
58
- # to_json support
59
- 'multi_json' => [],
60
- }.each do |gem, version|
61
- if version == []
62
- s.add_runtime_dependency(gem)
63
- else
64
- s.add_runtime_dependency(gem,version)
65
- end
66
- end
43
+ s.add_runtime_dependency 'fattr', ["= 2.2.1"]
44
+ s.add_runtime_dependency 'arrayfields', ["= 4.7.4"]
45
+ s.add_runtime_dependency 'map', ["= 6.2.0"]
46
+ s.add_runtime_dependency 'rails_best_practices', ['= 1.13.2']
47
+ s.add_runtime_dependency 'metric_fu-Saikuro', ['>= 1.1.1.0']
48
+ s.add_runtime_dependency 'metric_fu-roodi', ['>= 2.2.1']
67
49
 
68
- end
50
+ # other dependencies
51
+ # ruby version identification
52
+ s.add_runtime_dependency 'redcard'
53
+ # syntax highlighting
54
+ s.add_runtime_dependency 'coderay'
55
+ # default graphing libraries
56
+ s.add_runtime_dependency 'bluff'
57
+ # to_json support
58
+ s.add_runtime_dependency 'multi_json'
69
59
 
60
+ end
@@ -49,6 +49,9 @@ describe MetricFu::Cli::Helper do
49
49
  defaults[:rcov].should be_true
50
50
  end
51
51
 
52
+ it "runs by default" do
53
+ defaults[:run].should be_true
54
+ end
52
55
  end
53
56
 
54
57
  if MetricFu.configuration.mri?
@@ -163,6 +166,18 @@ describe MetricFu::Cli::Helper do
163
166
  helper.process_options(["--roodi"])[:roodi].should be_true
164
167
  end
165
168
 
169
+ context 'given a single format' do
170
+ it "sets the format" do
171
+ helper.process_options(["--format", "json"])[:format].should eq([['json']])
172
+ end
173
+ end
174
+
175
+ context 'given multiple formats' do
176
+ it "sets multiple formats" do
177
+ helper.process_options(["--format", "json", "--format", "yaml"])[:format].should eq([['json'], ['yaml']])
178
+ end
179
+ end
180
+
166
181
  end
167
182
 
168
183
  end
@@ -194,7 +194,7 @@ describe MetricFu::Configuration do
194
194
 
195
195
  before(:each) do
196
196
  @config = MetricFu.configuration
197
- @config.stub!(:rails?).and_return(true)
197
+ @config.stub(:rails?).and_return(true)
198
198
  @config.reset
199
199
  MetricFu.configure
200
200
  %w(stats rails_best_practices).each do |metric|
@@ -236,7 +236,7 @@ describe MetricFu::Configuration do
236
236
  describe 'if #rails? is false ' do
237
237
  before(:each) do
238
238
  get_new_config
239
- @config.stub!(:rails?).and_return(false)
239
+ @config.stub(:rails?).and_return(false)
240
240
  %w(stats rails_best_practices).each do |metric|
241
241
  load_metric metric
242
242
  end
@@ -329,4 +329,42 @@ describe MetricFu::Configuration do
329
329
  end
330
330
  end
331
331
  end
332
+
333
+ describe '#add_formatter' do
334
+ before(:each) { get_new_config }
335
+
336
+ context 'given a built-in formatter' do
337
+ before do
338
+ @config.add_formatter('html')
339
+ end
340
+
341
+ it 'adds to the list of formatters' do
342
+ @config.formatters.first.should be_an_instance_of(MetricFu::Formatter::HTML)
343
+ end
344
+ end
345
+
346
+ context 'given a custom formatter by class name' do
347
+ before do
348
+ stub_const('MyCustomFormatter', Class.new() { def initialize(*); end })
349
+ @config.add_formatter('MyCustomFormatter')
350
+ end
351
+
352
+ it 'adds to the list of formatters' do
353
+ @config.formatters.first.should be_an_instance_of(MyCustomFormatter)
354
+ end
355
+ end
356
+
357
+ context 'given multiple formatters' do
358
+ before do
359
+ stub_const('MyCustomFormatter', Class.new() { def initialize(*); end })
360
+ @config.add_formatter('html')
361
+ @config.add_formatter('yaml')
362
+ @config.add_formatter('MyCustomFormatter')
363
+ end
364
+
365
+ it 'adds each to the list of formatters' do
366
+ @config.formatters.count.should eq(3)
367
+ end
368
+ end
369
+ end
332
370
  end