mutant 0.8.7 → 0.8.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/Changelog.md +5 -0
 - data/README.md +64 -3
 - data/config/flay.yml +1 -1
 - data/lib/mutant.rb +2 -0
 - data/lib/mutant/cli.rb +1 -1
 - data/lib/mutant/env/bootstrap.rb +36 -8
 - data/lib/mutant/expression/method.rb +3 -5
 - data/lib/mutant/expression/methods.rb +2 -4
 - data/lib/mutant/expression/namespace.rb +4 -8
 - data/lib/mutant/matcher.rb +3 -18
 - data/lib/mutant/matcher/chain.rb +7 -13
 - data/lib/mutant/matcher/compiler.rb +2 -13
 - data/lib/mutant/matcher/filter.rb +6 -19
 - data/lib/mutant/matcher/method.rb +124 -104
 - data/lib/mutant/matcher/method/instance.rb +40 -34
 - data/lib/mutant/matcher/method/singleton.rb +80 -61
 - data/lib/mutant/matcher/methods.rb +19 -29
 - data/lib/mutant/matcher/namespace.rb +22 -16
 - data/lib/mutant/matcher/null.rb +4 -7
 - data/lib/mutant/matcher/scope.rb +23 -13
 - data/lib/mutant/matcher/static.rb +17 -0
 - data/lib/mutant/mutation.rb +0 -5
 - data/lib/mutant/reporter/cli/format.rb +2 -3
 - data/lib/mutant/reporter/cli/printer/env_progress.rb +37 -11
 - data/lib/mutant/reporter/cli/printer/status_progressive.rb +1 -1
 - data/lib/mutant/scope.rb +6 -0
 - data/lib/mutant/subject/method.rb +0 -7
 - data/lib/mutant/subject/method/instance.rb +0 -10
 - data/lib/mutant/subject/method/singleton.rb +0 -10
 - data/lib/mutant/version.rb +1 -1
 - data/lib/mutant/zombifier.rb +2 -1
 - data/mutant-rspec.gemspec +1 -1
 - data/spec/integration/mutant/rspec_spec.rb +1 -1
 - data/spec/shared/method_matcher_behavior.rb +21 -14
 - data/spec/spec_helper.rb +6 -0
 - data/spec/unit/mutant/env/boostrap_spec.rb +88 -26
 - data/spec/unit/mutant/env_spec.rb +0 -1
 - data/spec/unit/mutant/expression/method_spec.rb +3 -3
 - data/spec/unit/mutant/expression/methods_spec.rb +3 -4
 - data/spec/unit/mutant/expression/namespace/flat_spec.rb +2 -3
 - data/spec/unit/mutant/expression/namespace/recursive_spec.rb +2 -4
 - data/spec/unit/mutant/matcher/chain_spec.rb +21 -29
 - data/spec/unit/mutant/matcher/compiler/subject_prefix_spec.rb +16 -13
 - data/spec/unit/mutant/matcher/compiler_spec.rb +49 -60
 - data/spec/unit/mutant/matcher/filter_spec.rb +15 -31
 - data/spec/unit/mutant/matcher/method/instance_spec.rb +84 -128
 - data/spec/unit/mutant/matcher/method/singleton_spec.rb +48 -52
 - data/spec/unit/mutant/matcher/methods/instance_spec.rb +21 -24
 - data/spec/unit/mutant/matcher/methods/singleton_spec.rb +18 -21
 - data/spec/unit/mutant/matcher/namespace_spec.rb +30 -38
 - data/spec/unit/mutant/matcher/null_spec.rb +5 -20
 - data/spec/unit/mutant/matcher/scope_spec.rb +33 -0
 - data/spec/unit/mutant/matcher/static_spec.rb +11 -0
 - data/spec/unit/mutant/mutation_spec.rb +30 -10
 - data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +6 -0
 - data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +2 -0
 - data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +10 -0
 - data/spec/unit/mutant/reporter/cli_spec.rb +4 -0
 - data/spec/unit/mutant/subject/method/instance_spec.rb +0 -28
 - data/spec/unit/mutant/subject/method/singleton_spec.rb +0 -28
 - data/test_app/Gemfile.rspec3.4 +7 -0
 - data/test_app/lib/test_app.rb +16 -12
 - data/test_app/lib/test_app/literal.rb +3 -0
 - metadata +9 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: d83617d43f73b49c391d1b7e8f3317a666297c83
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 186b8ce58089718ba3cafa1c08f609b89941541e
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 3d4ee1e94a96ba909cf327bde6afdca8ff5e50f80603ca8835115fdba2abbfa05ad89897366908f8b64bca2e9302605e7accddf1167260c187cf4e40417d0df5
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 7b599e22fa7ddd03e9f9ac91af9ce0e730b155c8df2b5ab1b5a67fc8cd62f8bf8972ca8df64b45fb5114a556e7416f3c86baf666ea62f5de5201e8b068406afc
         
     | 
    
        data/Changelog.md
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | 
         @@ -73,6 +73,54 @@ To mutation test Rails models with rspec comment out ```require 'rspec/autorun'` 
     | 
|
| 
       73 
73 
     | 
    
         
             
            RAILS_ENV=test bundle exec mutant -r ./config/environment --use rspec User
         
     | 
| 
       74 
74 
     | 
    
         
             
            ```
         
     | 
| 
       75 
75 
     | 
    
         | 
| 
      
 76 
     | 
    
         
            +
            Limitations
         
     | 
| 
      
 77 
     | 
    
         
            +
            -----------
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
            Mutant cannot emit mutations for...
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
            * methods defined within a closure.  For example, methods defined using `module_eval`, `class_eval`,
         
     | 
| 
      
 82 
     | 
    
         
            +
              `define_method`, or `define_singleton_method`:
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                ```ruby
         
     | 
| 
      
 85 
     | 
    
         
            +
                class Example
         
     | 
| 
      
 86 
     | 
    
         
            +
                  class_eval do
         
     | 
| 
      
 87 
     | 
    
         
            +
                    def example1
         
     | 
| 
      
 88 
     | 
    
         
            +
                    end
         
     | 
| 
      
 89 
     | 
    
         
            +
                  end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                  module_eval do
         
     | 
| 
      
 92 
     | 
    
         
            +
                    def example2
         
     | 
| 
      
 93 
     | 
    
         
            +
                    end
         
     | 
| 
      
 94 
     | 
    
         
            +
                  end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                  define_method(:example3) do
         
     | 
| 
      
 97 
     | 
    
         
            +
                  end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                  define_singleton_method(:example4) do
         
     | 
| 
      
 100 
     | 
    
         
            +
                  end
         
     | 
| 
      
 101 
     | 
    
         
            +
                end
         
     | 
| 
      
 102 
     | 
    
         
            +
                ```
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
            * singleton methods not defined on a constant or `self`
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                ```ruby
         
     | 
| 
      
 107 
     | 
    
         
            +
                class Foo
         
     | 
| 
      
 108 
     | 
    
         
            +
                  def self.bar; end   # ok
         
     | 
| 
      
 109 
     | 
    
         
            +
                  def Foo.baz; end    # ok
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                  myself = self
         
     | 
| 
      
 112 
     | 
    
         
            +
                  def myself.qux; end # cannot mutate
         
     | 
| 
      
 113 
     | 
    
         
            +
                end
         
     | 
| 
      
 114 
     | 
    
         
            +
                ```
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
            * methods defined with eval:
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                ```ruby
         
     | 
| 
      
 119 
     | 
    
         
            +
                class Foo
         
     | 
| 
      
 120 
     | 
    
         
            +
                  class_eval('def bar; end') # cannot mutate
         
     | 
| 
      
 121 
     | 
    
         
            +
                end
         
     | 
| 
      
 122 
     | 
    
         
            +
                ```
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
       76 
124 
     | 
    
         
             
            Mutation-Operators:
         
     | 
| 
       77 
125 
     | 
    
         
             
            -------------------
         
     | 
| 
       78 
126 
     | 
    
         | 
| 
         @@ -182,11 +230,24 @@ There are some presentations about mutant in the wild: 
     | 
|
| 
       182 
230 
     | 
    
         
             
            * [eurucamp 2013](http://2013.eurucamp.org/) / FrOSCon-2013 http://slid.es/markusschirp/mutation-testing
         
     | 
| 
       183 
231 
     | 
    
         
             
            * [Cologne.rb](http://www.colognerb.de/topics/mutation-testing-mit-mutant) / https://github.com/DonSchado/colognerb-on-mutant/blob/master/mutation_testing_slides.pdf
         
     | 
| 
       184 
232 
     | 
    
         | 
| 
       185 
     | 
    
         
            -
            Blog 
     | 
| 
      
 233 
     | 
    
         
            +
            Blog posts
         
     | 
| 
       186 
234 
     | 
    
         
             
            ----------
         
     | 
| 
       187 
235 
     | 
    
         | 
| 
       188 
     | 
    
         
            -
             
     | 
| 
       189 
     | 
    
         
            -
             
     | 
| 
      
 236 
     | 
    
         
            +
            Sorted by recency:
         
     | 
| 
      
 237 
     | 
    
         
            +
             
     | 
| 
      
 238 
     | 
    
         
            +
            * [How to write better code using mutation testing (November 2015)][blockscore]
         
     | 
| 
      
 239 
     | 
    
         
            +
            * [How good are your Ruby tests? Testing your tests with mutant (June 2015)][arkency1]
         
     | 
| 
      
 240 
     | 
    
         
            +
            * [Mutation testing and continuous integration (May 2015)][arkency2]
         
     | 
| 
      
 241 
     | 
    
         
            +
            * [Why I want to introduce mutation testing to the `rails_event_store` gem (April 2015)][arkency3]
         
     | 
| 
      
 242 
     | 
    
         
            +
            * [Mutation testing with mutant (April 2014)][sitepoint]
         
     | 
| 
      
 243 
     | 
    
         
            +
            * [Mutation testing with mutant (January 2013)][solnic]
         
     | 
| 
      
 244 
     | 
    
         
            +
             
     | 
| 
      
 245 
     | 
    
         
            +
            [blockscore]: https://blog.blockscore.com/how-to-write-better-code-using-mutation-testing/
         
     | 
| 
      
 246 
     | 
    
         
            +
            [sitepoint]: http://www.sitepoint.com/mutation-testing-mutant/
         
     | 
| 
      
 247 
     | 
    
         
            +
            [arkency1]: http://blog.arkency.com/2015/06/how-good-are-your-ruby-tests-testing-your-tests-with-mutant/
         
     | 
| 
      
 248 
     | 
    
         
            +
            [arkency2]: http://blog.arkency.com/2015/05/mutation-testing-and-continuous-integration/
         
     | 
| 
      
 249 
     | 
    
         
            +
            [arkency3]: http://blog.arkency.com/2015/04/why-i-want-to-introduce-mutation-testing-to-the-rails-event-store-gem/  
         
     | 
| 
      
 250 
     | 
    
         
            +
            [solnic]: http://solnic.eu/2013/01/23/mutation-testing-with-mutant.html
         
     | 
| 
       190 
251 
     | 
    
         | 
| 
       191 
252 
     | 
    
         
             
            The Crash / Stuck Problem (MRI)
         
     | 
| 
       192 
253 
     | 
    
         
             
            -------------------------------
         
     | 
    
        data/config/flay.yml
    CHANGED
    
    
    
        data/lib/mutant.rb
    CHANGED
    
    | 
         @@ -132,6 +132,7 @@ require 'mutant/mutator/node/match_current_line' 
     | 
|
| 
       132 
132 
     | 
    
         
             
            require 'mutant/loader'
         
     | 
| 
       133 
133 
     | 
    
         
             
            require 'mutant/context'
         
     | 
| 
       134 
134 
     | 
    
         
             
            require 'mutant/context/scope'
         
     | 
| 
      
 135 
     | 
    
         
            +
            require 'mutant/scope'
         
     | 
| 
       135 
136 
     | 
    
         
             
            require 'mutant/subject'
         
     | 
| 
       136 
137 
     | 
    
         
             
            require 'mutant/subject/method'
         
     | 
| 
       137 
138 
     | 
    
         
             
            require 'mutant/subject/method/instance'
         
     | 
| 
         @@ -148,6 +149,7 @@ require 'mutant/matcher/namespace' 
     | 
|
| 
       148 
149 
     | 
    
         
             
            require 'mutant/matcher/scope'
         
     | 
| 
       149 
150 
     | 
    
         
             
            require 'mutant/matcher/filter'
         
     | 
| 
       150 
151 
     | 
    
         
             
            require 'mutant/matcher/null'
         
     | 
| 
      
 152 
     | 
    
         
            +
            require 'mutant/matcher/static'
         
     | 
| 
       151 
153 
     | 
    
         
             
            require 'mutant/expression'
         
     | 
| 
       152 
154 
     | 
    
         
             
            require 'mutant/expression/parser'
         
     | 
| 
       153 
155 
     | 
    
         
             
            require 'mutant/expression/method'
         
     | 
    
        data/lib/mutant/cli.rb
    CHANGED
    
    
    
        data/lib/mutant/env/bootstrap.rb
    CHANGED
    
    | 
         @@ -4,10 +4,18 @@ module Mutant 
     | 
|
| 
       4 
4 
     | 
    
         
             
                class Bootstrap
         
     | 
| 
       5 
5 
     | 
    
         
             
                  include Adamantium::Flat, Concord::Public.new(:config, :cache), Procto.call(:env)
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
                   
     | 
| 
       8 
     | 
    
         
            -
                    "Fix your lib to follow normal ruby semantics!\n" \
         
     | 
| 
      
 7 
     | 
    
         
            +
                  SEMANTICS_MESSAGE_FORMAT =
         
     | 
| 
      
 8 
     | 
    
         
            +
                    "%<message>s. Fix your lib to follow normal ruby semantics!\n" \
         
     | 
| 
       9 
9 
     | 
    
         
             
                    '{Module,Class}#name should return resolvable constant name as String or nil'.freeze
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
      
 11 
     | 
    
         
            +
                  CLASS_NAME_RAISED_EXCEPTION =
         
     | 
| 
      
 12 
     | 
    
         
            +
                    '%<scope_class>s#name from: %<scope>s raised an error: %<exception>s'.freeze
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  CLASS_NAME_TYPE_MISMATCH_FORMAT =
         
     | 
| 
      
 15 
     | 
    
         
            +
                    '%<scope_class>s#name from: %<scope>s returned %<name>s'.freeze
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  private_constant(*constants(false))
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
       11 
19 
     | 
    
         
             
                  # Scopes that are eligible for matching
         
     | 
| 
       12 
20 
     | 
    
         
             
                  #
         
     | 
| 
       13 
21 
     | 
    
         
             
                  # @return [Enumerable<Matcher::Scope>]
         
     | 
| 
         @@ -84,7 +92,12 @@ module Mutant 
     | 
|
| 
       84 
92 
     | 
    
         
             
                  def scope_name(scope)
         
     | 
| 
       85 
93 
     | 
    
         
             
                    scope.name
         
     | 
| 
       86 
94 
     | 
    
         
             
                  rescue => exception
         
     | 
| 
       87 
     | 
    
         
            -
                     
     | 
| 
      
 95 
     | 
    
         
            +
                    semantics_warning(
         
     | 
| 
      
 96 
     | 
    
         
            +
                      CLASS_NAME_RAISED_EXCEPTION,
         
     | 
| 
      
 97 
     | 
    
         
            +
                      scope_class: scope.class,
         
     | 
| 
      
 98 
     | 
    
         
            +
                      scope:       scope,
         
     | 
| 
      
 99 
     | 
    
         
            +
                      exception:   exception.inspect
         
     | 
| 
      
 100 
     | 
    
         
            +
                    )
         
     | 
| 
       88 
101 
     | 
    
         
             
                    nil
         
     | 
| 
       89 
102 
     | 
    
         
             
                  end
         
     | 
| 
       90 
103 
     | 
    
         | 
| 
         @@ -95,7 +108,7 @@ module Mutant 
     | 
|
| 
       95 
108 
     | 
    
         
             
                  # @api private
         
     | 
| 
       96 
109 
     | 
    
         
             
                  def infect
         
     | 
| 
       97 
110 
     | 
    
         
             
                    config.includes.each(&$LOAD_PATH.method(:<<))
         
     | 
| 
       98 
     | 
    
         
            -
                    config.requires.each(&method(:require))
         
     | 
| 
      
 111 
     | 
    
         
            +
                    config.requires.each(&Kernel.method(:require))
         
     | 
| 
       99 
112 
     | 
    
         
             
                    @integration = config.integration.new(config).setup
         
     | 
| 
       100 
113 
     | 
    
         
             
                  end
         
     | 
| 
       101 
114 
     | 
    
         | 
| 
         @@ -105,7 +118,7 @@ module Mutant 
     | 
|
| 
       105 
118 
     | 
    
         
             
                  #
         
     | 
| 
       106 
119 
     | 
    
         
             
                  # @api private
         
     | 
| 
       107 
120 
     | 
    
         
             
                  def matched_subjects
         
     | 
| 
       108 
     | 
    
         
            -
                    Matcher::Compiler.call( 
     | 
| 
      
 121 
     | 
    
         
            +
                    Matcher::Compiler.call(config.matcher).call(self)
         
     | 
| 
       109 
122 
     | 
    
         
             
                  end
         
     | 
| 
       110 
123 
     | 
    
         | 
| 
       111 
124 
     | 
    
         
             
                  # Initialize matchable scopes
         
     | 
| 
         @@ -115,8 +128,8 @@ module Mutant 
     | 
|
| 
       115 
128 
     | 
    
         
             
                  # @api private
         
     | 
| 
       116 
129 
     | 
    
         
             
                  def initialize_matchable_scopes
         
     | 
| 
       117 
130 
     | 
    
         
             
                    scopes = ObjectSpace.each_object(Module).each_with_object([]) do |scope, aggregate|
         
     | 
| 
       118 
     | 
    
         
            -
                      expression = expression(scope)
         
     | 
| 
       119 
     | 
    
         
            -
                      aggregate <<  
     | 
| 
      
 131 
     | 
    
         
            +
                      expression = expression(scope) || next
         
     | 
| 
      
 132 
     | 
    
         
            +
                      aggregate << Scope.new(scope, expression)
         
     | 
| 
       120 
133 
     | 
    
         
             
                    end
         
     | 
| 
       121 
134 
     | 
    
         | 
| 
       122 
135 
     | 
    
         
             
                    @matchable_scopes = scopes.sort_by { |scope| scope.expression.syntax }
         
     | 
| 
         @@ -137,12 +150,27 @@ module Mutant 
     | 
|
| 
       137 
150 
     | 
    
         
             
                    name = scope_name(scope) or return
         
     | 
| 
       138 
151 
     | 
    
         | 
| 
       139 
152 
     | 
    
         
             
                    unless name.instance_of?(String)
         
     | 
| 
       140 
     | 
    
         
            -
                       
     | 
| 
      
 153 
     | 
    
         
            +
                      semantics_warning(
         
     | 
| 
      
 154 
     | 
    
         
            +
                        CLASS_NAME_TYPE_MISMATCH_FORMAT,
         
     | 
| 
      
 155 
     | 
    
         
            +
                        scope_class: scope.class,
         
     | 
| 
      
 156 
     | 
    
         
            +
                        scope:       scope,
         
     | 
| 
      
 157 
     | 
    
         
            +
                        name:        name
         
     | 
| 
      
 158 
     | 
    
         
            +
                      )
         
     | 
| 
       141 
159 
     | 
    
         
             
                      return
         
     | 
| 
       142 
160 
     | 
    
         
             
                    end
         
     | 
| 
       143 
161 
     | 
    
         | 
| 
       144 
162 
     | 
    
         
             
                    config.expression_parser.try_parse(name)
         
     | 
| 
       145 
163 
     | 
    
         
             
                  end
         
     | 
| 
      
 164 
     | 
    
         
            +
             
     | 
| 
      
 165 
     | 
    
         
            +
                  # Write a semantics warning
         
     | 
| 
      
 166 
     | 
    
         
            +
                  #
         
     | 
| 
      
 167 
     | 
    
         
            +
                  # @return [undefined]
         
     | 
| 
      
 168 
     | 
    
         
            +
                  #
         
     | 
| 
      
 169 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 170 
     | 
    
         
            +
                  def semantics_warning(format, options)
         
     | 
| 
      
 171 
     | 
    
         
            +
                    message = format % options
         
     | 
| 
      
 172 
     | 
    
         
            +
                    warn(SEMANTICS_MESSAGE_FORMAT % { message: message })
         
     | 
| 
      
 173 
     | 
    
         
            +
                  end
         
     | 
| 
       146 
174 
     | 
    
         
             
                end # Boostrap
         
     | 
| 
       147 
175 
     | 
    
         
             
              end # Env
         
     | 
| 
       148 
176 
     | 
    
         
             
            end # Mutant
         
     | 
| 
         @@ -32,15 +32,13 @@ module Mutant 
     | 
|
| 
       32 
32 
     | 
    
         | 
| 
       33 
33 
     | 
    
         
             
                  # Matcher for expression
         
     | 
| 
       34 
34 
     | 
    
         
             
                  #
         
     | 
| 
       35 
     | 
    
         
            -
                  # @param [Env] env
         
     | 
| 
       36 
     | 
    
         
            -
                  #
         
     | 
| 
       37 
35 
     | 
    
         
             
                  # @return [Matcher]
         
     | 
| 
       38 
36 
     | 
    
         
             
                  #
         
     | 
| 
       39 
37 
     | 
    
         
             
                  # @api private
         
     | 
| 
       40 
     | 
    
         
            -
                  def matcher 
     | 
| 
       41 
     | 
    
         
            -
                    methods_matcher = MATCHERS.fetch(scope_symbol).new( 
     | 
| 
      
 38 
     | 
    
         
            +
                  def matcher
         
     | 
| 
      
 39 
     | 
    
         
            +
                    methods_matcher = MATCHERS.fetch(scope_symbol).new(scope)
         
     | 
| 
       42 
40 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
                    Matcher::Filter. 
     | 
| 
      
 41 
     | 
    
         
            +
                    Matcher::Filter.new(methods_matcher, ->(subject) { subject.expression.eql?(self) })
         
     | 
| 
       44 
42 
     | 
    
         
             
                  end
         
     | 
| 
       45 
43 
     | 
    
         | 
| 
       46 
44 
     | 
    
         
             
                private
         
     | 
| 
         @@ -26,13 +26,11 @@ module Mutant 
     | 
|
| 
       26 
26 
     | 
    
         | 
| 
       27 
27 
     | 
    
         
             
                  # Matcher on expression
         
     | 
| 
       28 
28 
     | 
    
         
             
                  #
         
     | 
| 
       29 
     | 
    
         
            -
                  # @param [Env] env
         
     | 
| 
       30 
     | 
    
         
            -
                  #
         
     | 
| 
       31 
29 
     | 
    
         
             
                  # @return [Matcher::Method]
         
     | 
| 
       32 
30 
     | 
    
         
             
                  #
         
     | 
| 
       33 
31 
     | 
    
         
             
                  # @api private
         
     | 
| 
       34 
     | 
    
         
            -
                  def matcher 
     | 
| 
       35 
     | 
    
         
            -
                    MATCHERS.fetch(scope_symbol).new( 
     | 
| 
      
 32 
     | 
    
         
            +
                  def matcher
         
     | 
| 
      
 33 
     | 
    
         
            +
                    MATCHERS.fetch(scope_symbol).new(scope)
         
     | 
| 
       36 
34 
     | 
    
         
             
                  end
         
     | 
| 
       37 
35 
     | 
    
         | 
| 
       38 
36 
     | 
    
         
             
                  # Length of match with other expression
         
     | 
| 
         @@ -35,13 +35,11 @@ module Mutant 
     | 
|
| 
       35 
35 
     | 
    
         | 
| 
       36 
36 
     | 
    
         
             
                    # Matcher for expression
         
     | 
| 
       37 
37 
     | 
    
         
             
                    #
         
     | 
| 
       38 
     | 
    
         
            -
                    # @param [Env::Bootstrap] env
         
     | 
| 
       39 
     | 
    
         
            -
                    #
         
     | 
| 
       40 
38 
     | 
    
         
             
                    # @return [Matcher]
         
     | 
| 
       41 
39 
     | 
    
         
             
                    #
         
     | 
| 
       42 
40 
     | 
    
         
             
                    # @api private
         
     | 
| 
       43 
     | 
    
         
            -
                    def matcher 
     | 
| 
       44 
     | 
    
         
            -
                      Matcher::Namespace.new( 
     | 
| 
      
 41 
     | 
    
         
            +
                    def matcher
         
     | 
| 
      
 42 
     | 
    
         
            +
                      Matcher::Namespace.new(self)
         
     | 
| 
       45 
43 
     | 
    
         
             
                    end
         
     | 
| 
       46 
44 
     | 
    
         | 
| 
       47 
45 
     | 
    
         
             
                    # Length of match with other expression
         
     | 
| 
         @@ -71,13 +69,11 @@ module Mutant 
     | 
|
| 
       71 
69 
     | 
    
         | 
| 
       72 
70 
     | 
    
         
             
                    # Matcher matcher on expression
         
     | 
| 
       73 
71 
     | 
    
         
             
                    #
         
     | 
| 
       74 
     | 
    
         
            -
                    # @param [Env::Bootstrap] env
         
     | 
| 
       75 
     | 
    
         
            -
                    #
         
     | 
| 
       76 
72 
     | 
    
         
             
                    # @return [Matcher]
         
     | 
| 
       77 
73 
     | 
    
         
             
                    #
         
     | 
| 
       78 
74 
     | 
    
         
             
                    # @api private
         
     | 
| 
       79 
     | 
    
         
            -
                    def matcher 
     | 
| 
       80 
     | 
    
         
            -
                      Matcher::Scope.new( 
     | 
| 
      
 75 
     | 
    
         
            +
                    def matcher
         
     | 
| 
      
 76 
     | 
    
         
            +
                      Matcher::Scope.new(Object.const_get(scope_name))
         
     | 
| 
       81 
77 
     | 
    
         
             
                    end
         
     | 
| 
       82 
78 
     | 
    
         | 
| 
       83 
79 
     | 
    
         
             
                    # Syntax for expression
         
     | 
    
        data/lib/mutant/matcher.rb
    CHANGED
    
    | 
         @@ -1,30 +1,15 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Mutant
         
     | 
| 
       2 
2 
     | 
    
         
             
              # Abstract matcher to find subjects to mutate
         
     | 
| 
       3 
3 
     | 
    
         
             
              class Matcher
         
     | 
| 
       4 
     | 
    
         
            -
                include Adamantium::Flat,  
     | 
| 
      
 4 
     | 
    
         
            +
                include Adamantium::Flat, AbstractType
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
                #  
     | 
| 
      
 6 
     | 
    
         
            +
                # Call matcher
         
     | 
| 
       7 
7 
     | 
    
         
             
                #
         
     | 
| 
       8 
8 
     | 
    
         
             
                # @param [Env] env
         
     | 
| 
       9 
     | 
    
         
            -
                # @param [Object] input
         
     | 
| 
       10 
     | 
    
         
            -
                #
         
     | 
| 
       11 
     | 
    
         
            -
                # @return [undefined]
         
     | 
| 
       12 
     | 
    
         
            -
                #
         
     | 
| 
       13 
     | 
    
         
            -
                # @api private
         
     | 
| 
       14 
     | 
    
         
            -
                def self.build(*arguments)
         
     | 
| 
       15 
     | 
    
         
            -
                  new(*arguments)
         
     | 
| 
       16 
     | 
    
         
            -
                end
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
                # Enumerate subjects
         
     | 
| 
       19 
     | 
    
         
            -
                #
         
     | 
| 
       20 
     | 
    
         
            -
                # @return [self]
         
     | 
| 
       21 
     | 
    
         
            -
                #   if block given
         
     | 
| 
       22 
9 
     | 
    
         
             
                #
         
     | 
| 
       23 
10 
     | 
    
         
             
                # @return [Enumerable<Subject>]
         
     | 
| 
       24 
     | 
    
         
            -
                #   otherwise
         
     | 
| 
       25 
11 
     | 
    
         
             
                #
         
     | 
| 
       26 
     | 
    
         
            -
                 
     | 
| 
       27 
     | 
    
         
            -
                abstract_method :each
         
     | 
| 
      
 12 
     | 
    
         
            +
                abstract_method :call
         
     | 
| 
       28 
13 
     | 
    
         | 
| 
       29 
14 
     | 
    
         
             
              end # Matcher
         
     | 
| 
       30 
15 
     | 
    
         
             
            end # Mutant
         
     | 
    
        data/lib/mutant/matcher/chain.rb
    CHANGED
    
    | 
         @@ -1,26 +1,20 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Mutant
         
     | 
| 
       2 
2 
     | 
    
         
             
              class Matcher
         
     | 
| 
       3 
     | 
    
         
            -
                #  
     | 
| 
      
 3 
     | 
    
         
            +
                # Matcher chaining results of other matchers together
         
     | 
| 
       4 
4 
     | 
    
         
             
                class Chain < self
         
     | 
| 
       5 
5 
     | 
    
         
             
                  include Concord.new(:matchers)
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
                  #  
     | 
| 
      
 7 
     | 
    
         
            +
                  # Call matcher
         
     | 
| 
       8 
8 
     | 
    
         
             
                  #
         
     | 
| 
       9 
     | 
    
         
            -
                  # @ 
     | 
| 
       10 
     | 
    
         
            -
                  #   if no block given
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # @param [Env] env
         
     | 
| 
       11 
10 
     | 
    
         
             
                  #
         
     | 
| 
       12 
     | 
    
         
            -
                  # @return [ 
     | 
| 
       13 
     | 
    
         
            -
                  #   otherwise
         
     | 
| 
      
 11 
     | 
    
         
            +
                  # @return [Enumerable<Subject>]
         
     | 
| 
       14 
12 
     | 
    
         
             
                  #
         
     | 
| 
       15 
13 
     | 
    
         
             
                  # @api private
         
     | 
| 
       16 
     | 
    
         
            -
                  def  
     | 
| 
       17 
     | 
    
         
            -
                     
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
                    matchers.each do |matcher|
         
     | 
| 
       20 
     | 
    
         
            -
                      matcher.each(&block)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  def call(env)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    matchers.flat_map do |matcher|
         
     | 
| 
      
 16 
     | 
    
         
            +
                      matcher.call(env)
         
     | 
| 
       21 
17 
     | 
    
         
             
                    end
         
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
                    self
         
     | 
| 
       24 
18 
     | 
    
         
             
                  end
         
     | 
| 
       25 
19 
     | 
    
         | 
| 
       26 
20 
     | 
    
         
             
                end # Chain
         
     | 
| 
         @@ -3,7 +3,7 @@ module Mutant 
     | 
|
| 
       3 
3 
     | 
    
         | 
| 
       4 
4 
     | 
    
         
             
                # Compiler for complex matchers
         
     | 
| 
       5 
5 
     | 
    
         
             
                class Compiler
         
     | 
| 
       6 
     | 
    
         
            -
                  include Concord.new(: 
     | 
| 
      
 6 
     | 
    
         
            +
                  include Concord.new(:config), AST::Sexp, Procto.call(:result)
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
                  # Generated matcher
         
     | 
| 
       9 
9 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -12,7 +12,7 @@ module Mutant 
     | 
|
| 
       12 
12 
     | 
    
         
             
                  # @api private
         
     | 
| 
       13 
13 
     | 
    
         
             
                  def result
         
     | 
| 
       14 
14 
     | 
    
         
             
                    Filter.new(
         
     | 
| 
       15 
     | 
    
         
            -
                      Chain. 
     | 
| 
      
 15 
     | 
    
         
            +
                      Chain.new(config.match_expressions.map(&:matcher)),
         
     | 
| 
       16 
16 
     | 
    
         
             
                      Morpher::Evaluator::Predicate::Boolean::And.new(
         
     | 
| 
       17 
17 
     | 
    
         
             
                        [
         
     | 
| 
       18 
18 
     | 
    
         
             
                          ignored_subjects,
         
     | 
| 
         @@ -61,17 +61,6 @@ module Mutant 
     | 
|
| 
       61 
61 
     | 
    
         
             
                    Morpher::Evaluator::Predicate::Boolean::And.new(config.subject_filters)
         
     | 
| 
       62 
62 
     | 
    
         
             
                  end
         
     | 
| 
       63 
63 
     | 
    
         | 
| 
       64 
     | 
    
         
            -
                  # Matcher for expression on env
         
     | 
| 
       65 
     | 
    
         
            -
                  #
         
     | 
| 
       66 
     | 
    
         
            -
                  # @param [Mutant::Expression] expression
         
     | 
| 
       67 
     | 
    
         
            -
                  #
         
     | 
| 
       68 
     | 
    
         
            -
                  # @return [Matcher]
         
     | 
| 
       69 
     | 
    
         
            -
                  #
         
     | 
| 
       70 
     | 
    
         
            -
                  # @api private
         
     | 
| 
       71 
     | 
    
         
            -
                  def matcher(expression)
         
     | 
| 
       72 
     | 
    
         
            -
                    expression.matcher(env)
         
     | 
| 
       73 
     | 
    
         
            -
                  end
         
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
64 
     | 
    
         
             
                end # Compiler
         
     | 
| 
       76 
65 
     | 
    
         
             
              end # Matcher
         
     | 
| 
       77 
66 
     | 
    
         
             
            end # Mutant
         
     | 
| 
         @@ -4,30 +4,17 @@ module Mutant 
     | 
|
| 
       4 
4 
     | 
    
         
             
                class Filter < self
         
     | 
| 
       5 
5 
     | 
    
         
             
                  include Concord.new(:matcher, :predicate)
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
                  # New matcher
         
     | 
| 
       8 
     | 
    
         
            -
                  #
         
     | 
| 
       9 
     | 
    
         
            -
                  # @param [Matcher] matcher
         
     | 
| 
       10 
     | 
    
         
            -
                  #
         
     | 
| 
       11 
     | 
    
         
            -
                  # @return [Matcher]
         
     | 
| 
       12 
     | 
    
         
            -
                  #
         
     | 
| 
       13 
     | 
    
         
            -
                  # @api private
         
     | 
| 
       14 
     | 
    
         
            -
                  def self.build(matcher, &predicate)
         
     | 
| 
       15 
     | 
    
         
            -
                    new(matcher, predicate)
         
     | 
| 
       16 
     | 
    
         
            -
                  end
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
7 
     | 
    
         
             
                  # Enumerate matches
         
     | 
| 
       19 
8 
     | 
    
         
             
                  #
         
     | 
| 
       20 
     | 
    
         
            -
                  # @ 
     | 
| 
       21 
     | 
    
         
            -
                  #   if block given
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # @param [Env] env
         
     | 
| 
       22 
10 
     | 
    
         
             
                  #
         
     | 
| 
       23 
     | 
    
         
            -
                  # @return [ 
     | 
| 
       24 
     | 
    
         
            -
                  #   otherwise
         
     | 
| 
      
 11 
     | 
    
         
            +
                  # @return [Enumerable<Subject>]
         
     | 
| 
       25 
12 
     | 
    
         
             
                  #
         
     | 
| 
       26 
13 
     | 
    
         
             
                  # @api private
         
     | 
| 
       27 
     | 
    
         
            -
                  def  
     | 
| 
       28 
     | 
    
         
            -
                     
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def call(env)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    matcher
         
     | 
| 
      
 16 
     | 
    
         
            +
                      .call(env)
         
     | 
| 
      
 17 
     | 
    
         
            +
                      .select(&predicate.method(:call))
         
     | 
| 
       31 
18 
     | 
    
         
             
                  end
         
     | 
| 
       32 
19 
     | 
    
         | 
| 
       33 
20 
     | 
    
         
             
                end # Filter
         
     | 
| 
         @@ -1,133 +1,153 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Mutant
         
     | 
| 
       2 
2 
     | 
    
         
             
              class Matcher
         
     | 
| 
       3 
     | 
    
         
            -
                #  
     | 
| 
      
 3 
     | 
    
         
            +
                # Abstract base class for method matchers
         
     | 
| 
       4 
4 
     | 
    
         
             
                class Method < self
         
     | 
| 
       5 
     | 
    
         
            -
                  include  
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
      
 5 
     | 
    
         
            +
                  include AbstractType,
         
     | 
| 
      
 6 
     | 
    
         
            +
                          Adamantium::Flat,
         
     | 
| 
      
 7 
     | 
    
         
            +
                          Concord::Public.new(:scope, :target_method, :evaluator)
         
     | 
| 
       7 
8 
     | 
    
         | 
| 
       8 
9 
     | 
    
         
             
                  # Methods within rbx kernel directory are precompiled and their source
         
     | 
| 
       9 
10 
     | 
    
         
             
                  # cannot be accessed via reading source location. Same for methods created by eval.
         
     | 
| 
       10 
11 
     | 
    
         
             
                  BLACKLIST = %r{\A(kernel/|\(eval\)\z)}.freeze
         
     | 
| 
       11 
12 
     | 
    
         | 
| 
       12 
     | 
    
         
            -
                   
     | 
| 
      
 13 
     | 
    
         
            +
                  SOURCE_LOCATION_WARNING_FORMAT =
         
     | 
| 
      
 14 
     | 
    
         
            +
                    '%s does not have a valid source location, unable to emit subject'.freeze
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  CLOSURE_WARNING_FORMAT =
         
     | 
| 
      
 17 
     | 
    
         
            +
                    '%s is dynamically defined in a closure, unable to emit subject'.freeze
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  # Matched subjects
         
     | 
| 
       13 
20 
     | 
    
         
             
                  #
         
     | 
| 
       14 
     | 
    
         
            -
                  # @ 
     | 
| 
       15 
     | 
    
         
            -
                  #   if no block given
         
     | 
| 
      
 21 
     | 
    
         
            +
                  # @param [Env] env
         
     | 
| 
       16 
22 
     | 
    
         
             
                  #
         
     | 
| 
       17 
     | 
    
         
            -
                  # @return [ 
     | 
| 
       18 
     | 
    
         
            -
                  #   otherwise
         
     | 
| 
      
 23 
     | 
    
         
            +
                  # @return [Enumerable<Subject>]
         
     | 
| 
       19 
24 
     | 
    
         
             
                  #
         
     | 
| 
       20 
25 
     | 
    
         
             
                  # @api private
         
     | 
| 
       21 
     | 
    
         
            -
                  def  
     | 
| 
       22 
     | 
    
         
            -
                     
     | 
| 
      
 26 
     | 
    
         
            +
                  def call(env)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    evaluator.call(scope, target_method, env)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  # Abstract method match evaluator
         
     | 
| 
      
 31 
     | 
    
         
            +
                  #
         
     | 
| 
      
 32 
     | 
    
         
            +
                  # Present to avoid passing the env argument around in case the
         
     | 
| 
      
 33 
     | 
    
         
            +
                  # logic would be implemnented directly on the Matcher::Method
         
     | 
| 
      
 34 
     | 
    
         
            +
                  # instance
         
     | 
| 
      
 35 
     | 
    
         
            +
                  class Evaluator
         
     | 
| 
      
 36 
     | 
    
         
            +
                    include AbstractType,
         
     | 
| 
      
 37 
     | 
    
         
            +
                            Adamantium,
         
     | 
| 
      
 38 
     | 
    
         
            +
                            Concord.new(:scope, :target_method, :env),
         
     | 
| 
      
 39 
     | 
    
         
            +
                            Procto.call,
         
     | 
| 
      
 40 
     | 
    
         
            +
                            AST::NodePredicates
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                    # Matched subjects
         
     | 
| 
      
 43 
     | 
    
         
            +
                    #
         
     | 
| 
      
 44 
     | 
    
         
            +
                    # @return [Enumerable<Subject>]
         
     | 
| 
      
 45 
     | 
    
         
            +
                    #
         
     | 
| 
      
 46 
     | 
    
         
            +
                    # @api private
         
     | 
| 
      
 47 
     | 
    
         
            +
                    def call
         
     | 
| 
      
 48 
     | 
    
         
            +
                      return EMPTY_ARRAY if skip?
         
     | 
| 
       23 
49 
     | 
    
         | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
                      yield subject
         
     | 
| 
      
 50 
     | 
    
         
            +
                      [subject].compact
         
     | 
| 
       26 
51 
     | 
    
         
             
                    end
         
     | 
| 
       27 
52 
     | 
    
         | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
                  private
         
     | 
| 
       30 
54 
     | 
    
         | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
      
 55 
     | 
    
         
            +
                    # Test if method should be skipped
         
     | 
| 
      
 56 
     | 
    
         
            +
                    #
         
     | 
| 
      
 57 
     | 
    
         
            +
                    # @return [Truthy]
         
     | 
| 
      
 58 
     | 
    
         
            +
                    #
         
     | 
| 
      
 59 
     | 
    
         
            +
                    # @api private
         
     | 
| 
      
 60 
     | 
    
         
            +
                    def skip?
         
     | 
| 
      
 61 
     | 
    
         
            +
                      location = source_location
         
     | 
| 
      
 62 
     | 
    
         
            +
                      if location.nil? || BLACKLIST.match(location.first)
         
     | 
| 
      
 63 
     | 
    
         
            +
                        env.warn(SOURCE_LOCATION_WARNING_FORMAT % target_method)
         
     | 
| 
      
 64 
     | 
    
         
            +
                      elsif matched_node_path.any?(&method(:n_block?))
         
     | 
| 
      
 65 
     | 
    
         
            +
                        env.warn(CLOSURE_WARNING_FORMAT % target_method)
         
     | 
| 
      
 66 
     | 
    
         
            +
                      end
         
     | 
| 
      
 67 
     | 
    
         
            +
                    end
         
     | 
| 
       32 
68 
     | 
    
         | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
                    if location.nil? || BLACKLIST.match(location.first)
         
     | 
| 
       41 
     | 
    
         
            -
                      env.warn(format('%s does not have valid source location unable to emit subject', target_method.inspect))
         
     | 
| 
       42 
     | 
    
         
            -
                      true
         
     | 
| 
       43 
     | 
    
         
            -
                    elsif matched_node_path.any?(&method(:n_block?))
         
     | 
| 
       44 
     | 
    
         
            -
                      env.warn(format('%s is defined from a 3rd party lib unable to emit subject', target_method.inspect))
         
     | 
| 
       45 
     | 
    
         
            -
                      true
         
     | 
| 
       46 
     | 
    
         
            -
                    else
         
     | 
| 
       47 
     | 
    
         
            -
                      false
         
     | 
| 
      
 69 
     | 
    
         
            +
                    # Target method name
         
     | 
| 
      
 70 
     | 
    
         
            +
                    #
         
     | 
| 
      
 71 
     | 
    
         
            +
                    # @return [String]
         
     | 
| 
      
 72 
     | 
    
         
            +
                    #
         
     | 
| 
      
 73 
     | 
    
         
            +
                    # @api private
         
     | 
| 
      
 74 
     | 
    
         
            +
                    def method_name
         
     | 
| 
      
 75 
     | 
    
         
            +
                      target_method.name
         
     | 
| 
       48 
76 
     | 
    
         
             
                    end
         
     | 
| 
       49 
     | 
    
         
            -
                  end
         
     | 
| 
       50 
77 
     | 
    
         | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
             
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
      
 78 
     | 
    
         
            +
                    # Target context
         
     | 
| 
      
 79 
     | 
    
         
            +
                    #
         
     | 
| 
      
 80 
     | 
    
         
            +
                    # @return [Context::Scope]
         
     | 
| 
      
 81 
     | 
    
         
            +
                    #
         
     | 
| 
      
 82 
     | 
    
         
            +
                    # @api private
         
     | 
| 
      
 83 
     | 
    
         
            +
                    def context
         
     | 
| 
      
 84 
     | 
    
         
            +
                      Context::Scope.new(scope, source_path)
         
     | 
| 
      
 85 
     | 
    
         
            +
                    end
         
     | 
| 
       59 
86 
     | 
    
         | 
| 
       60 
     | 
    
         
            -
             
     | 
| 
       61 
     | 
    
         
            -
             
     | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
       64 
     | 
    
         
            -
             
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
      
 87 
     | 
    
         
            +
                    # Root source node
         
     | 
| 
      
 88 
     | 
    
         
            +
                    #
         
     | 
| 
      
 89 
     | 
    
         
            +
                    # @return [Parser::AST::Node]
         
     | 
| 
      
 90 
     | 
    
         
            +
                    #
         
     | 
| 
      
 91 
     | 
    
         
            +
                    # @api private
         
     | 
| 
      
 92 
     | 
    
         
            +
                    def ast
         
     | 
| 
      
 93 
     | 
    
         
            +
                      env.cache.parse(source_path)
         
     | 
| 
      
 94 
     | 
    
         
            +
                    end
         
     | 
| 
       68 
95 
     | 
    
         | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
       73 
     | 
    
         
            -
             
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
       76 
     | 
    
         
            -
             
     | 
| 
      
 96 
     | 
    
         
            +
                    # Path to source
         
     | 
| 
      
 97 
     | 
    
         
            +
                    #
         
     | 
| 
      
 98 
     | 
    
         
            +
                    # @return [Pathname]
         
     | 
| 
      
 99 
     | 
    
         
            +
                    #
         
     | 
| 
      
 100 
     | 
    
         
            +
                    # @api private
         
     | 
| 
      
 101 
     | 
    
         
            +
                    def source_path
         
     | 
| 
      
 102 
     | 
    
         
            +
                      Pathname.new(source_location.first)
         
     | 
| 
      
 103 
     | 
    
         
            +
                    end
         
     | 
| 
      
 104 
     | 
    
         
            +
                    memoize :source_path
         
     | 
| 
       77 
105 
     | 
    
         | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
       80 
     | 
    
         
            -
             
     | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
       83 
     | 
    
         
            -
             
     | 
| 
       84 
     | 
    
         
            -
             
     | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
       86 
     | 
    
         
            -
                  memoize :source_path
         
     | 
| 
      
 106 
     | 
    
         
            +
                    # Source file line
         
     | 
| 
      
 107 
     | 
    
         
            +
                    #
         
     | 
| 
      
 108 
     | 
    
         
            +
                    # @return [Fixnum]
         
     | 
| 
      
 109 
     | 
    
         
            +
                    #
         
     | 
| 
      
 110 
     | 
    
         
            +
                    # @api private
         
     | 
| 
      
 111 
     | 
    
         
            +
                    def source_line
         
     | 
| 
      
 112 
     | 
    
         
            +
                      source_location.last
         
     | 
| 
      
 113 
     | 
    
         
            +
                    end
         
     | 
| 
       87 
114 
     | 
    
         | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
       92 
     | 
    
         
            -
             
     | 
| 
       93 
     | 
    
         
            -
             
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
       95 
     | 
    
         
            -
             
     | 
| 
      
 115 
     | 
    
         
            +
                    # Full source location
         
     | 
| 
      
 116 
     | 
    
         
            +
                    #
         
     | 
| 
      
 117 
     | 
    
         
            +
                    # @return [Array{String,Fixnum}]
         
     | 
| 
      
 118 
     | 
    
         
            +
                    #
         
     | 
| 
      
 119 
     | 
    
         
            +
                    # @api private
         
     | 
| 
      
 120 
     | 
    
         
            +
                    def source_location
         
     | 
| 
      
 121 
     | 
    
         
            +
                      target_method.source_location
         
     | 
| 
      
 122 
     | 
    
         
            +
                    end
         
     | 
| 
       96 
123 
     | 
    
         | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
       98 
     | 
    
         
            -
             
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
       102 
     | 
    
         
            -
             
     | 
| 
       103 
     | 
    
         
            -
                     
     | 
| 
       104 
     | 
    
         
            -
             
     | 
| 
      
 124 
     | 
    
         
            +
                    # Matched subject
         
     | 
| 
      
 125 
     | 
    
         
            +
                    #
         
     | 
| 
      
 126 
     | 
    
         
            +
                    # @return [Subject]
         
     | 
| 
      
 127 
     | 
    
         
            +
                    #   if there is a matched node
         
     | 
| 
      
 128 
     | 
    
         
            +
                    #
         
     | 
| 
      
 129 
     | 
    
         
            +
                    # @return [nil]
         
     | 
| 
      
 130 
     | 
    
         
            +
                    #   otherwise
         
     | 
| 
      
 131 
     | 
    
         
            +
                    #
         
     | 
| 
      
 132 
     | 
    
         
            +
                    # @api private
         
     | 
| 
      
 133 
     | 
    
         
            +
                    def subject
         
     | 
| 
      
 134 
     | 
    
         
            +
                      node = matched_node_path.last || return
         
     | 
| 
      
 135 
     | 
    
         
            +
                      self.class::SUBJECT_CLASS.new(context, node)
         
     | 
| 
      
 136 
     | 
    
         
            +
                    end
         
     | 
| 
      
 137 
     | 
    
         
            +
                    memoize :subject
         
     | 
| 
       105 
138 
     | 
    
         | 
| 
       106 
     | 
    
         
            -
             
     | 
| 
       107 
     | 
    
         
            -
             
     | 
| 
       108 
     | 
    
         
            -
             
     | 
| 
       109 
     | 
    
         
            -
             
     | 
| 
       110 
     | 
    
         
            -
             
     | 
| 
       111 
     | 
    
         
            -
             
     | 
| 
       112 
     | 
    
         
            -
             
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
             
     | 
| 
       115 
     | 
    
         
            -
                   
     | 
| 
       116 
     | 
    
         
            -
                    node = matched_node_path.last
         
     | 
| 
       117 
     | 
    
         
            -
                    return unless node
         
     | 
| 
       118 
     | 
    
         
            -
                    self.class::SUBJECT_CLASS.new(context, node)
         
     | 
| 
       119 
     | 
    
         
            -
                  end
         
     | 
| 
       120 
     | 
    
         
            -
                  memoize :subject
         
     | 
| 
      
 139 
     | 
    
         
            +
                    # Matched node path
         
     | 
| 
      
 140 
     | 
    
         
            +
                    #
         
     | 
| 
      
 141 
     | 
    
         
            +
                    # @return [Array<Parser::AST::Node>]
         
     | 
| 
      
 142 
     | 
    
         
            +
                    #
         
     | 
| 
      
 143 
     | 
    
         
            +
                    # @api private
         
     | 
| 
      
 144 
     | 
    
         
            +
                    def matched_node_path
         
     | 
| 
      
 145 
     | 
    
         
            +
                      AST.find_last_path(ast, &method(:match?))
         
     | 
| 
      
 146 
     | 
    
         
            +
                    end
         
     | 
| 
      
 147 
     | 
    
         
            +
                    memoize :matched_node_path
         
     | 
| 
      
 148 
     | 
    
         
            +
                  end # Evaluator
         
     | 
| 
       121 
149 
     | 
    
         | 
| 
       122 
     | 
    
         
            -
                   
     | 
| 
       123 
     | 
    
         
            -
                  #
         
     | 
| 
       124 
     | 
    
         
            -
                  # @return [Array<Parser::AST::Node>]
         
     | 
| 
       125 
     | 
    
         
            -
                  #
         
     | 
| 
       126 
     | 
    
         
            -
                  # @api private
         
     | 
| 
       127 
     | 
    
         
            -
                  def matched_node_path
         
     | 
| 
       128 
     | 
    
         
            -
                    AST.find_last_path(ast, &method(:match?))
         
     | 
| 
       129 
     | 
    
         
            -
                  end
         
     | 
| 
       130 
     | 
    
         
            -
                  memoize :matched_node_path
         
     | 
| 
      
 150 
     | 
    
         
            +
                  private_constant(*constants(false))
         
     | 
| 
       131 
151 
     | 
    
         | 
| 
       132 
152 
     | 
    
         
             
                end # Method
         
     | 
| 
       133 
153 
     | 
    
         
             
              end # Matcher
         
     |