123456789_123456789_123456789_123456789_123456789_

Module: SimpleCov::CLI::Dotfile

Relationships & Source Files
Defined in: lib/simplecov/cli/dotfile.rb

Overview

Loads a project's .simplecov config file purely to read .coverage_dir from it, with SimpleCov.start and the at_exit hook installer neutered so the load doesn't trigger coverage tracking. Used by the ::SimpleCov::CLI to default --input / --report paths to whatever the project's dotfile declares, without making every read-only subcommand pay for actually starting Coverage.

Class Method Summary

Class Method Details

.coverage_dir (mod_func)

[ GitHub ]

  
# File 'lib/simplecov/cli/dotfile.rb', line 16

def coverage_dir
  dotfile = find
  return "coverage" unless dotfile

  with_simplecov_loaded { read_from(dotfile) }
rescue LoadError, StandardError => e
  # simplecov:disable — defensive fallback for a bad dotfile (parse
  # error, EACCES, etc.); never fires in the project's own dogfood run
  warn "simplecov: failed to read coverage_dir from #{dotfile}: #{e.class}: #{e.message}"
  "coverage"
  # simplecov:enable
end

.find (mod_func)

[ GitHub ]

  
# File 'lib/simplecov/cli/dotfile.rb', line 47

def find
  dir = Pathname.new(Dir.pwd)
  loop do
    candidate = dir.join(".simplecov")
    return candidate.to_s if candidate.exist?
    break if dir.root?

    dir = dir.parent
  end
  nil
end

.load_with_start_neutered(path) (mod_func)

Load path with SimpleCov.start and the at_exit installer turned into no-ops, so a project whose dotfile calls SimpleCov.start doesn't trigger Coverage just because we asked for .coverage_dir. Config inside any SimpleCov.start { ... } block still runs.

[ GitHub ]

  
# File 'lib/simplecov/cli/dotfile.rb', line 79

def load_with_start_neutered(path)
  klass = SimpleCov.singleton_class
  names = %i[start_tracking install_at_exit_hook]
  stash = names.to_h { |name| [name, klass.instance_method(name)] }
  # define_method over an existing method emits a "method redefined"
  # warning under $VERBOSE; the override and restore are intentional.
  silence_verbose { names.each { |name| klass.define_method(name) { nil } } }
  load path
ensure
  silence_verbose { stash.each { |name, method| klass.define_method(name, method) } }
end

.read_from(dotfile) (mod_func)

Load the dotfile, snapshot+restore SimpleCov.coverage_dir so we don't quietly clobber it in a host process that's already configured (e.g. when the ::SimpleCov::CLI is exercised inline by simplecov's own spec suite). The snapshot is intentionally narrow: a dotfile can still mutate other ::SimpleCov configuration (filters, groups, formatters, command_name, ...) via SimpleCov.configure or SimpleCov.start { ... } blocks. The CLI normally runs as a top-level process where that's harmless; callers driving it from inside a Ruby host that cares about isolation should arrange that themselves.

[ GitHub ]

  
# File 'lib/simplecov/cli/dotfile.rb', line 39

def read_from(dotfile)
  snapshot = SimpleCov.instance_variable_get(:@coverage_dir)
  load_with_start_neutered(dotfile)
  dir = SimpleCov.coverage_dir
  SimpleCov.instance_variable_set(:@coverage_dir, snapshot)
  dir
end

.silence_verbose (mod_func)

[ GitHub ]

  
# File 'lib/simplecov/cli/dotfile.rb', line 91

def silence_verbose
  previous = $VERBOSE
  $VERBOSE = nil
  yield
ensure
  $VERBOSE = previous
end

.with_simplecov_loaded (mod_func)

[ GitHub ]

  
# File 'lib/simplecov/cli/dotfile.rb', line 59

def with_simplecov_loaded
  previous_no_defaults = ENV.fetch("SIMPLECOV_NO_DEFAULTS", nil)
  previous_cli         = ENV.fetch("SIMPLECOV_CLI", nil)
  ENV["SIMPLECOV_NO_DEFAULTS"] = "1"
  # SIMPLECOV_CLI lets a project's `.simplecov` opt some config into
  # CLI-only behavior — e.g. simplecov itself sets `coverage_dir`
  # to the dogfood path here but skips that for descendants.
  ENV["SIMPLECOV_CLI"] = "1"
  require "simplecov"
  yield
ensure
  ENV["SIMPLECOV_NO_DEFAULTS"] = previous_no_defaults
  ENV["SIMPLECOV_CLI"]         = previous_cli
end