metric_fu 4.4.4 → 4.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. checksums.yaml +14 -6
  2. checksums.yaml.gz.sig +3 -0
  3. data.tar.gz.sig +0 -0
  4. data/.gitignore +1 -0
  5. data/.metrics +0 -3
  6. data/.travis.yml +1 -1
  7. data/.yardopts +0 -1
  8. data/CONTRIBUTING.md +1 -0
  9. data/CONTRIBUTORS +61 -2
  10. data/Gemfile +14 -11
  11. data/Gemfile.devtools +40 -0
  12. data/Guardfile +30 -0
  13. data/HISTORY.md +54 -1
  14. data/README.md +86 -56
  15. data/bin/mf-cane +8 -6
  16. data/bin/mf-churn +8 -7
  17. data/bin/mf-flay +8 -7
  18. data/bin/mf-reek +8 -7
  19. data/bin/mf-roodi +8 -7
  20. data/bin/mf-saikuro +8 -6
  21. data/certs/bf4.pem +22 -0
  22. data/checksum/metric_fu-4.4.4.gem.sha512 +1 -0
  23. data/checksum/metric_fu-4.5.0.gem.sha512 +1 -0
  24. data/etc/README.md +16 -0
  25. data/etc/erd.dot +173 -0
  26. data/etc/erd.png +0 -0
  27. data/lib/metric_fu.rb +56 -12
  28. data/lib/metric_fu/cli/helper.rb +8 -2
  29. data/lib/metric_fu/cli/parser.rb +86 -50
  30. data/lib/metric_fu/configuration.rb +4 -31
  31. data/lib/metric_fu/environment.rb +1 -1
  32. data/lib/metric_fu/formatter/html.rb +5 -5
  33. data/lib/metric_fu/gem_run.rb +68 -0
  34. data/lib/metric_fu/gem_version.rb +57 -0
  35. data/lib/metric_fu/io.rb +1 -1
  36. data/lib/metric_fu/load_files.rb +3 -5
  37. data/lib/metric_fu/loader.rb +31 -2
  38. data/lib/metric_fu/logging/mf_debugger.rb +1 -0
  39. data/lib/metric_fu/metric.rb +23 -1
  40. data/lib/metric_fu/metrics/cane/cane.rb +7 -3
  41. data/lib/metric_fu/metrics/cane/cane_grapher.rb +19 -0
  42. data/lib/metric_fu/metrics/cane/template_awesome/cane.html.erb +0 -4
  43. data/lib/metric_fu/metrics/churn/churn.rb +6 -7
  44. data/lib/metric_fu/metrics/flay/flay.rb +2 -4
  45. data/lib/metric_fu/metrics/flay/flay_grapher.rb +19 -0
  46. data/lib/metric_fu/metrics/flay/template_awesome/flay.html.erb +0 -4
  47. data/lib/metric_fu/metrics/flog/flog.rb +0 -2
  48. data/lib/metric_fu/metrics/flog/flog_grapher.rb +19 -0
  49. data/lib/metric_fu/metrics/flog/template_awesome/flog.html.erb +0 -4
  50. data/lib/metric_fu/metrics/generator.rb +34 -24
  51. data/lib/metric_fu/metrics/graph.rb +8 -14
  52. data/lib/metric_fu/metrics/hotspots/hotspot.rb +7 -5
  53. data/lib/metric_fu/metrics/hotspots/template_awesome/hotspots.html.erb +4 -6
  54. data/lib/metric_fu/metrics/rails_best_practices/rails_best_practices.rb +0 -2
  55. data/lib/metric_fu/metrics/rails_best_practices/rails_best_practices_grapher.rb +19 -0
  56. data/lib/metric_fu/metrics/rails_best_practices/template_awesome/rails_best_practices.html.erb +0 -4
  57. data/lib/metric_fu/metrics/rcov/rcov_grapher.rb +19 -0
  58. data/lib/metric_fu/metrics/rcov/template_awesome/rcov.html.erb +0 -4
  59. data/lib/metric_fu/metrics/reek/init.rb +1 -1
  60. data/lib/metric_fu/metrics/reek/reek.rb +12 -8
  61. data/lib/metric_fu/metrics/reek/reek_grapher.rb +19 -0
  62. data/lib/metric_fu/metrics/reek/template_awesome/reek.html.erb +0 -4
  63. data/lib/metric_fu/metrics/roodi/roodi.rb +2 -3
  64. data/lib/metric_fu/metrics/roodi/roodi_grapher.rb +19 -0
  65. data/lib/metric_fu/metrics/roodi/template_awesome/roodi.html.erb +0 -4
  66. data/lib/metric_fu/metrics/saikuro/saikuro.rb +69 -33
  67. data/lib/metric_fu/metrics/saikuro/scratch_file.rb +8 -9
  68. data/lib/metric_fu/metrics/stats/stats_grapher.rb +20 -0
  69. data/lib/metric_fu/metrics/stats/template_awesome/stats.html.erb +0 -4
  70. data/lib/metric_fu/reporting/graphs/grapher.rb +69 -3
  71. data/lib/metric_fu/reporting/result.rb +5 -1
  72. data/lib/metric_fu/reporting/templates/awesome/awesome_template.rb +7 -3
  73. data/lib/metric_fu/run.rb +13 -7
  74. data/lib/metric_fu/tasks/metric_fu.rake +50 -3
  75. data/lib/metric_fu/utility.rb +10 -0
  76. data/lib/metric_fu/version.rb +1 -1
  77. data/metric_fu.gemspec +7 -4
  78. data/spec/dummy/.gitignore +1 -0
  79. data/spec/dummy/.gitkeep +0 -0
  80. data/spec/dummy/.metrics +4 -0
  81. data/spec/dummy/lib/.gitkeep +0 -0
  82. data/spec/dummy/spec/.gitkeep +0 -0
  83. data/spec/{resources/yml → fixtures}/20090630.yml +1 -1
  84. data/spec/{resources/yml → fixtures}/hotspots/flog.yml +0 -0
  85. data/spec/{resources/yml → fixtures}/hotspots/generator.yml +0 -0
  86. data/spec/{resources/yml → fixtures}/hotspots/generator_analysis.yml +0 -0
  87. data/spec/{resources/yml → fixtures}/hotspots/reek.yml +0 -0
  88. data/spec/{resources/yml → fixtures}/hotspots/roodi.yml +0 -0
  89. data/spec/{resources/yml → fixtures}/hotspots/saikuro.yml +0 -0
  90. data/spec/{resources/yml → fixtures}/hotspots/several_metrics.yml +0 -0
  91. data/spec/{resources/yml → fixtures}/hotspots/stats.yml +0 -0
  92. data/spec/{resources/yml → fixtures}/hotspots/three_metrics_on_same_file.yml +0 -0
  93. data/spec/{resources → fixtures}/line_numbers/foo.rb +0 -0
  94. data/spec/{resources → fixtures}/line_numbers/module.rb +0 -0
  95. data/spec/{resources → fixtures}/line_numbers/module_surrounds_class.rb +0 -0
  96. data/spec/{resources → fixtures}/line_numbers/two_classes.rb +0 -0
  97. data/spec/{resources/yml → fixtures}/metric_missing.yml +0 -0
  98. data/spec/{resources → fixtures}/saikuro/app/controllers/sessions_controller.rb_cyclo.html +0 -0
  99. data/spec/{resources → fixtures}/saikuro/app/controllers/users_controller.rb_cyclo.html +0 -0
  100. data/spec/{resources → fixtures}/saikuro/index_cyclo.html +0 -0
  101. data/spec/{resources → fixtures}/saikuro_sfiles/thing.rb_cyclo.html +0 -0
  102. data/spec/metric_fu/configuration_spec.rb +1 -1
  103. data/spec/metric_fu/data_structures/line_numbers_spec.rb +13 -11
  104. data/spec/metric_fu/formatter/html_spec.rb +2 -2
  105. data/spec/metric_fu/gem_version_spec.rb +14 -0
  106. data/spec/metric_fu/loader_spec.rb +12 -0
  107. data/spec/metric_fu/metrics/base_template_spec.rb +9 -7
  108. data/spec/metric_fu/metrics/cane/cane_spec.rb +7 -7
  109. data/spec/metric_fu/metrics/churn/churn_spec.rb +1 -1
  110. data/spec/metric_fu/metrics/flay/flay_grapher_spec.rb +2 -2
  111. data/spec/metric_fu/metrics/flay/flay_spec.rb +2 -2
  112. data/spec/metric_fu/metrics/flog/flog_grapher_spec.rb +3 -3
  113. data/spec/metric_fu/metrics/generator_spec.rb +1 -35
  114. data/spec/metric_fu/metrics/graph_spec.rb +7 -24
  115. data/spec/metric_fu/metrics/hotspots/analysis/analyzed_problems_spec.rb +2 -2
  116. data/spec/metric_fu/metrics/hotspots/analysis/analyzer_tables_spec.rb +2 -2
  117. data/spec/metric_fu/metrics/hotspots/analysis/rankings_spec.rb +5 -5
  118. data/spec/metric_fu/metrics/hotspots/hotspots_spec.rb +2 -3
  119. data/spec/metric_fu/metrics/rails_best_practices/rails_best_practices_grapher_spec.rb +2 -2
  120. data/spec/metric_fu/metrics/rails_best_practices/rails_best_practices_spec.rb +1 -1
  121. data/spec/metric_fu/metrics/rcov/rcov_grapher_spec.rb +2 -2
  122. data/spec/metric_fu/metrics/rcov/rcov_spec.rb +1 -4
  123. data/spec/metric_fu/metrics/reek/reek_grapher_spec.rb +2 -2
  124. data/spec/metric_fu/metrics/reek/reek_spec.rb +1 -1
  125. data/spec/metric_fu/metrics/roodi/roodi_grapher_spec.rb +2 -2
  126. data/spec/metric_fu/metrics/roodi/roodi_spec.rb +3 -3
  127. data/spec/metric_fu/metrics/saikuro/saikuro_spec.rb +14 -10
  128. data/spec/metric_fu/metrics/stats/stats_grapher_spec.rb +2 -2
  129. data/spec/metric_fu/reporting/graphs/{engines/bluff_spec.rb → grapher_spec.rb} +8 -2
  130. data/spec/{run_spec.rb → metric_fu/run_spec.rb} +8 -13
  131. data/spec/spec_helper.rb +30 -5
  132. data/spec/support/deferred_garbaged_collection.rb +34 -0
  133. data/spec/support/helper_methods.rb +1 -15
  134. data/spec/support/suite.rb +4 -24
  135. data/spec/support/test_fixtures.rb +39 -0
  136. data/spec/support/timeout.rb +7 -0
  137. metadata +129 -104
  138. metadata.gz.sig +1 -0
  139. data/lib/metric_fu/metrics/cane/cane_bluff_grapher.rb +0 -16
  140. data/lib/metric_fu/metrics/cane/cane_gchart_grapher.rb +0 -25
  141. data/lib/metric_fu/metrics/flay/flay_bluff_grapher.rb +0 -16
  142. data/lib/metric_fu/metrics/flay/flay_gchart_grapher.rb +0 -20
  143. data/lib/metric_fu/metrics/flog/flog_bluff_grapher.rb +0 -17
  144. data/lib/metric_fu/metrics/flog/flog_gchart_grapher.rb +0 -28
  145. data/lib/metric_fu/metrics/rails_best_practices/rails_best_practices_bluff_grapher.rb +0 -16
  146. data/lib/metric_fu/metrics/rails_best_practices/rails_best_practices_gchart_grapher.rb +0 -27
  147. data/lib/metric_fu/metrics/rcov/rcov_bluff_grapher.rb +0 -16
  148. data/lib/metric_fu/metrics/rcov/rcov_gchart_grapher.rb +0 -22
  149. data/lib/metric_fu/metrics/reek/reek_bluff_grapher.rb +0 -16
  150. data/lib/metric_fu/metrics/reek/reek_gchart_grapher.rb +0 -30
  151. data/lib/metric_fu/metrics/roodi/roodi_bluff_grapher.rb +0 -16
  152. data/lib/metric_fu/metrics/roodi/roodi_gchart_grapher.rb +0 -20
  153. data/lib/metric_fu/metrics/stats/stats_bluff_grapher.rb +0 -17
  154. data/lib/metric_fu/metrics/stats/stats_gchart_grapher.rb +0 -27
  155. data/lib/metric_fu/reporting/graphs/engines/bluff.rb +0 -33
  156. data/lib/metric_fu/reporting/graphs/engines/gchart.rb +0 -72
  157. data/lib/metric_fu/reporting/graphs/engines/init.rb +0 -19
  158. data/lib/metric_fu_requires.rb +0 -63
  159. data/spec/metric_fu/reporting/graphs/engines/gchart_spec.rb +0 -161
@@ -13,72 +13,102 @@ module MetricFu
13
13
  yield self if block_given?
14
14
  end
15
15
 
16
+ def process!(arguments = ARGV)
17
+ parser = build_option_parser
18
+ process_options(parser, arguments)
19
+ end
20
+
16
21
  def option(name, desc, settings = {})
17
22
  @options << [name, desc, settings]
18
23
  end
19
24
 
20
- def short_from(name)
21
- name.to_s.chars.each do |c|
22
- next if @used_short.include?(c) || c == "_"
23
- return c # returns from short_from method
24
- end
25
- end
26
25
 
27
- def process!(arguments = ARGV)
26
+ private
27
+
28
+ def build_option_parser
28
29
  @result = (@default_values || {}).clone # reset or new
30
+
29
31
  @optionparser ||= OptionParser.new do |p| # prepare only once
30
- @options.each do |o|
31
- @used_short << short = o[2][:short] || short_from(o[0])
32
- @result[o[0]] = o[2][:default] || false # set default
33
- klass = o[2][:default].class == Fixnum ? Integer : o[2][:default].class
34
-
35
- if [TrueClass, FalseClass, NilClass].include?(klass) # boolean switch
36
- p.on("-" << short, "--[no-]" << o[0].to_s.gsub("_", "-"), o[1]) {|x| @result[o[0]] = x}
37
- else # argument with parameter
38
- p.on("-" << short, "--" << o[0].to_s.gsub("_", "-") << " " << o[2][:default].to_s, klass, o[1]) {|x| @result[o[0]] = x}
39
- end
40
- end
41
-
42
- p.on("--format FORMAT",
43
- "Specify the formatter to use for output.",
44
- "This option can be specified multiple times.",
45
- "Specify a built-in formatter from the list below,",
46
- "or the fully-qualified class name of your own custom formatter.",
47
- *format_descriptions) do |f|
48
- @result[:format] ||= []
49
- @result[:format] << [f]
50
- end
51
-
52
- p.on("--out FILE|DIR",
53
- "Specify the file or directory to use for output",
54
- "This option applies to the previously",
55
- "specified --format, or the default format",
56
- "if no format is specified. Paths are relative to",
57
- "#{Pathname.pwd.join(MetricFu::Io::FileSystem.directory('base_directory'))}",
58
- "Check the specific formatter\'s docs to see",
59
- "whether to pass a file or a dir.") do |o|
60
- @result[:format] ||= MetricFu::Formatter::DEFAULT
61
- @result[:format].last << o
62
- end
63
-
64
- p.banner = @banner unless @banner.nil?
65
- p.on_tail("-h", "--help", "Show this message") {puts p ; exit}
66
- short = @used_short.include?("v") ? "-V" : "-v"
67
- p.on_tail(short, "--version", "Print version") {puts @version ; exit} unless @version.nil?
68
- p.on_tail("--debug-info", "Print debug info") { debug_info; exit }
69
- @default_values = @result.clone # save default values to reset @result in subsequent calls
32
+ configure_options(p)
70
33
  end
34
+ end
71
35
 
36
+ def process_options(parser, arguments)
72
37
  begin
73
- @optionparser.parse!(arguments)
38
+ parser.parse!(arguments)
74
39
  rescue OptionParser::ParseError => e
75
- puts e.message ; exit(1)
40
+ puts e.message
41
+ MetricFu::Cli.immediate_shutdown!
76
42
  end
77
43
 
78
- validate(@result) if self.respond_to?("validate")
79
44
  @result
80
45
  end
81
46
 
47
+ def configure_options(p)
48
+ add_general_options(@options, p)
49
+
50
+ add_format_option(p)
51
+ add_output_option(p)
52
+
53
+ p.banner = @banner unless @banner.nil?
54
+ p.on_tail("-h", "--help", "Show this message") {puts p ; success!}
55
+ short = @used_short.include?("v") ? "-V" : "-v"
56
+ p.on_tail(short, "--version", "Print version") {puts @version ; success!} unless @version.nil?
57
+ p.on_tail("--debug-info", "Print debug info") { debug_info; success! }
58
+ @default_values = @result.clone # save default values to reset @result in subsequent calls
59
+ end
60
+
61
+ def add_general_options(options, p)
62
+ options.each do |o|
63
+ add_general_option(p, o)
64
+ end
65
+ end
66
+
67
+ def add_general_option(p, o)
68
+ @used_short << short = o[2][:short] || short_from(o[0])
69
+ @result[o[0]] = o[2][:default] || false # set default
70
+ klass = o[2][:default].class == Fixnum ? Integer : o[2][:default].class
71
+
72
+ if [TrueClass, FalseClass, NilClass].include?(klass) # boolean switch
73
+ p.on("-" << short, "--[no-]" << o[0].to_s.gsub("_", "-"), o[1]) {|x| @result[o[0]] = x}
74
+ else # argument with parameter
75
+ p.on("-" << short, "--" << o[0].to_s.gsub("_", "-") << " " << o[2][:default].to_s, klass, o[1]) {|x| @result[o[0]] = x}
76
+ end
77
+ end
78
+
79
+ def add_output_option(p)
80
+ p.on("--out FILE|DIR",
81
+ "Specify the file or directory to use for output",
82
+ "This option applies to the previously",
83
+ "specified --format, or the default format",
84
+ "if no format is specified. Paths are relative to",
85
+ "#{MetricFu.run_path.join(MetricFu::Io::FileSystem.directory('base_directory'))}",
86
+ "Check the specific formatter\'s docs to see",
87
+ "whether to pass a file or a dir.") do |o|
88
+ @result[:format] ||= MetricFu::Formatter::DEFAULT
89
+ @result[:format].last << o
90
+ end
91
+ end
92
+
93
+ def add_format_option(p)
94
+ p.on("--format FORMAT",
95
+ "Specify the formatter to use for output.",
96
+ "This option can be specified multiple times.",
97
+ "Specify a built-in formatter from the list below,",
98
+ "or the fully-qualified class name of your own custom formatter.",
99
+ *format_descriptions) do |f|
100
+ @result[:format] ||= []
101
+ @result[:format] << [f]
102
+ end
103
+ end
104
+
105
+ def short_from(name)
106
+ name.to_s.chars.each do |c|
107
+ next if @used_short.include?(c) || c == "_"
108
+ return c # returns from short_from method
109
+ end
110
+ end
111
+
82
112
  def debug_info
83
113
  extend(MetricFu::Environment)
84
114
  require 'pp'
@@ -99,6 +129,12 @@ module MetricFu
99
129
  " #{key}#{' ' * (max - key.length)} : #{formats[key][1]}"
100
130
  end
101
131
  end
132
+
133
+ def success!
134
+ MetricFu::Cli.complete!
135
+ end
136
+
137
+
102
138
  end
103
139
  end
104
140
 
@@ -52,12 +52,6 @@ module MetricFu
52
52
  # config.configure_formatter(:yaml, "customreport.yml")
53
53
  # config.configure_formatter(MyCustomFormatter)
54
54
  #
55
- # == Graph Configuration
56
- #
57
- # Graphing engine can be configured by e.g.
58
- # config.configure_graph_engine(:bluff)
59
- #
60
- #
61
55
  class Configuration
62
56
  require_relative 'environment'
63
57
  require_relative 'io'
@@ -83,17 +77,16 @@ module MetricFu
83
77
  MetricFu::Io::FileSystem.set_directories
84
78
  MetricFu::Formatter::Templates.configure_template(self)
85
79
  @formatters = []
86
- @graph_engine_config = MetricFu::GraphEngine.new
87
80
  end
88
81
 
89
82
  # This allows us to have a nice syntax like:
90
83
  #
91
84
  # MetricFu.run do |config|
92
- # congif.configure_metric(:churn) do
85
+ # config.configure_metric(:churn) do
93
86
  # ...
94
87
  # end
95
88
  #
96
- # config.configure_graph_engine(:bluff)
89
+ # config.configure_formatter(MyCustomFormatter)
97
90
  # end
98
91
  #
99
92
  # See the README for more information on configuration options.
@@ -133,33 +126,13 @@ module MetricFu
133
126
  end
134
127
 
135
128
  # @return [Array<Symbol>] names of enabled metrics with graphs
136
- def graphs
129
+ def graphed_metrics
137
130
  # TODO: This is a common enough need to be pushed into MetricFu::Metric as :enabled_metrics_with_graphs
138
131
  MetricFu::Metric.enabled_metrics.select{|metric|metric.has_graph?}.map(&:name)
139
132
  end
140
133
 
141
- # TODO: Consider if we need to delegate so much to graph_engine_config
142
- # if we should use forwardable or change the api
143
-
144
- # @return [Array<Symbol>] names of available graph engines
145
- # @example [:bluff, :gchart]
146
- def graph_engines
147
- @graph_engine_config.graph_engines
148
- end
149
-
150
- # @return [Symbol] the selected graph engine
151
134
  def graph_engine
152
- @graph_engine_config.graph_engine
153
- end
154
-
155
- # @param graph_engine [Symbol] the name of an available graph engine
156
- def add_graph_engine(graph_engine)
157
- @graph_engine_config.add_graph_engine(graph_engine)
158
- end
159
-
160
- # @param graph_engine [Symbol] sets the selected graph engine to use
161
- def configure_graph_engine(graph_engine)
162
- @graph_engine_config.configure_graph_engine(graph_engine)
135
+ :bluff
163
136
  end
164
137
 
165
138
  end
@@ -106,7 +106,7 @@ module MetricFu
106
106
  'Version' => version,
107
107
  'Verbose Mode' => verbose,
108
108
  'Enabled Metrics' => MetricFu::Metric.enabled_metrics.map(&:name),
109
- # 'Dependencies' => `gem dependency metric_fu`, # TODO how should we handle this?
109
+ 'Dependencies' => MetricFu::GemVersion.dependencies_summary,
110
110
  }
111
111
  end
112
112
 
@@ -15,7 +15,7 @@ module MetricFu
15
15
  mf_debug "** SAVING REPORT DATA OUTPUT TO #{MetricFu::Io::FileSystem.directory('data_directory')}"
16
16
  # TODO: Allow customizing output filenames
17
17
  MetricFu::Formatter::YAML.new(
18
- output: Pathname.pwd.join("#{MetricFu::Io::FileSystem.directory('data_directory')}/#{Time.now.strftime("%Y%m%d")}.yml")
18
+ output: MetricFu.run_path.join("#{MetricFu::Io::FileSystem.directory('data_directory')}/#{Time.now.strftime("%Y%m%d")}.yml")
19
19
  ).finish
20
20
 
21
21
  mf_debug "** SAVING TEMPLATIZED REPORT"
@@ -37,7 +37,7 @@ module MetricFu
37
37
  protected
38
38
 
39
39
  def output_directory
40
- @output ||= dir_for(@options[:output]) || Pathname.pwd.join(MetricFu::Io::FileSystem.directory('output_directory'))
40
+ @output ||= dir_for(@options[:output]) || MetricFu.run_path.join(MetricFu::Io::FileSystem.directory('output_directory'))
41
41
  end
42
42
 
43
43
  # Instantiates a new template class based on the configuration set
@@ -57,11 +57,11 @@ module MetricFu
57
57
  def save_graphs
58
58
  mf_log "** GENERATING GRAPHS"
59
59
  mf_debug "** PREPARING TO GRAPH"
60
- MetricFu.configuration.graphs.each {|graph|
61
- mf_debug "** Graphing #{graph} with #{MetricFu.configuration.graph_engine}"
60
+ MetricFu.configuration.graphed_metrics.each {|graphed_metric|
61
+ mf_debug "** Graphing #{graphed_metric} with #{MetricFu.configuration.graph_engine}"
62
62
  # TODO: This should probably be defined on configuration
63
63
  # rather than the module. See MetricFu::Graph
64
- MetricFu.graph.add(graph, MetricFu.configuration.graph_engine, self.output_directory)
64
+ MetricFu.graph.add(graphed_metric, MetricFu.configuration.graph_engine, self.output_directory)
65
65
  }
66
66
  mf_debug "** GENERATING GRAPH"
67
67
  MetricFu.graph.generate
@@ -0,0 +1,68 @@
1
+ # encoding: utf-8
2
+ require 'open3'
3
+ require 'shellwords'
4
+ require 'metric_fu'
5
+ MetricFu.lib_require { 'logging/mf_debugger' }
6
+ MetricFu.lib_require { 'gem_version' }
7
+ module MetricFu
8
+ class GemRun
9
+
10
+ attr_reader :output, :gem_name, :library_name, :version, :arguments
11
+ def initialize(arguments={})
12
+ @gem_name = arguments.fetch(:gem_name)
13
+ @library_name = arguments.fetch(:metric_name)
14
+ @version = arguments.fetch(:version) { MetricFu::GemVersion.for(library_name) }
15
+ args = arguments.fetch(:args)
16
+ @arguments = args.respond_to?(:scan) ? Shellwords.shellwords(args) : args
17
+ @output = ''
18
+ @errors = []
19
+ end
20
+
21
+ def summary
22
+ "RubyGem #{gem_name}, library #{library_name}, version #{version}, arguments #{arguments}"
23
+ end
24
+
25
+ def run
26
+ @output = execute
27
+ end
28
+
29
+ def execute
30
+ mf_debug "Running #{summary}"
31
+ captured_output = ''
32
+ Open3.popen3("#{library_name}", *arguments) do |stdin, stdout, stderr, wait_thr|
33
+ captured_output << stdout.read.chomp
34
+ end
35
+ rescue StandardError => run_error
36
+ handle_run_error(run_error)
37
+ rescue SystemExit => system_exit
38
+ handle_system_exit(system_exit)
39
+ ensure
40
+ print_errors
41
+ return captured_output
42
+ end
43
+
44
+ def handle_run_error(run_error)
45
+ @errors << "ERROR: #{run_error.inspect}"
46
+ end
47
+
48
+ def handle_system_exit(system_exit)
49
+ status = system_exit.success? ? "SUCCESS" : "FAILURE"
50
+ message = "#{status} with code #{system_exit.status}: " <<
51
+ "#{system_exit.message}: #{system_exit.backtrace.inspect}"
52
+ if status == 'SUCCESS'
53
+ mf_debug message
54
+ else
55
+ @errors << message
56
+ end
57
+ end
58
+
59
+ def print_errors
60
+ return if @errors.empty?
61
+ STDERR.puts "ERRORS running #{summary}"
62
+ @errors.each do |error|
63
+ STDERR.puts "\t" << error
64
+ end
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,57 @@
1
+ require 'rubygems'
2
+ module MetricFu
3
+ class GemVersion
4
+
5
+ def initialize
6
+ @gem_spec = Gem::Specification.load(gemspec)
7
+ end
8
+
9
+ def gemspec
10
+ gemspec = File.join(MetricFu.root_dir, 'metric_fu.gemspec')
11
+ end
12
+
13
+ def new_dependency(name, version)
14
+ Gem::Dependency.new(name, version, :runtime)
15
+ end
16
+
17
+ def gem_runtime_dependencies
18
+ @gem_runtime_dependencies ||= begin
19
+ @gem_spec.dependencies.select{|gem| gem.type == :runtime}.each do |gem_dep|
20
+ gem_dep.name = gem_dep.name.downcase.sub('metric_fu-','')
21
+ end << new_dependency('rcov', ['~> 0.8'])
22
+ end
23
+ end
24
+
25
+ def for(name)
26
+ name.downcase!
27
+ dep = gem_runtime_dependencies.find(unknown_dependency(name)) do |gem_dep|
28
+ gem_dep.name == name
29
+ end
30
+
31
+ dep.requirements_list
32
+ end
33
+
34
+ def unknown_dependency(name)
35
+ ->{ new_dependency(name, ['>= 0']) }
36
+ end
37
+
38
+ RESOLVER = new
39
+ def self.for(name)
40
+ RESOLVER.for(name).dup
41
+ end
42
+
43
+ def self.dependencies
44
+ RESOLVER.gem_runtime_dependencies.dup
45
+ end
46
+
47
+ def self.dependencies_summary
48
+ dependencies.map do |gem_dep|
49
+ {
50
+ 'name' => gem_dep.name,
51
+ 'version' => gem_dep.requirements_list,
52
+ }
53
+ end
54
+ end
55
+
56
+ end
57
+ end
@@ -127,7 +127,7 @@ module MetricFu
127
127
  end
128
128
 
129
129
  def path_relative_to_base(path)
130
- pathname = Pathname.pwd.join(MetricFu::Io::FileSystem.directory('base_directory')) # make full path relative to base directory
130
+ pathname = MetricFu.run_path.join(MetricFu::Io::FileSystem.directory('base_directory')) # make full path relative to base directory
131
131
  pathname.join(path)
132
132
  end
133
133
  end
@@ -11,11 +11,9 @@ Dir.glob(File.join(MetricFu.lib_dir, '*.rb')).
11
11
  each do |file|
12
12
  require file
13
13
  end
14
- # prevent the task from being run multiple times.
15
- unless Rake::Task.task_defined? "metrics:all"
16
- # Load the rakefile so users of the gem get the default metric_fu task
17
- MetricFu.tasks_load 'metric_fu.rake'
18
- end
14
+
15
+ MetricFu.load_tasks('metric_fu.rake', task_name: 'metrics:all')
16
+
19
17
  Dir.glob(File.join(MetricFu.data_structures_dir, '**/*.rb')).each do |file|
20
18
  require file
21
19
  end
@@ -24,6 +24,14 @@ module MetricFu
24
24
  end
25
25
 
26
26
  # TODO: Reduce duplication of directory logic
27
+ # Adds methods x_dir and _x_require for the directory x,
28
+ # relative to the metric_fu lib, to the given klass
29
+ # @param klass [Class] the klass to add methods for the specified directories
30
+ # @yieldreturn [Array<String>] Takes a list of directories and adds readers for each
31
+ # @example For the directory 'metrics', which is relative to the metric_fu lib directory,
32
+ # creates on the klass two methods:
33
+ # ::metrics_dir which returns the full path
34
+ # ::metrics_require which takes a block of files to require relative to the metrics_dir
27
35
  def create_dirs(klass)
28
36
  class << klass
29
37
  Array(yield).each do |dir|
@@ -35,6 +43,12 @@ module MetricFu
35
43
  end
36
44
  end
37
45
 
46
+ # Adds method x_dir relative to the metric_fu artifact directory to the given klass
47
+ # And strips any leading non-alphanumerical character from the directory name
48
+ # @param klass [Class] the klass to add methods for the specified artifact sub-directories
49
+ # @yieldreturn [Array<String>] Takes a list of directories and adds readers for each
50
+ # @example For the artifact sub-directory '_scratch', creates on the klass one method:
51
+ # ::scratch_dir (which notably has the leading underscore removed)
38
52
  def create_artifact_subdirs(klass)
39
53
  class << klass
40
54
  Array(yield).each do |dir|
@@ -45,8 +59,16 @@ module MetricFu
45
59
  end
46
60
  end
47
61
 
48
- def load_tasks(tasks_relative_path)
49
- load File.join(@lib_root, 'tasks', *Array(tasks_relative_path))
62
+ # Load specified task task only once
63
+ # if and only if rake is required and the task is not yet defined
64
+ # to prevent the task from being loaded multiple times
65
+ # @param tasks_relative_path [String] 'metric_fu.rake' by default
66
+ # @param options [Hash] optional task_name to check if loaded
67
+ # @option options [String] :task_name The task_name to load, if not yet loaded
68
+ def load_tasks(tasks_relative_path, options={task_name: ''})
69
+ if defined?(Rake::Task) and not Rake::Task.task_defined?(options[:task_name])
70
+ load File.join(@lib_root, 'tasks', *Array(tasks_relative_path))
71
+ end
50
72
  end
51
73
 
52
74
  def setup
@@ -56,7 +78,14 @@ module MetricFu
56
78
  MetricFu.lib_require { 'initial_requires' }
57
79
  # Load a few things to make our lives easier elsewhere.
58
80
  MetricFu.lib_require { 'load_files' }
81
+ load_user_configuration
82
+ end
83
+
84
+ def load_user_configuration
85
+ file = File.join(MetricFu.run_dir, '.metrics')
86
+ load file if File.exist?(file)
59
87
  end
88
+
60
89
  end
61
90
  end
62
91