Class: ActiveMutator::ConfigFile

Inherits:
Object
  • Object
show all
Defined in:
lib/active_mutator/config_file.rb

Overview

Project config file, layered UNDER CLI flags: CLI.parse seeds its option defaults from this before OptionParser runs, so any flag given on the command line wins. Strict on unknown keys and types — a typo silently ignored would be a config that silently doesn't apply.

Constant Summary collapse

FILENAME =
".active_mutator.yml"
FORMATS =
%w[terminal json stryker-json github].freeze
KEYS =
{
  "jobs" => :integer,
  "format" => :format,
  "timeout_factor" => :number,
  "timeout_floor" => :number,
  "browser_boot_seconds" => :number,
  "fail_at" => :score,
  "exclude" => :string_list,
  "serial_patterns" => :string_list,
  "requires" => :string_list,
  "operators" => :string_list,
  "preload_helper" => :preload_helper,
  "adaptive_timeout" => :boolean
}.freeze
RENAMES =

YAML keys that don't match their Config member name.

{ "operators" => :operator_paths }.freeze

Class Method Summary collapse

Class Method Details

.coerce(key, validator, value) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/active_mutator/config_file.rb', line 53

def self.coerce(key, validator, value)
  case validator
  when :integer
    raise Error, "#{FILENAME}: #{key} must be an integer" unless value.is_a?(Integer)
    value
  when :number
    raise Error, "#{FILENAME}: #{key} must be a number" unless value.is_a?(Numeric)
    value.to_f
  when :score
    raise Error, "#{FILENAME}: #{key} must be a number" unless value.is_a?(Numeric)
    raise Error, "#{FILENAME}: #{key} must be within 0..100" unless (0..100).cover?(value)
    value.to_f
  when :format
    unless FORMATS.include?(value)
      raise Error, "#{FILENAME}: format must be one of #{FORMATS.join(", ")}"
    end
    value.tr("-", "_").to_sym
  when :string_list
    unless value.is_a?(Array) && value.all?(String)
      raise Error, "#{FILENAME}: #{key} must be a list of strings"
    end
    value
  when :boolean
    unless [true, false].include?(value)
      raise Error, "#{FILENAME}: #{key} must be true or false"
    end
    value
  when :preload_helper
    return :none if value == false
    raise Error, "#{FILENAME}: preload_helper must be a path or false" unless value.is_a?(String)
    value
  else
    raise Error, "unhandled validator #{validator}"
  end
end

.load(root) ⇒ Object

Raises:



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/active_mutator/config_file.rb', line 31

def self.load(root)
  path = File.join(root, FILENAME)
  return {} unless File.exist?(path)

  data = parse(path)
  return {} if data.nil?
  raise Error, "#{FILENAME}: top level must be a mapping" unless data.is_a?(Hash)

  data.to_h do |key, value|
    validator = KEYS[key]
    raise Error, "#{FILENAME}: unknown config key: #{key}" unless validator

    [RENAMES.fetch(key, key.to_sym), coerce(key, validator, value)]
  end
end

.parse(path) ⇒ Object



47
48
49
50
51
# File 'lib/active_mutator/config_file.rb', line 47

def self.parse(path)
  YAML.safe_load_file(path, aliases: true)
rescue Psych::Exception => e
  raise Error, "#{FILENAME}: #{e.message}"
end