require 'erb' module MetricFu TEMPLATE_DIR = File.join(File.dirname(__FILE__), '..', 'templates') BASE_DIRECTORY = ENV['CC_BUILD_ARTIFACTS'] || 'tmp/metric_fu' class << self # The Configuration instance used to configure the Rails environment def configuration @@configuration ||= Configuration.new end def churn configuration.churn end def coverage configuration.coverage end def flay configuration.flay end def flog configuration.flog end def metrics configuration.metrics end def open_in_browser? configuration.general[:open_in_browser] && PLATFORM['darwin'] && !run_by_cruise_control? end def saikuro configuration.saikuro end def reek configuration.reek end def roodi configuration.roodi end def run_by_cruise_control? !!ENV['CC_BUILD_ARTIFACTS'] end def uses_git? File.exist?(".git") end def uses_svn? File.exist?(".svn") end def can_churn? uses_git? || uses_svn? end def is_rails? File.exist?("config/environment.rb") end def code_dirs dirs = ['lib'] dirs << 'app' if is_rails? dirs.sort{|v1, v2| v1.to_s <=> v2.to_s} end def default_metrics metrics = [:coverage, :flog, :flay, :reek, :roodi, :saikuro ] metrics << :stats if is_rails? # Churning requires a subversion or git repo metrics << :churn if can_churn? metrics.sort{|v1, v2| v1.to_s <=> v2.to_s} end end class Configuration attr_accessor :churn, :coverage, :flay, :flog, :metrics, :reek, :roodi, :saikuro, :general def initialize raise "Use config.churn instead of MetricFu::CHURN_OPTIONS" if defined? ::MetricFu::CHURN_OPTIONS raise "Use config.flog[:dirs_to_flog] instead of MetricFu::DIRECTORIES_TO_FLOG" if defined? ::MetricFu::DIRECTORIES_TO_FLOG raise "Use config.saikuro instead of MetricFu::SAIKURO_OPTIONS" if defined? ::MetricFu::SAIKURO_OPTIONS reset end def self.run() yield MetricFu.configuration end def reset @general = { :open_in_browser => true } @churn = {} rcov_opts = ["--sort coverage", "--html", "--exclude /gems/,/Library/,spec"] rcov_opts << "--rails" if MetricFu.is_rails? @coverage = { :test_files => ['test/**/*_test.rb', 'spec/**/*_spec.rb'], :rcov_opts => rcov_opts } @flay = { :dirs_to_flay => MetricFu.code_dirs} @flog = { :dirs_to_flog => MetricFu.code_dirs} @reek = { :dirs_to_reek => MetricFu.code_dirs} @roodi = { :dirs_to_roodi => MetricFu.code_dirs} @metrics = MetricFu.default_metrics @saikuro = {} end def saikuro=(options) raise "saikuro need to be a Hash" unless options.is_a?(Hash) @saikuro = options end end module Base ###################################################################### # Base class for report Generators # class Generator def initialize(options={}) @base_dir = self.class.metric_dir end def self.metric_dir File.join(BASE_DIRECTORY, template_name) end def self.template_name self.to_s.split('::').last.downcase end def self.generate_report(options={}) FileUtils.mkdir_p(metric_dir, :verbose => false) unless File.directory?(metric_dir) self.new(options).generate_report end def save_html(content, file='index.html') open("#{@base_dir}/#{file}", "w") do |f| f.puts content end end def generate_report save_html(generate_html) end def generate_html analyze html = ERB.new(File.read(template_file)).result(binding) end def template_name self.class.template_name end def template_file File.join(MetricFu::TEMPLATE_DIR, "#{template_name}.html.erb") end ######################## # Template methods def inline_css(css) open(File.join(MetricFu::TEMPLATE_DIR, css)) { |f| f.read } end def link_to_filename(name, line = nil) if MetricFu.run_by_cruise_control? cc_link_to_filename(name, line) else system_link_to_filename(name, line) end end def cycle(first_value, second_value, iteration) return first_value if iteration % 2 == 0 return second_value end private def cc_link_to_filename(name, line = nil) if MetricFu.configuration.general[:url_prefix] MetricFu.configuration.general[:url_prefix] += '/' unless MetricFu.configuration.general[:url_prefix] =~ /\/$/ %{#{name}} else %{"#{name}"} # No link for cruise control without a prefix end end def system_link_to_filename(name, line = nil) filename = File.expand_path(name) if PLATFORM['darwin'] %{#{name}} else %{#{name}} end end end end end