Use OptionParser (closes #7).
* Supports -h and --help options. * Rescue OptionParser::ParseErrors and re-raise them as CLI::Errors. * Moved CLIParser::EXIT_FAILURE, EXIT_SUCCESS and Error into CLI. * Removed CLIParser.
This commit is contained in:
parent
f730590d4d
commit
b4108f17ea
4 changed files with 81 additions and 152 deletions
|
@ -114,7 +114,6 @@ require 'mutant/runner'
|
||||||
require 'mutant/runner/config'
|
require 'mutant/runner/config'
|
||||||
require 'mutant/runner/subject'
|
require 'mutant/runner/subject'
|
||||||
require 'mutant/runner/mutation'
|
require 'mutant/runner/mutation'
|
||||||
require 'mutant/cli_parser'
|
|
||||||
require 'mutant/cli'
|
require 'mutant/cli'
|
||||||
require 'mutant/cli/classifier'
|
require 'mutant/cli/classifier'
|
||||||
require 'mutant/cli/classifier/namespace'
|
require 'mutant/cli/classifier/namespace'
|
||||||
|
|
|
@ -1,9 +1,17 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
module Mutant
|
module Mutant
|
||||||
|
|
||||||
# Comandline parser
|
# Comandline parser
|
||||||
class CLI < CLIParser
|
class CLI
|
||||||
include Adamantium::Flat, Equalizer.new(:config)
|
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
|
# Run cli with arguments
|
||||||
#
|
#
|
||||||
# @param [Array<String>] arguments
|
# @param [Array<String>] arguments
|
||||||
|
@ -13,8 +21,8 @@ module Mutant
|
||||||
#
|
#
|
||||||
# @api private
|
# @api private
|
||||||
#
|
#
|
||||||
def self.run(*arguments)
|
def self.run(arguments)
|
||||||
config = new(*arguments).config
|
config = new(arguments).config
|
||||||
runner = Runner::Config.run(config)
|
runner = Runner::Config.run(config)
|
||||||
runner.success? ? EXIT_SUCCESS : EXIT_FAILURE
|
runner.success? ? EXIT_SUCCESS : EXIT_FAILURE
|
||||||
rescue Error => exception
|
rescue Error => exception
|
||||||
|
@ -22,15 +30,6 @@ module Mutant
|
||||||
EXIT_FAILURE
|
EXIT_FAILURE
|
||||||
end
|
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
|
# Initialize objecct
|
||||||
#
|
#
|
||||||
# @param [Array<String>]
|
# @param [Array<String>]
|
||||||
|
@ -39,9 +38,10 @@ module Mutant
|
||||||
#
|
#
|
||||||
# @api private
|
# @api private
|
||||||
#
|
#
|
||||||
def initialize(arguments)
|
def initialize(arguments=[])
|
||||||
@filters, @matchers = [], []
|
@filters, @matchers = [], []
|
||||||
super(arguments)
|
|
||||||
|
parse(arguments)
|
||||||
strategy
|
strategy
|
||||||
matcher
|
matcher
|
||||||
end
|
end
|
||||||
|
@ -135,57 +135,18 @@ module Mutant
|
||||||
end
|
end
|
||||||
memoize :matcher
|
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
|
# Add mutation filter
|
||||||
#
|
#
|
||||||
# @param [Class<Mutant::Filter>] klass
|
# @param [Class<Mutant::Filter>] klass
|
||||||
#
|
#
|
||||||
|
# @param [String] filter
|
||||||
|
#
|
||||||
# @return [undefined]
|
# @return [undefined]
|
||||||
#
|
#
|
||||||
# @api private
|
# @api private
|
||||||
#
|
#
|
||||||
def add_filter(klass)
|
def add_filter(klass,filter)
|
||||||
@filters << klass.new(current_option_value)
|
@filters << klass.new(filter)
|
||||||
consume(2)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Set debug mode
|
# Set debug mode
|
||||||
|
@ -195,7 +156,6 @@ module Mutant
|
||||||
# @return [undefined]
|
# @return [undefined]
|
||||||
#
|
#
|
||||||
def set_debug
|
def set_debug
|
||||||
consume(1)
|
|
||||||
@debug = true
|
@debug = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -208,8 +168,65 @@ module Mutant
|
||||||
# @return [undefined]
|
# @return [undefined]
|
||||||
#
|
#
|
||||||
def set_strategy(strategy)
|
def set_strategy(strategy)
|
||||||
consume(1)
|
|
||||||
@strategy = strategy
|
@strategy = strategy
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Parses the command-line options.
|
||||||
|
#
|
||||||
|
# @param [Array<String>] 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
|
||||||
end
|
end
|
||||||
|
|
|
@ -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<String>] 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
|
|
|
@ -2,7 +2,7 @@ require 'spec_helper'
|
||||||
|
|
||||||
shared_examples_for 'an invalid cli run' do
|
shared_examples_for 'an invalid cli run' do
|
||||||
it 'should raise error' 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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ describe Mutant::CLI, '.new' do
|
||||||
context 'with unknown flag' do
|
context 'with unknown flag' do
|
||||||
let(:arguments) { %w(--invalid) }
|
let(:arguments) { %w(--invalid) }
|
||||||
|
|
||||||
let(:expected_message) { 'Unknown option: "--invalid"' }
|
let(:expected_message) { 'invalid option: --invalid' }
|
||||||
|
|
||||||
it_should_behave_like 'an invalid cli run'
|
it_should_behave_like 'an invalid cli run'
|
||||||
end
|
end
|
||||||
|
@ -43,7 +43,7 @@ describe Mutant::CLI, '.new' do
|
||||||
context 'with unknown option' do
|
context 'with unknown option' do
|
||||||
let(:arguments) { %w(--invalid Foo) }
|
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'
|
it_should_behave_like 'an invalid cli run'
|
||||||
end
|
end
|
||||||
|
@ -64,7 +64,7 @@ describe Mutant::CLI, '.new' do
|
||||||
|
|
||||||
context 'with code filter and missing argument' do
|
context 'with code filter and missing argument' do
|
||||||
let(:arguments) { %w(--rspec-unit --code) }
|
let(:arguments) { %w(--rspec-unit --code) }
|
||||||
let(:expected_message) { '"--code" is missing an argument' }
|
let(:expected_message) { 'missing argument: --code' }
|
||||||
|
|
||||||
it_should_behave_like 'an invalid cli run'
|
it_should_behave_like 'an invalid cli run'
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue