diff --git a/lib/mutant/matcher.rb b/lib/mutant/matcher.rb index 8aaa3f16..d388dd4d 100644 --- a/lib/mutant/matcher.rb +++ b/lib/mutant/matcher.rb @@ -1,7 +1,8 @@ module Mutant # Abstract matcher to find ASTs to mutate class Matcher - include Enumerable, Abstract + include Enumerable, Abstract, Immutable + extend DescendantsTracker # Enumerate subjects # @@ -19,7 +20,36 @@ module Mutant # abstract_method :identification - private + # Return matcher + # + # @param [String] input + # + # @return [nil] + # returns nil as default implementation + # + # @api private + # + def self.parse(input) + nil + end + # Return match from string + # + # @param [String] input + # + # @return [Matcher] + # returns matcher input if successful + # + # @return [nil] + # returns nil otherwise + # + def self.from_string(input) + descendants.each do |descendant| + matcher = descendant.parse(input) + return matcher if matcher + end + + nil + end end end diff --git a/spec/unit/mutant/matcher/class_methods/from_string_spec.rb b/spec/unit/mutant/matcher/class_methods/from_string_spec.rb new file mode 100644 index 00000000..04483be3 --- /dev/null +++ b/spec/unit/mutant/matcher/class_methods/from_string_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper' + +describe Mutant::Matcher, '.from_string' do + subject { object.from_string(input) } + + let(:input) { mock('Input') } + let(:matcher) { mock('Matcher') } + + let(:descendant_a) { mock('Descendant A', :parse => nil) } + let(:descendant_b) { mock('Descendant B', :parse => nil) } + + let(:object) { described_class } + + before do + described_class.stub(:descendants => [descendant_a, descendant_b]) + end + + context 'when no descendant takes the input' do + it { should be(nil) } + + it_should_behave_like 'an idempotent method' + end + + context 'when one descendant handles input' do + before do + descendant_a.stub(:parse => matcher) + end + + it { should be(matcher) } + + it_should_behave_like 'an idempotent method' + end + + pending 'when more than one descendant handles input' do + let(:matcher_b) { mock('Matcher B') } + + before do + descendant_a.stub(:parse => matcher) + descendant_b.stub(:parse => matcher_b) + end + + it 'should return the first matcher' do + should be(matcher) + end + + it_should_behave_like 'an idempotent method' + end +end + diff --git a/spec/unit/mutant/matcher/class_methods/parse_spec.rb b/spec/unit/mutant/matcher/class_methods/parse_spec.rb new file mode 100644 index 00000000..1f2971d7 --- /dev/null +++ b/spec/unit/mutant/matcher/class_methods/parse_spec.rb @@ -0,0 +1,12 @@ +require 'spec_helper' + +describe Mutant::Matcher, '.parse' do + subject { object.parse(input) } + + let(:input) { mock('Input') } + let(:object) { described_class } + + it { should be(nil) } + + it_should_behave_like 'an idempotent method' +end diff --git a/spec/unit/mutant/matcher/method/classifier/class_methods/run_spec.rb b/spec/unit/mutant/matcher/method/classifier/class_methods/run_spec.rb index 4d156588..768ebf13 100644 --- a/spec/unit/mutant/matcher/method/classifier/class_methods/run_spec.rb +++ b/spec/unit/mutant/matcher/method/classifier/class_methods/run_spec.rb @@ -21,8 +21,8 @@ describe Mutant::Matcher::Method::Classifier, '.run' do context 'with invalid notation' do let(:input) { 'Foo' } - it 'should raise error' do - expect { subject }.to raise_error(ArgumentError, "Cannot determine subject from #{input.inspect}") + it 'should return nil' do + should be(nil) end end end