diff --git a/lib/mutant/matcher/methods.rb b/lib/mutant/matcher/methods.rb index a06fa79e..6b0edc4a 100644 --- a/lib/mutant/matcher/methods.rb +++ b/lib/mutant/matcher/methods.rb @@ -2,27 +2,7 @@ module Mutant class Matcher # Abstract base class for matcher that returns method subjects extracted from scope class Methods < self - include AbstractType, Equalizer.new(:scope) - - # Return scope - # - # @return [Class, Model] - # - # @api private - # - attr_reader :scope - - # Initialize object - # - # @param [Class,Module] scope - # - # @return [undefined] - # - # @api private - # - def initialize(scope) - @scope = scope - end + include AbstractType, Concord.new(:scope) # Enumerate subjects # @@ -44,6 +24,8 @@ module Mutant self end + private + # Return method matcher class # # @return [Class:Matcher::Method] @@ -54,35 +36,6 @@ module Mutant self.class::MATCHER end - # Return methods - # - # @return [Enumerable] - # - # @api private - # - def methods - method_names.map do |name| - access(name) - end - end - memoize :methods - - private - - # Return method names - # - # @param [Object] object - # - # @return [Enumerable] - # - # @api private - # - def self.method_names(object) - object.public_instance_methods(false) + - object.private_instance_methods(false) + - object.protected_instance_methods(false) - end - # Emit matches for method # # @param [UnboundMethod, Method] method @@ -97,13 +50,36 @@ module Mutant end end - # Return method names + # Return methods + # + # @return [Enumerable] + # + # @api private + # + def methods + candidates.each_with_object([]) do |name, methods| + method = access(name) + methods << method if method.owner == scope + end + end + memoize :methods + + # Return candidate names + # + # @param [Object] object # # @return [Enumerable] # # @api private # - abstract_method :method_names + def candidates + object = self.scope + names = + object.public_instance_methods(false) + + object.private_instance_methods(false) + + object.protected_instance_methods(false) + names.sort + end class Singleton < self MATCHER = Matcher::Method::Singleton @@ -132,9 +108,7 @@ module Mutant # def method_names singleton_class = scope.singleton_class - names = self.class.method_names(singleton_class) - - names.sort.reject do |name| + candidate_names.sort.reject do |name| name.to_sym == :__class_init__ end end @@ -168,8 +142,7 @@ module Mutant def method_names scope = self.scope return [] unless scope.kind_of?(Module) - names = self.class.method_names(scope) - names.uniq.sort + candidate_names.sort end end end diff --git a/spec/unit/mutant/matcher/methods/instance/each_spec.rb b/spec/unit/mutant/matcher/methods/instance/each_spec.rb new file mode 100644 index 00000000..8a18fe66 --- /dev/null +++ b/spec/unit/mutant/matcher/methods/instance/each_spec.rb @@ -0,0 +1,59 @@ +require 'spec_helper' + +describe Mutant::Matcher::Methods::Instance, '#each' do + let(:object) { described_class.new(Foo) } + + subject { object.each { |matcher| yields << matcher } } + + let(:yields) { [] } + + module Bar + def method_d + end + + def method_e + end + end + + class Foo + include Bar + + private :method_d + + public + + def method_a + end + + protected + + def method_b + end + + private + + def method_c + end + + end + + let(:subject_a) { mock('Subject A') } + let(:subject_b) { mock('Subject B') } + let(:subject_c) { mock('Subject C') } + + let(:subjects) { [subject_a, subject_b, subject_c] } + + before do + matcher = Mutant::Matcher::Method::Instance + matcher.stub(:new).with(Foo, Foo.instance_method(:method_a)).and_return([subject_a]) + matcher.stub(:new).with(Foo, Foo.instance_method(:method_b)).and_return([subject_b]) + matcher.stub(:new).with(Foo, Foo.instance_method(:method_c)).and_return([subject_c]) + end + + it 'should yield expected subjects' do + subject + yields.should eql(subjects) + end + + it_should_behave_like 'an #each method' +end