diff --git a/lib/mutant.rb b/lib/mutant.rb index 0ce8c5d1..c89c554e 100644 --- a/lib/mutant.rb +++ b/lib/mutant.rb @@ -114,7 +114,6 @@ require 'mutant/runner' require 'mutant/runner/config' require 'mutant/runner/subject' require 'mutant/runner/mutation' -require 'mutant/cli_parser' require 'mutant/cli' require 'mutant/cli/classifier' require 'mutant/cli/classifier/namespace' diff --git a/lib/mutant/cli.rb b/lib/mutant/cli.rb index 3c3b112f..f646c45a 100644 --- a/lib/mutant/cli.rb +++ b/lib/mutant/cli.rb @@ -1,9 +1,17 @@ +require 'optparse' + module Mutant # Comandline parser - class CLI < CLIParser + class CLI include Adamantium::Flat, Equalizer.new(:config) + # Error raised when CLI argv is inalid + Error = Class.new(RuntimeError) + + EXIT_FAILURE = 1 + EXIT_SUCCESS = 0 + # Run cli with arguments # # @param [Array] arguments @@ -13,8 +21,8 @@ module Mutant # # @api private # - def self.run(*arguments) - config = new(*arguments).config + def self.run(arguments) + config = new(arguments).config runner = Runner::Config.run(config) runner.success? ? EXIT_SUCCESS : EXIT_FAILURE rescue Error => exception @@ -22,15 +30,6 @@ module Mutant EXIT_FAILURE end - OPTIONS = { - '--code' => [:add_filter, Mutation::Filter::Code ], - '--debug' => [:set_debug ], - '-d' => [:set_debug ], - '--rspec-unit' => [:set_strategy, Strategy::Rspec::Unit ], - '--rspec-full' => [:set_strategy, Strategy::Rspec::Full ], - '--rspec-dm2' => [:set_strategy, Strategy::Rspec::DM2 ] - }.freeze - # Initialize objecct # # @param [Array] @@ -39,9 +38,10 @@ module Mutant # # @api private # - def initialize(arguments) + def initialize(arguments=[]) @filters, @matchers = [], [] - super(arguments) + + parse(arguments) strategy matcher end @@ -135,57 +135,18 @@ module Mutant end memoize :matcher - # Move processed argument by amount - # - # @param [Fixnum] amount - # the amount of arguments to be consumed - # - # @return [undefined] - # - # @api private - # - def consume(amount) - @index += amount - end - - # Process matcher argument - # - # @return [undefined] - # - # @api private - # - def dispatch_matcher - argument = current_argument - consume(1) - matcher = Classifier.build(argument) - @matchers << matcher if matcher - end - - # Process option argument - # - # @return [Undefined] - # - # @api private - # - def dispatch_option - argument = current_argument - arguments = *OPTIONS.fetch(argument) do - raise Error, "Unknown option: #{argument.inspect}" - end - send(*arguments) - end - # Add mutation filter # # @param [Class] klass # + # @param [String] filter + # # @return [undefined] # # @api private # - def add_filter(klass) - @filters << klass.new(current_option_value) - consume(2) + def add_filter(klass,filter) + @filters << klass.new(filter) end # Set debug mode @@ -195,7 +156,6 @@ module Mutant # @return [undefined] # def set_debug - consume(1) @debug = true end @@ -208,8 +168,65 @@ module Mutant # @return [undefined] # def set_strategy(strategy) - consume(1) @strategy = strategy end + + # Parses the command-line options. + # + # @param [Array] arguments + # Command-line options and arguments to be parsed. + # + # @raise [Error] + # An error occurred while parsing the options. + # + # @api private + # + def parse(arguments) + opts = OptionParser.new do |opts| + opts.banner = 'usage: mutant STRATEGY [options] MATCHERS ...' + + opts.separator '' + opts.separator 'Strategies:' + + opts.on('--rspec-unit','executes all specs under ./spec/unit') do + set_strategy Strategy::Rspec::Unit + end + + opts.on('--rspec-full','executes all specs under ./spec') do + set_strategy Strategy::Rspec::Full + end + + opts.on('--rspec-dm2','executes spec/unit/namespace/class/method_spec.rb') do + set_strategy Strategy::Rspec::DM2 + end + + opts.separator '' + opts.separator 'Options:' + + opts.on('--code FILTER','Adds a code filter') do |filter| + add_filter Mutation::Filter::Code, filter + end + + opts.on('-d','--debug','Enable debugging output') do + set_debug + end + + opts.on_tail('-h','--help','Show this message') do + puts opts + exit + end + end + + matchers = begin + opts.parse!(arguments) + rescue OptionParser::ParseError => e + raise(Error,e.message,e.backtrace) + end + + matchers.each do |pattern| + matcher = Classifier.build(pattern) + @matchers << matcher if matcher + end + end end end diff --git a/lib/mutant/cli_parser.rb b/lib/mutant/cli_parser.rb deleted file mode 100644 index cd701b41..00000000 --- a/lib/mutant/cli_parser.rb +++ /dev/null @@ -1,87 +0,0 @@ -module Mutant - # Base class for cli parsers - # - # I hate base classes for reusable functionallity. - # But could not come up with a nice composition/instantiation - # solution. - # - class CLIParser - - # Error raised when CLI argv is inalid - Error = Class.new(RuntimeError) - - EXIT_FAILURE = 1 - EXIT_SUCCESS = 0 - - OPTION_PATTERN = %r(\A-(?:-)?[a-zA-Z0-9\-]+\z).freeze - - # Initialize CLI - # - # @param [Array] arguments - # - # @return [undefined] - # - # @api private - # - def initialize(arguments) - @arguments, @index = arguments, 0 - while @index < @arguments.length - dispatch - end - end - - private - - # Return option for argument with index - # - # @param [Fixnum] index - # - # @return [String] - # - # @api private - # - def option(index) - @arguments.fetch(index+1) - end - - # Return current argument - # - # @return [String] - # - # @api private - # - def current_argument - @arguments.fetch(@index) - end - - # Return current option value - # - # @return [String] - # - # @raise [CLI::Error] - # raises error when option is missing - # - # @api private - # - def current_option_value - @arguments.fetch(@index+1) - rescue IndexError - raise Error, "#{current_argument.inspect} is missing an argument" - end - - # Process current argument - # - # @return [undefined] - # - # @api private - # - def dispatch - if OPTION_PATTERN =~ current_argument - dispatch_option - else - dispatch_matcher - end - end - - end -end diff --git a/spec/unit/mutant/cli/class_methods/new_spec.rb b/spec/unit/mutant/cli/class_methods/new_spec.rb index 9508125d..12a77593 100644 --- a/spec/unit/mutant/cli/class_methods/new_spec.rb +++ b/spec/unit/mutant/cli/class_methods/new_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' shared_examples_for 'an invalid cli run' do it 'should raise error' do - expect { subject }.to raise_error(Mutant::CLIParser::Error, expected_message) + expect { subject }.to raise_error(Mutant::CLI::Error, expected_message) end end @@ -35,7 +35,7 @@ describe Mutant::CLI, '.new' do context 'with unknown flag' do let(:arguments) { %w(--invalid) } - let(:expected_message) { 'Unknown option: "--invalid"' } + let(:expected_message) { 'invalid option: --invalid' } it_should_behave_like 'an invalid cli run' end @@ -43,7 +43,7 @@ describe Mutant::CLI, '.new' do context 'with unknown option' do let(:arguments) { %w(--invalid Foo) } - let(:expected_message) { 'Unknown option: "--invalid"' } + let(:expected_message) { 'invalid option: --invalid' } it_should_behave_like 'an invalid cli run' end @@ -63,8 +63,8 @@ describe Mutant::CLI, '.new' do end context 'with code filter and missing argument' do - let(:arguments) { %w(--rspec-unit --code) } - let(:expected_message) { '"--code" is missing an argument' } + let(:arguments) { %w(--rspec-unit --code) } + let(:expected_message) { 'missing argument: --code' } it_should_behave_like 'an invalid cli run' end