Progress on method matching
* Adjust metrics * Add initial integration spec on method matching * Yard and Heckle coverage is at 100% (heckle cov is disputable) * Rcov does not really make sense as MRI 1.8 cannot reach all code paths.
This commit is contained in:
		
							parent
							
								
									d74481b8fb
								
							
						
					
					
						commit
						dc893bfd7d
					
				
					 21 changed files with 446 additions and 105 deletions
				
			
		
							
								
								
									
										2
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,2 +1,4 @@
 | 
			
		|||
/.rbx
 | 
			
		||||
/Gemfile.lock
 | 
			
		||||
/tmp
 | 
			
		||||
/coverage
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,3 @@
 | 
			
		|||
---
 | 
			
		||||
threshold: 9
 | 
			
		||||
total_score: 41
 | 
			
		||||
threshold: 8
 | 
			
		||||
total_score: 50
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,2 +1,2 @@
 | 
			
		|||
---
 | 
			
		||||
threshold: 12.4
 | 
			
		||||
threshold: 13.7
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ ClassVariableCheck:              {}
 | 
			
		|||
CyclomaticComplexityBlockCheck:
 | 
			
		||||
  complexity: 2
 | 
			
		||||
CyclomaticComplexityMethodCheck:
 | 
			
		||||
  complexity: 2
 | 
			
		||||
  complexity: 3
 | 
			
		||||
EmptyRescueBodyCheck:            {}
 | 
			
		||||
ForLoopCheck:                    {}
 | 
			
		||||
MethodLineCountCheck:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,10 +8,10 @@ UncommunicativeParameterName:
 | 
			
		|||
  - !ruby/regexp /[0-9]$/
 | 
			
		||||
  - !ruby/regexp /[A-Z]/
 | 
			
		||||
LargeClass:
 | 
			
		||||
  max_methods: 10
 | 
			
		||||
  max_methods: 11
 | 
			
		||||
  exclude: []
 | 
			
		||||
  enabled: true
 | 
			
		||||
  max_instance_variables: 3
 | 
			
		||||
  max_instance_variables: 2
 | 
			
		||||
UncommunicativeMethodName:
 | 
			
		||||
  accept: []
 | 
			
		||||
  exclude: []
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,11 +23,30 @@ module Mutant
 | 
			
		|||
  # @return [undefined]
 | 
			
		||||
  #
 | 
			
		||||
  # @api private
 | 
			
		||||
  #
 | 
			
		||||
  def self.not_implemented(object)
 | 
			
		||||
    method = caller(1).first[/`(.*)'/,1].to_sym
 | 
			
		||||
    delimiter = object.kind_of?(Module) ? '.' : '#'
 | 
			
		||||
    raise NotImplementedError,"#{object.class}#{delimiter}#{method} is not implemented"
 | 
			
		||||
    constant_name,delimiter = not_implemented_info(object)
 | 
			
		||||
    raise NotImplementedError,"#{constant_name}#{delimiter}#{method} is not implemented"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Return name and delimiter
 | 
			
		||||
  #
 | 
			
		||||
  # @param [Object] object
 | 
			
		||||
  #
 | 
			
		||||
  # @return [Array]
 | 
			
		||||
  #
 | 
			
		||||
  # @api private
 | 
			
		||||
  #
 | 
			
		||||
  def self.not_implemented_info(object)
 | 
			
		||||
    if object.kind_of?(Module)
 | 
			
		||||
      [object.name,'.']
 | 
			
		||||
    else
 | 
			
		||||
      [object.class.name,'#']
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private_class_method :not_implemented_info
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
require 'mutant/matcher'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,8 @@ module Mutant
 | 
			
		|||
    #
 | 
			
		||||
    # @api private
 | 
			
		||||
    #
 | 
			
		||||
    # @return [undefined]
 | 
			
		||||
    #
 | 
			
		||||
    def each
 | 
			
		||||
      Mutant.not_implemented(self)
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,35 +2,6 @@ module Mutant
 | 
			
		|||
  class Matcher
 | 
			
		||||
    # A filter for methods
 | 
			
		||||
    class Method < Matcher
 | 
			
		||||
      # Return constant name 
 | 
			
		||||
      #
 | 
			
		||||
      # @return [String]
 | 
			
		||||
      #
 | 
			
		||||
      # @api private
 | 
			
		||||
      #
 | 
			
		||||
      attr_reader :constant_name
 | 
			
		||||
 | 
			
		||||
      # Return method name
 | 
			
		||||
      #
 | 
			
		||||
      # @return [String]
 | 
			
		||||
      #
 | 
			
		||||
      # @api private
 | 
			
		||||
      #
 | 
			
		||||
      attr_reader :method_name
 | 
			
		||||
 | 
			
		||||
      # Initialize method filter
 | 
			
		||||
      # 
 | 
			
		||||
      # @param [String] constant_name
 | 
			
		||||
      # @param [String] method_name
 | 
			
		||||
      #
 | 
			
		||||
      # @return [undefined]
 | 
			
		||||
      #
 | 
			
		||||
      # @api private
 | 
			
		||||
      #
 | 
			
		||||
      def initialize(constant_name, method_name)
 | 
			
		||||
        @constant_name, @method_name = constant_name, method_name
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Parse a method string into filter
 | 
			
		||||
      #
 | 
			
		||||
      # @param [String] input
 | 
			
		||||
| 
						 | 
				
			
			@ -53,15 +24,69 @@ module Mutant
 | 
			
		|||
      #
 | 
			
		||||
      # @api private
 | 
			
		||||
      #   
 | 
			
		||||
      def each
 | 
			
		||||
      def each(&block)
 | 
			
		||||
        return to_enum(__method__) unless block_given?
 | 
			
		||||
        yield root_node
 | 
			
		||||
        node = root_node
 | 
			
		||||
        yield node if node
 | 
			
		||||
        self
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
      # Return constant name 
 | 
			
		||||
      #
 | 
			
		||||
      # @return [String]
 | 
			
		||||
      #
 | 
			
		||||
      # @api private
 | 
			
		||||
      #
 | 
			
		||||
      attr_reader :constant_name
 | 
			
		||||
      private :constant_name
 | 
			
		||||
 | 
			
		||||
      # Return method name
 | 
			
		||||
      #
 | 
			
		||||
      # @return [String]
 | 
			
		||||
      #
 | 
			
		||||
      # @api private
 | 
			
		||||
      #
 | 
			
		||||
      attr_reader :method_name
 | 
			
		||||
      private :method_name
 | 
			
		||||
 | 
			
		||||
      # Initialize method filter
 | 
			
		||||
      # 
 | 
			
		||||
      # @param [String] constant_name
 | 
			
		||||
      # @param [Symbol] method_name
 | 
			
		||||
      #
 | 
			
		||||
      # @return [undefined]
 | 
			
		||||
      #
 | 
			
		||||
      # @api private
 | 
			
		||||
      #
 | 
			
		||||
      def initialize(constant_name, method_name)
 | 
			
		||||
        @constant_name, @method_name = constant_name, method_name
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Return method
 | 
			
		||||
      # 
 | 
			
		||||
      # @return [UnboundMethod]
 | 
			
		||||
      #
 | 
			
		||||
      # @api private
 | 
			
		||||
      #
 | 
			
		||||
      def method
 | 
			
		||||
        Mutant.not_implemented(self)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Return node classes this matcher matches
 | 
			
		||||
      #
 | 
			
		||||
      # @return [Rubinius::AST::Node]
 | 
			
		||||
      #
 | 
			
		||||
      # @api private
 | 
			
		||||
      #
 | 
			
		||||
      def node_class
 | 
			
		||||
        Mutant.not_implemented(self)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Check if node is matched 
 | 
			
		||||
      #
 | 
			
		||||
      # @param [Rubinius::AST::Node]
 | 
			
		||||
      # @param [Rubinius::AST::Node] node
 | 
			
		||||
      #
 | 
			
		||||
      # @return [true]
 | 
			
		||||
      #   returns true if node matches method
 | 
			
		||||
| 
						 | 
				
			
			@ -72,44 +97,9 @@ module Mutant
 | 
			
		|||
      # @api private
 | 
			
		||||
      #
 | 
			
		||||
      def match?(node)
 | 
			
		||||
        node.line == source_file_line && node_class == node.class && node.name.to_s == method_name
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
      # Return method
 | 
			
		||||
      # 
 | 
			
		||||
      # @return [UnboundMethod]
 | 
			
		||||
      #
 | 
			
		||||
      # @api private
 | 
			
		||||
      #
 | 
			
		||||
      def method
 | 
			
		||||
        Mutant.not_implemente(self)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Return node classes this matcher matches
 | 
			
		||||
      #
 | 
			
		||||
      # @return [Enumerable]
 | 
			
		||||
      #
 | 
			
		||||
      # @api private
 | 
			
		||||
      #
 | 
			
		||||
      def node_classes
 | 
			
		||||
        Mutant.not_implemented(self)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Return root node
 | 
			
		||||
      #
 | 
			
		||||
      # @return [Rubinus::AST::Node]
 | 
			
		||||
      #
 | 
			
		||||
      # @api private
 | 
			
		||||
      #
 | 
			
		||||
      def root_node
 | 
			
		||||
        root_node = nil
 | 
			
		||||
        ast.walk do |_, node|
 | 
			
		||||
          root_node = node if match?(node)
 | 
			
		||||
          true
 | 
			
		||||
        end
 | 
			
		||||
        root_node
 | 
			
		||||
        node.line  == source_file_line && 
 | 
			
		||||
        node.class == node_class && 
 | 
			
		||||
        node.name  == method_name
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Return full ast
 | 
			
		||||
| 
						 | 
				
			
			@ -152,6 +142,21 @@ module Mutant
 | 
			
		|||
        method.source_location
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Return root node
 | 
			
		||||
      #
 | 
			
		||||
      # @return [Rubinus::AST]
 | 
			
		||||
      #
 | 
			
		||||
      # @api private
 | 
			
		||||
      #
 | 
			
		||||
      def root_node
 | 
			
		||||
        root_node = nil
 | 
			
		||||
        ast.walk do |predicate, node|
 | 
			
		||||
          root_node = node if match?(node)
 | 
			
		||||
          true
 | 
			
		||||
        end
 | 
			
		||||
        root_node
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Return constant
 | 
			
		||||
      #
 | 
			
		||||
      # @return [Class|Module]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,8 @@ module Mutant
 | 
			
		|||
    class Method < Matcher
 | 
			
		||||
      # A classifier for input strings
 | 
			
		||||
      class Classifier
 | 
			
		||||
        extend Veritas::Immutable
 | 
			
		||||
 | 
			
		||||
        TABLE = {
 | 
			
		||||
          '.' => Matcher::Method::Singleton,
 | 
			
		||||
          '#' => Matcher::Method::Instance
 | 
			
		||||
| 
						 | 
				
			
			@ -12,35 +14,81 @@ module Mutant
 | 
			
		|||
 | 
			
		||||
        private_class_method :new
 | 
			
		||||
 | 
			
		||||
        # Run classifier
 | 
			
		||||
        #
 | 
			
		||||
        # @param [String] input
 | 
			
		||||
        #
 | 
			
		||||
        # @return [Matcher::Method]
 | 
			
		||||
        #
 | 
			
		||||
        # @api private
 | 
			
		||||
        #
 | 
			
		||||
        def self.run(input)
 | 
			
		||||
          match = SCOPE_FORMAT.match(input)
 | 
			
		||||
          raise ArgumentError, "Cannot determine subject from #{input.inspect}" unless match
 | 
			
		||||
          new(match).matcher
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      public
 | 
			
		||||
 | 
			
		||||
        # Return method matcher
 | 
			
		||||
        #
 | 
			
		||||
        # @return [Matcher::Method]
 | 
			
		||||
        #
 | 
			
		||||
        # @api private
 | 
			
		||||
        #
 | 
			
		||||
        def matcher
 | 
			
		||||
          scope.new(constant_name, method_name)
 | 
			
		||||
          matcher_class.new(constant_name, method_name)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
        # Initialize matcher
 | 
			
		||||
        #
 | 
			
		||||
        # @param [MatchData] match
 | 
			
		||||
        #
 | 
			
		||||
        # @api private
 | 
			
		||||
        #
 | 
			
		||||
        def initialize(match)
 | 
			
		||||
          @match = match
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        # Return constant name
 | 
			
		||||
        #
 | 
			
		||||
        # @return [String]
 | 
			
		||||
        #
 | 
			
		||||
        # @api private
 | 
			
		||||
        #
 | 
			
		||||
        def constant_name
 | 
			
		||||
          @match[1]
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        # Return method name
 | 
			
		||||
        #
 | 
			
		||||
        # @return [String]
 | 
			
		||||
        #
 | 
			
		||||
        # @api private
 | 
			
		||||
        #
 | 
			
		||||
        def method_name
 | 
			
		||||
          @match[3]
 | 
			
		||||
          @match[3].to_sym
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        # Return scope symbol
 | 
			
		||||
        #
 | 
			
		||||
        # @return [Symbol]
 | 
			
		||||
        #
 | 
			
		||||
        # @api private
 | 
			
		||||
        #
 | 
			
		||||
        def scope_symbol
 | 
			
		||||
          @match[2]
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        def scope
 | 
			
		||||
        # Return matcher class
 | 
			
		||||
        #
 | 
			
		||||
        # @return [Class<Matcher>]
 | 
			
		||||
        #
 | 
			
		||||
        # @api private
 | 
			
		||||
        #
 | 
			
		||||
        def matcher_class
 | 
			
		||||
          TABLE.fetch(scope_symbol)
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,10 +4,22 @@ module Mutant
 | 
			
		|||
      # A instance method filter
 | 
			
		||||
      class Instance < Method
 | 
			
		||||
      private
 | 
			
		||||
        # Return method instance
 | 
			
		||||
        # 
 | 
			
		||||
        # @return [UnboundMethod]
 | 
			
		||||
        #
 | 
			
		||||
        # @api private
 | 
			
		||||
        #
 | 
			
		||||
        def method
 | 
			
		||||
          constant.instance_method(method_name)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        # Return matched node class 
 | 
			
		||||
        # 
 | 
			
		||||
        # @return [Rubinius::AST::Define]
 | 
			
		||||
        #
 | 
			
		||||
        # @api private
 | 
			
		||||
        #
 | 
			
		||||
        def node_class
 | 
			
		||||
          Rubinius::AST::Define
 | 
			
		||||
        end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,12 +4,24 @@ module Mutant
 | 
			
		|||
      # A singleton method filter
 | 
			
		||||
      class Singleton < Method
 | 
			
		||||
      private
 | 
			
		||||
        # Return method instance
 | 
			
		||||
        # 
 | 
			
		||||
        # @return [UnboundMethod]
 | 
			
		||||
        #
 | 
			
		||||
        # @api private
 | 
			
		||||
        #
 | 
			
		||||
        def method
 | 
			
		||||
          constant.method(method_name)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        # Return matched node class 
 | 
			
		||||
        # 
 | 
			
		||||
        # @return [Rubinius::AST::Define]
 | 
			
		||||
        #
 | 
			
		||||
        # @api private
 | 
			
		||||
        #
 | 
			
		||||
        def node_class
 | 
			
		||||
          Rubinius::AST::DefineSingleton
 | 
			
		||||
          Rubinius::AST::DefineSingletonScope
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										82
									
								
								spec/integration/method_matching_spec.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								spec/integration/method_matching_spec.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,82 @@
 | 
			
		|||
require 'spec_helper'
 | 
			
		||||
if defined?(Rubinius)
 | 
			
		||||
  class Toplevel
 | 
			
		||||
    def simple
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def self.simple
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def multiple; end; 
 | 
			
		||||
    def multiple(foo); end
 | 
			
		||||
    
 | 
			
		||||
    def self.complex; end; def complex(foo); end
 | 
			
		||||
 | 
			
		||||
    class Nested
 | 
			
		||||
      def foo
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    attr_reader :foo
 | 
			
		||||
 | 
			
		||||
    def multiline(
 | 
			
		||||
      foo
 | 
			
		||||
    )
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe Mutant,'method matching' do
 | 
			
		||||
    def match(input)
 | 
			
		||||
      Mutant::Matcher::Method.parse(input).to_a.first
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'allows to match simple instance methods' do
 | 
			
		||||
      match = match('Toplevel#simple')
 | 
			
		||||
      match.name.should be(:simple)
 | 
			
		||||
      match.line.should be(4)
 | 
			
		||||
      match.arguments.required.should be_empty
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'allows to match simple singleton methods' do
 | 
			
		||||
      match = match('Toplevel.simple')
 | 
			
		||||
      match.name.should be(:simple)
 | 
			
		||||
      match.line.should be(7)
 | 
			
		||||
      match.arguments.required.should be_empty
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'returns last method definition' do
 | 
			
		||||
      match = match('Toplevel#multiple')
 | 
			
		||||
      match.name.should be(:multiple)
 | 
			
		||||
      match.line.should be(11)
 | 
			
		||||
      match.arguments.required.length.should be(1)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'does not fail on multiple definitions of differend scope per row' do
 | 
			
		||||
      match = match('Toplevel.complex')
 | 
			
		||||
      match.name.should be(:complex)
 | 
			
		||||
      match.line.should be(13)
 | 
			
		||||
      match.arguments.required.length.should be(0)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'allows matching on nested methods' do
 | 
			
		||||
      match = match('Toplevel::Nested#foo')
 | 
			
		||||
      match.name.should be(:foo)
 | 
			
		||||
      match.line.should be(16)
 | 
			
		||||
      match.arguments.required.length.should be(0)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
  # pending 'allows matching on attr_readers' do
 | 
			
		||||
  #   match = match('Toplevel#foo')
 | 
			
		||||
  #   match.name.should be(:foo)
 | 
			
		||||
  #   match.line.should be(19)
 | 
			
		||||
  #   match.arguments.required.length.should be(0)
 | 
			
		||||
  # end
 | 
			
		||||
 | 
			
		||||
    it 'does not fail on multi line defs' do
 | 
			
		||||
      match = match('Toplevel#multiline')
 | 
			
		||||
      match.name.should be(:multiline)
 | 
			
		||||
      match.line.should be(23)
 | 
			
		||||
      match.arguments.required.length.should be(1)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										35
									
								
								spec/unit/mutant/class_methods/not_implemented_spec.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								spec/unit/mutant/class_methods/not_implemented_spec.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,35 @@
 | 
			
		|||
require 'spec_helper'
 | 
			
		||||
 | 
			
		||||
describe Mutant,'.not_implemented' do
 | 
			
		||||
  let(:object) { described_class.new }
 | 
			
		||||
 | 
			
		||||
  let(:described_class) do
 | 
			
		||||
    Class.new do
 | 
			
		||||
      def foo
 | 
			
		||||
        Mutant.not_implemented(self)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def self.foo
 | 
			
		||||
        Mutant.not_implemented(self)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def self.name
 | 
			
		||||
        'Test'
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  context 'on instance method' do
 | 
			
		||||
    subject { object.foo }
 | 
			
		||||
    it 'should raise error' do
 | 
			
		||||
      expect { subject }.to raise_error(NotImplementedError,'Test#foo is not implemented')
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  context 'on singleton method' do
 | 
			
		||||
    subject { described_class.foo }
 | 
			
		||||
    it 'should raise error' do
 | 
			
		||||
      expect { subject }.to raise_error(NotImplementedError,'Test.foo is not implemented')
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,34 +1,21 @@
 | 
			
		|||
require 'spec_helper'
 | 
			
		||||
 | 
			
		||||
shared_examples_for 'a method filter parse result' do
 | 
			
		||||
  it { should be(response) }
 | 
			
		||||
 | 
			
		||||
  it 'should initialize method filter with correct arguments' do
 | 
			
		||||
    expected_class.should_receive(:new).with('Foo', 'bar').and_return(response)
 | 
			
		||||
    subject
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
describe Mutant::Matcher::Method, '.parse' do
 | 
			
		||||
  subject { described_class.parse(input) }
 | 
			
		||||
 | 
			
		||||
  before do
 | 
			
		||||
    expected_class.stub(:new => response)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  let(:response) { mock('Response') }
 | 
			
		||||
  let(:input)    { mock('Input')    }
 | 
			
		||||
 | 
			
		||||
  context 'when input is in instance method format' do
 | 
			
		||||
    let(:input)          { 'Foo#bar' }
 | 
			
		||||
    let(:expected_class) { described_class::Instance }
 | 
			
		||||
  let(:classifier) { described_class::Classifier }
 | 
			
		||||
 | 
			
		||||
    it_should_behave_like 'a method filter parse result'
 | 
			
		||||
  before do
 | 
			
		||||
    classifier.stub(:run => response)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  context 'when input is in singleton method format' do
 | 
			
		||||
    let(:input)          { 'Foo.bar' }
 | 
			
		||||
    let(:expected_class) { described_class::Singleton }
 | 
			
		||||
  it { should be(response) }
 | 
			
		||||
 | 
			
		||||
    it_should_behave_like 'a method filter parse result'
 | 
			
		||||
  it 'should call classifier' do
 | 
			
		||||
    classifier.should_receive(:run).with(input).and_return(response)
 | 
			
		||||
    subject
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,44 @@
 | 
			
		|||
require 'spec_helper'
 | 
			
		||||
 | 
			
		||||
shared_examples_for 'a method filter parse result' do
 | 
			
		||||
  it { should be(response) }
 | 
			
		||||
 | 
			
		||||
  it 'should initialize method filter with correct arguments' do
 | 
			
		||||
    expected_class.should_receive(:new).with('Foo', :bar).and_return(response)
 | 
			
		||||
    subject
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
describe Mutant::Matcher::Method::Classifier, '.run' do
 | 
			
		||||
  subject { described_class.run(input) }
 | 
			
		||||
 | 
			
		||||
  context 'with format' do
 | 
			
		||||
    before do
 | 
			
		||||
      expected_class.stub(:new => response)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    let(:response) { mock('Response') }
 | 
			
		||||
 | 
			
		||||
    context 'in instance method notation' do
 | 
			
		||||
      let(:input)          { 'Foo#bar' }
 | 
			
		||||
      let(:expected_class) { Mutant::Matcher::Method::Instance }
 | 
			
		||||
 | 
			
		||||
      it_should_behave_like 'a method filter parse result'
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    context 'when input is in singleton method notation' do
 | 
			
		||||
      let(:input)          { 'Foo.bar' }
 | 
			
		||||
      let(:expected_class) { Mutant::Matcher::Method::Singleton }
 | 
			
		||||
 | 
			
		||||
      it_should_behave_like 'a method filter parse result'
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  context 'when input is not in a valid format' do
 | 
			
		||||
    let(:input) { 'Foo' }
 | 
			
		||||
 | 
			
		||||
    it 'should raise error' do
 | 
			
		||||
      expect { subject }.to raise_error(ArgumentError,"Cannot determine subject from #{input.inspect}")
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										29
									
								
								spec/unit/mutant/matcher/method/classifier/matcher_spec.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								spec/unit/mutant/matcher/method/classifier/matcher_spec.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,29 @@
 | 
			
		|||
require 'spec_helper'
 | 
			
		||||
 | 
			
		||||
# This method cannot be called directly, spec only exists for heckle demands
 | 
			
		||||
describe Mutant::Matcher::Method::Classifier,'#matcher' do
 | 
			
		||||
  subject { object.matcher }
 | 
			
		||||
 | 
			
		||||
  let(:object) { described_class.send(:new,match) }
 | 
			
		||||
 | 
			
		||||
  let(:match) { [mock,constant_name,scope_symbol,method_name] }
 | 
			
		||||
 | 
			
		||||
  let(:constant_name) { mock('Constant Name') }
 | 
			
		||||
  let(:method_name)   { 'foo'                  }
 | 
			
		||||
 | 
			
		||||
  context 'with "#" as scope symbol' do
 | 
			
		||||
    let(:scope_symbol) { '#' }
 | 
			
		||||
 | 
			
		||||
    it { should be_a(Mutant::Matcher::Method::Instance) }
 | 
			
		||||
    its(:method_name)   { should be(method_name.to_sym) }
 | 
			
		||||
    its(:constant_name) { should be(constant_name)      }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  context 'with "." as scope symbol' do
 | 
			
		||||
    let(:scope_symbol) { '.' }
 | 
			
		||||
 | 
			
		||||
    it { should be_a(Mutant::Matcher::Method::Singleton) }
 | 
			
		||||
    its(:method_name)   { should be(method_name.to_sym)  }
 | 
			
		||||
    its(:constant_name) { should be(constant_name)       }
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										39
									
								
								spec/unit/mutant/matcher/method/each_spec.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								spec/unit/mutant/matcher/method/each_spec.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,39 @@
 | 
			
		|||
require 'spec_helper'
 | 
			
		||||
 | 
			
		||||
# This method implementation cannot be called from the outside, but heckle needs to be happy.
 | 
			
		||||
 | 
			
		||||
describe Mutant::Matcher::Method,'#each' do
 | 
			
		||||
  let(:class_under_test) do
 | 
			
		||||
    node = self.root_node
 | 
			
		||||
    Class.new(described_class) do
 | 
			
		||||
      define_method(:root_node) do
 | 
			
		||||
        node
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  subject { object.each { |item| yields << item }  }
 | 
			
		||||
 | 
			
		||||
  let(:object) { class_under_test.allocate }
 | 
			
		||||
  let(:yields) { [] }
 | 
			
		||||
 | 
			
		||||
  it_should_behave_like 'an #each method'
 | 
			
		||||
 | 
			
		||||
  let(:root_node) { mock('Root Node') }
 | 
			
		||||
 | 
			
		||||
  context 'with match' do
 | 
			
		||||
    it 'should yield root node' do
 | 
			
		||||
      expect { subject }.to change { yields.dup }.from([]).to([root_node])
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  context 'without match' do
 | 
			
		||||
    let(:root_node) { nil }
 | 
			
		||||
 | 
			
		||||
    it 'should yield nothing' do
 | 
			
		||||
      subject
 | 
			
		||||
      yields.should eql([])
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										11
									
								
								spec/unit/mutant/matcher/method/method_spec.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								spec/unit/mutant/matcher/method/method_spec.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
require 'spec_helper'
 | 
			
		||||
 | 
			
		||||
describe Mutant::Matcher::Method,'#method' do
 | 
			
		||||
  subject { object.send(:method) }
 | 
			
		||||
 | 
			
		||||
  let(:object) { described_class.allocate }
 | 
			
		||||
 | 
			
		||||
  it 'should raise error' do
 | 
			
		||||
    expect { subject }.to raise_error(NotImplementedError,'Mutant::Matcher::Method#method is not implemented')
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										12
									
								
								spec/unit/mutant/matcher/method/node_class_spec.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								spec/unit/mutant/matcher/method/node_class_spec.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
require 'spec_helper'
 | 
			
		||||
 | 
			
		||||
describe Mutant::Matcher::Method,'#node_class' do
 | 
			
		||||
  subject { object.send(:node_class) }
 | 
			
		||||
 | 
			
		||||
  let(:object) { described_class.allocate }
 | 
			
		||||
 | 
			
		||||
  it 'should raise error' do
 | 
			
		||||
    expect { subject }.to raise_error(NotImplementedError,'Mutant::Matcher::Method#node_class is not implemented')
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -29,12 +29,12 @@ begin
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  desc 'Heckle each module and class'
 | 
			
		||||
  task :heckle => :rcov do
 | 
			
		||||
  task :heckle do
 | 
			
		||||
    unless Ruby2Ruby::VERSION == '1.2.2'
 | 
			
		||||
      raise "ruby2ruby version #{Ruby2Ruby::VERSION} may not work properly, 1.2.2 *only* is recommended for use with heckle"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    require 'veritas-mongo-adapter'
 | 
			
		||||
    require 'mutant'
 | 
			
		||||
 | 
			
		||||
    root_module_regexp = Regexp.union('Mutant')
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,6 @@
 | 
			
		|||
begin
 | 
			
		||||
  # Require veritas before metric foo pulls AS
 | 
			
		||||
  require 'veritas'
 | 
			
		||||
  require 'metric_fu'
 | 
			
		||||
  require 'json'
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue