lib/mutant/cli.rb in mutant-0.8.24 vs lib/mutant/cli.rb in mutant-0.9.0

- old
+ new

@@ -1,75 +1,103 @@ # frozen_string_literal: true module Mutant # Commandline parser / runner class CLI - include Adamantium::Flat, Equalizer.new(:config), Procto.call(:config) + include Concord.new(:world, :config) - # Error failed when CLI argv is invalid - Error = Class.new(RuntimeError) + private_class_method :new + OPTIONS = + %i[ + add_environment_options + add_mutation_options + add_filter_options + add_debug_options + ].freeze + + private_constant(*constants(false)) + # Run cli with arguments # - # @param [Array<String>] arguments + # @param [World] world + # the outside world # + # @param [Config] default_config + # the default config + # + # @param [Array<String>] + # the user provided arguments + # # @return [Boolean] - def self.run(arguments) - Runner.call(Env::Bootstrap.call(call(arguments))).success? - rescue Error => exception - $stderr.puts(exception.message) - false + # + # rubocop:disable Style/Semicolon + # + # ignore :reek:LongParameterList + def self.run(world, default_config, arguments) + License + .apply(world) + .apply { Config.load_config_file(world, default_config) } + .apply { |file_config| apply(world, file_config, arguments) } + .apply { |cli_config| Bootstrap.apply(world, cli_config) } + .apply(&Runner.method(:apply)) + .from_right { |error| world.stderr.puts(error); return false } + .success? end + # rubocop:enable Style/Semicolon - # Initialize object + # Parse arguments into config # - # @param [Array<String>] + # @param [World] world + # @param [Config] config + # @param [Array<String>] arguments # - # @return [undefined] - def initialize(arguments) - @config = Config::DEFAULT - - parse(arguments) + # @return [Either<OptionParser::ParseError, Config>] + # + # ignore :reek:LongParameterList + def self.apply(world, config, arguments) + Either + .wrap_error(OptionParser::ParseError) { new(world, config).parse(arguments) } + .lmap(&:message) end - # Config parsed from CLI - # - # @return [Config] - attr_reader :config + # Local opt out of option parser defaults + class OptionParser < ::OptionParser + # Kill defaults added by option parser that + # inference with ours under mutation testing. + define_method(:add_officious) {} + end # OptionParser - private - # Parse the command-line options # # @param [Array<String>] arguments # Command-line options and arguments to be parsed. # - # @fail [Error] - # An error occurred while parsing the options. - # - # @return [undefined] + # @return [Config] def parse(arguments) opts = OptionParser.new do |builder| builder.banner = 'usage: mutant [options] MATCH_EXPRESSION ...' - %i[add_environment_options add_mutation_options add_filter_options add_debug_options].each do |name| + OPTIONS.each do |name| __send__(name, builder) end end - parse_match_expressions(opts.parse!(arguments)) - rescue OptionParser::ParseError => error - raise(Error, error) + parse_match_expressions(opts.parse!(arguments.dup)) + + config end + private + # Parse matchers # # @param [Array<String>] expressions # # @return [undefined] def parse_match_expressions(expressions) expressions.each do |expression| - add_matcher(:match_expressions, config.expression_parser.(expression)) + add_matcher(:match_expressions, config.expression_parser.apply(expression).from_right) end end # Add environmental options # @@ -92,51 +120,38 @@ opts.on('-j', '--jobs NUMBER', 'Number of kill jobs. Defaults to number of processors.') do |number| with(jobs: Integer(number)) end end - # Use integration - # - # @param [String] name - # - # @return [undefined] - def setup_integration(name) - with(integration: Integration.setup(config.kernel, name)) - rescue LoadError - raise Error, "Could not load integration #{name.inspect} (you may want to try installing the gem mutant-#{name})" - end - # Add mutation options # # @param [OptionParser] opts # # @return [undefined] def add_mutation_options(opts) opts.separator(nil) opts.separator('Options:') - opts.on('--use INTEGRATION', 'Use INTEGRATION to kill mutations', &method(:setup_integration)) + opts.on('--use INTEGRATION', 'Use INTEGRATION to kill mutations') do |name| + with(integration: name) + end end # Add filter options # # @param [OptionParser] opts # # @return [undefined] def add_filter_options(opts) opts.on('--ignore-subject EXPRESSION', 'Ignore subjects that match EXPRESSION as prefix') do |pattern| - add_matcher(:ignore_expressions, config.expression_parser.(pattern)) + add_matcher(:ignore_expressions, config.expression_parser.apply(pattern).from_right) end opts.on('--since REVISION', 'Only select subjects touched since REVISION') do |revision| add_matcher( :subject_filters, Repository::SubjectFilter.new( - Repository::Diff.new( - config: config, - from: Repository::Diff::HEAD, - to: revision - ) + Repository::Diff.new(to: revision, world: world) ) ) end end @@ -148,16 +163,16 @@ def add_debug_options(opts) opts.on('--fail-fast', 'Fail fast') do with(fail_fast: true) end opts.on('--version', 'Print mutants version') do - puts("mutant-#{VERSION}") - config.kernel.exit + world.stdout.puts("mutant-#{VERSION}") + world.kernel.exit end opts.on_tail('-h', '--help', 'Show this message') do - puts(opts.to_s) - config.kernel.exit + world.stdout.puts(opts.to_s) + world.kernel.exit end end # With configuration # @@ -191,8 +206,7 @@ # # @return [undefined] def add_matcher(attribute, value) with(matcher: config.matcher.add(attribute, value)) end - end # CLI end # Mutant