metamorpher 0.1.1 → 0.2.0
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/.gitignore +1 -0
 - data/README.md +80 -37
 - data/RELEASES.md +14 -0
 - data/lib/metamorpher.rb +1 -0
 - data/lib/metamorpher/builders/ruby/builder.rb +4 -0
 - data/lib/metamorpher/builders/ruby/uppercase_constant_rewriter.rb +3 -17
 - data/lib/metamorpher/mutator.rb +15 -0
 - data/lib/metamorpher/refactorer.rb +10 -36
 - data/lib/metamorpher/transformer/base.rb +51 -0
 - data/lib/metamorpher/{refactorer → transformer}/merger.rb +1 -1
 - data/lib/metamorpher/{refactorer → transformer}/site.rb +1 -1
 - data/lib/metamorpher/version.rb +1 -1
 - data/spec/integration/ruby/mutator_spec.rb +215 -0
 - data/spec/integration/ruby/refactorer_spec.rb +1 -1
 - data/spec/unit/{refactorer → transformer}/merger_spec.rb +3 -3
 - data/spec/unit/{refactorer → transformer}/site_spec.rb +2 -2
 - metadata +12 -7
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 07d706738851b486c6fc3a58140b5046a1569a6e
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 77e1d643b5816016c0d054954af1d9f7f9e6bbae
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 6a15ddbe30e40c36ec9d4ea427d6e5558650b00d6aabb907d2954cd5327abe5effc232355fc249fe0faa59191fe9546dadb2846ae4ef7e7f56796b52446ed3fe
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 063d0829bb4dbc7de52d3a50b78599d752d395a94f0b3e5cb9dd9067dfb3f8eae389ec6d3380db1a6b865f9b13f2fb9fc75c0bf1fa7606c427de4cfb4ed3d115
         
     | 
    
        data/.gitignore
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | 
         @@ -36,7 +36,7 @@ This simple example is short, but terse! To fully understand it, you might now w 
     | 
|
| 
       36 
36 
     | 
    
         | 
| 
       37 
37 
     | 
    
         
             
            * [Practicalities](#practicalities) - Information on how to use metamorpher to manipulate (Ruby) programs:
         
     | 
| 
       38 
38 
     | 
    
         
             
                * [Building Ruby terms](#building-ruby-terms) - how to concisely create terms that represent Ruby programs.
         
     | 
| 
       39 
     | 
    
         
            -
                * [ 
     | 
| 
      
 39 
     | 
    
         
            +
                * [Transformers](#transformers) - how to use rewriters to transform Ruby programs.
         
     | 
| 
       40 
40 
     | 
    
         | 
| 
       41 
41 
     | 
    
         | 
| 
       42 
42 
     | 
    
         
             
            ## Fundamentals
         
     | 
| 
         @@ -54,7 +54,7 @@ The primary data structure used for [rewriting](#rewriters) and for [matching](# 
     | 
|
| 
       54 
54 
     | 
    
         
             
            * Greedy variable - a variable that is bound to a set of subterms during [matching](#matchers).
         
     | 
| 
       55 
55 
     | 
    
         
             
            * Derivation - a placeholder node, which is replaced during [rewriting](#rewriters).
         
     | 
| 
       56 
56 
     | 
    
         | 
| 
       57 
     | 
    
         
            -
            To simplify the construction of terms, metamorpher provides the `Metamorpher::Builders::AST::Builder` class, which is demonstrated below. 
     | 
| 
      
 57 
     | 
    
         
            +
            To simplify the construction of terms, metamorpher provides the `Metamorpher::Builders::AST::Builder` class, which is demonstrated below.
         
     | 
| 
       58 
58 
     | 
    
         | 
| 
       59 
59 
     | 
    
         
             
            ```ruby
         
     | 
| 
       60 
60 
     | 
    
         
             
            require "metamorpher"
         
     | 
| 
         @@ -71,7 +71,7 @@ builder.derivation! :singular do |singular, builder| 
     | 
|
| 
       71 
71 
     | 
    
         
             
              builder.literal!(singular.name + "s")
         
     | 
| 
       72 
72 
     | 
    
         
             
            end
         
     | 
| 
       73 
73 
     | 
    
         
             
             # [SINGULAR] -> ...
         
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
       75 
75 
     | 
    
         
             
            builder.derivation! :key, :value do |key, value, builder|
         
     | 
| 
       76 
76 
     | 
    
         
             
              builder.pair(key, value)
         
     | 
| 
       77 
77 
     | 
    
         
             
            end
         
     | 
| 
         @@ -91,7 +91,7 @@ The builder provides a method missing shorthand for constructing literals, varia 
     | 
|
| 
       91 
91 
     | 
    
         | 
| 
       92 
92 
     | 
    
         
             
            ```ruby
         
     | 
| 
       93 
93 
     | 
    
         
             
            builder.succ # => succ
         
     | 
| 
       94 
     | 
    
         
            -
            builder.N # => N 
     | 
| 
      
 94 
     | 
    
         
            +
            builder.N # => N
         
     | 
| 
       95 
95 
     | 
    
         
             
            builder.N_ # => N+
         
     | 
| 
       96 
96 
     | 
    
         
             
            ```
         
     | 
| 
       97 
97 
     | 
    
         | 
| 
         @@ -137,7 +137,7 @@ require "metamorpher" 
     | 
|
| 
       137 
137 
     | 
    
         
             
            class SuccZeroMatcher
         
     | 
| 
       138 
138 
     | 
    
         
             
              include Metamorpher::Matcher
         
     | 
| 
       139 
139 
     | 
    
         
             
              include Metamorpher::Builders::AST
         
     | 
| 
       140 
     | 
    
         
            -
             
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
       141 
141 
     | 
    
         
             
              def pattern
         
     | 
| 
       142 
142 
     | 
    
         
             
                builder.succ(0)
         
     | 
| 
       143 
143 
     | 
    
         
             
              end
         
     | 
| 
         @@ -145,7 +145,7 @@ end 
     | 
|
| 
       145 
145 
     | 
    
         | 
| 
       146 
146 
     | 
    
         
             
            expression = Metamorpher.builder.succ(0) # => succ(0)
         
     | 
| 
       147 
147 
     | 
    
         
             
            result = SuccZeroMatcher.new.run(expression)
         
     | 
| 
       148 
     | 
    
         
            -
             # => <Metamorpher::Matcher::Match root=succ(0), substitution={}> 
     | 
| 
      
 148 
     | 
    
         
            +
             # => <Metamorpher::Matcher::Match root=succ(0), substitution={}>
         
     | 
| 
       149 
149 
     | 
    
         
             
            result.matches? # => true
         
     | 
| 
       150 
150 
     | 
    
         | 
| 
       151 
151 
     | 
    
         
             
            expression = Metamorpher.builder.succ(1) # => succ(1)
         
     | 
| 
         @@ -164,7 +164,7 @@ For example, suppose we wish to match expressions of the form `succ(X)` where X 
     | 
|
| 
       164 
164 
     | 
    
         
             
            class SuccMatcher
         
     | 
| 
       165 
165 
     | 
    
         
             
              include Metamorpher::Matcher
         
     | 
| 
       166 
166 
     | 
    
         
             
              include Metamorpher::Builders::AST
         
     | 
| 
       167 
     | 
    
         
            -
             
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
       168 
168 
     | 
    
         
             
              def pattern
         
     | 
| 
       169 
169 
     | 
    
         
             
                builder.succ(builder.X)
         
     | 
| 
       170 
170 
     | 
    
         
             
              end
         
     | 
| 
         @@ -172,21 +172,21 @@ end 
     | 
|
| 
       172 
172 
     | 
    
         | 
| 
       173 
173 
     | 
    
         
             
            expression = Metamorpher.builder.succ(0) # => succ(0)
         
     | 
| 
       174 
174 
     | 
    
         
             
            SuccMatcher.new.run(expression)
         
     | 
| 
       175 
     | 
    
         
            -
             # => <Metamorpher::Matcher::Match root=succ(0), substitution={:x=>0}> 
     | 
| 
      
 175 
     | 
    
         
            +
             # => <Metamorpher::Matcher::Match root=succ(0), substitution={:x=>0}>
         
     | 
| 
       176 
176 
     | 
    
         | 
| 
       177 
177 
     | 
    
         
             
            expression = Metamorpher.builder.succ(1) # => succ(1)
         
     | 
| 
       178 
178 
     | 
    
         
             
            SuccMatcher.new.run(expression)
         
     | 
| 
       179 
179 
     | 
    
         
             
             # => <Metamorpher::Matcher::Match root=succ(0), substitution={:x=>1}>
         
     | 
| 
       180 
     | 
    
         
            -
             
     | 
| 
      
 180 
     | 
    
         
            +
             
     | 
| 
       181 
181 
     | 
    
         
             
            expression = Metamorpher.builder.succ(:n) # => succ(n)
         
     | 
| 
       182 
182 
     | 
    
         
             
            SuccMatcher.new.run(expression)
         
     | 
| 
       183 
183 
     | 
    
         
             
             # => <Metamorpher::Matcher::Match root=succ(n), substitution={:x=>n}>
         
     | 
| 
       184 
184 
     | 
    
         | 
| 
       185 
185 
     | 
    
         
             
            expression = Metamorpher.builder.succ(Metamorpher.builder.succ(:n)) # => succ(succ(n))
         
     | 
| 
       186 
186 
     | 
    
         
             
            SuccMatcher.new.run(expression)
         
     | 
| 
       187 
     | 
    
         
            -
             # => <Metamorpher::Matcher::Match root=succ(succ(n)), substitution={:x=>succ(n)}> 
     | 
| 
      
 187 
     | 
    
         
            +
             # => <Metamorpher::Matcher::Match root=succ(succ(n)), substitution={:x=>succ(n)}>
         
     | 
| 
       188 
188 
     | 
    
         
             
            ```
         
     | 
| 
       189 
     | 
    
         
            -
             
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
       190 
190 
     | 
    
         
             
            #### Conditional variables
         
     | 
| 
       191 
191 
     | 
    
         | 
| 
       192 
192 
     | 
    
         
             
            By default, a variable matches any literal. Matching is more powerful when variables are able to match only those literals that satisfy some condition. Metamorpher provides conditional variables for this purpose.
         
     | 
| 
         @@ -197,7 +197,7 @@ For example, suppose that we wish to create a matcher that only matches method c 
     | 
|
| 
       197 
197 
     | 
    
         
             
            class DynamicFinderMatcher
         
     | 
| 
       198 
198 
     | 
    
         
             
              include Metamorpher::Matcher
         
     | 
| 
       199 
199 
     | 
    
         
             
              include Metamorpher::Builders::AST
         
     | 
| 
       200 
     | 
    
         
            -
             
     | 
| 
      
 200 
     | 
    
         
            +
             
     | 
| 
       201 
201 
     | 
    
         
             
              def pattern
         
     | 
| 
       202 
202 
     | 
    
         
             
                builder.literal!(
         
     | 
| 
       203 
203 
     | 
    
         
             
                  :".",
         
     | 
| 
         @@ -209,7 +209,7 @@ end 
     | 
|
| 
       209 
209 
     | 
    
         | 
| 
       210 
210 
     | 
    
         
             
            expression = Metamorpher.builder.literal!(:".", :User, :find_by_name) # => .(User, find_by_name)
         
     | 
| 
       211 
211 
     | 
    
         
             
            DynamicFinderMatcher.new.run(expression)
         
     | 
| 
       212 
     | 
    
         
            -
             # => #<Metamorpher::Matcher::Match root=.(User, find_by_name), substitution={:method=>find_by_name}> 
     | 
| 
      
 212 
     | 
    
         
            +
             # => #<Metamorpher::Matcher::Match root=.(User, find_by_name), substitution={:method=>find_by_name}>
         
     | 
| 
       213 
213 
     | 
    
         | 
| 
       214 
214 
     | 
    
         
             
            expression = Metamorpher.builder.literal!(:".", :User, :find) # => .(User, find)
         
     | 
| 
       215 
215 
     | 
    
         
             
            DynamicFinderMatcher.new.run(expression)
         
     | 
| 
         @@ -226,7 +226,7 @@ For example, suppose that we wish to create a matcher that works for an expressi 
     | 
|
| 
       226 
226 
     | 
    
         
             
            class MultiAddMatcher
         
     | 
| 
       227 
227 
     | 
    
         
             
              include Metamorpher::Matcher
         
     | 
| 
       228 
228 
     | 
    
         
             
              include Metamorpher::Builders::AST
         
     | 
| 
       229 
     | 
    
         
            -
             
     | 
| 
      
 229 
     | 
    
         
            +
             
     | 
| 
       230 
230 
     | 
    
         
             
              def pattern
         
     | 
| 
       231 
231 
     | 
    
         
             
                builder.add(
         
     | 
| 
       232 
232 
     | 
    
         
             
                  builder.ARGS_
         
     | 
| 
         @@ -235,10 +235,10 @@ class MultiAddMatcher 
     | 
|
| 
       235 
235 
     | 
    
         
             
            end
         
     | 
| 
       236 
236 
     | 
    
         | 
| 
       237 
237 
     | 
    
         
             
            MultiAddMatcher.new.run(Metamorpher.builder.add(1,2))
         
     | 
| 
       238 
     | 
    
         
            -
             # => #<Metamorpher::Matcher::Match root=add(1,2), substitution={:args=>[1, 2]}> 
     | 
| 
      
 238 
     | 
    
         
            +
             # => #<Metamorpher::Matcher::Match root=add(1,2), substitution={:args=>[1, 2]}>
         
     | 
| 
       239 
239 
     | 
    
         | 
| 
       240 
240 
     | 
    
         
             
            MultiAddMatcher.new.run(Metamorpher.builder.add(1,2,3))
         
     | 
| 
       241 
     | 
    
         
            -
             # => #<Metamorpher::Matcher::Match root=add(1,2,3), substitution={:args=>[1, 2, 3]}> 
     | 
| 
      
 241 
     | 
    
         
            +
             # => #<Metamorpher::Matcher::Match root=add(1,2,3), substitution={:args=>[1, 2, 3]}>
         
     | 
| 
       242 
242 
     | 
    
         
             
            ```
         
     | 
| 
       243 
243 
     | 
    
         | 
| 
       244 
244 
     | 
    
         
             
            ### Rewriters
         
     | 
| 
         @@ -253,11 +253,11 @@ require "metamorpher" 
     | 
|
| 
       253 
253 
     | 
    
         
             
            class SuccZeroRewriter
         
     | 
| 
       254 
254 
     | 
    
         
             
              include Metamorpher::Rewriter
         
     | 
| 
       255 
255 
     | 
    
         
             
              include Metamorpher::Builders::AST
         
     | 
| 
       256 
     | 
    
         
            -
             
     | 
| 
      
 256 
     | 
    
         
            +
             
     | 
| 
       257 
257 
     | 
    
         
             
              def pattern
         
     | 
| 
       258 
258 
     | 
    
         
             
                builder.literal! :succ, 0
         
     | 
| 
       259 
259 
     | 
    
         
             
              end
         
     | 
| 
       260 
     | 
    
         
            -
             
     | 
| 
      
 260 
     | 
    
         
            +
             
     | 
| 
       261 
261 
     | 
    
         
             
              def replacement
         
     | 
| 
       262 
262 
     | 
    
         
             
                builder.literal! 1
         
     | 
| 
       263 
263 
     | 
    
         
             
              end
         
     | 
| 
         @@ -300,7 +300,7 @@ SuccZeroRewriter.new.reduce(expression) do |matching, rewritten| 
     | 
|
| 
       300 
300 
     | 
    
         
             
            end
         
     | 
| 
       301 
301 
     | 
    
         
             
             # About to replace 'succ(0)' at position [0] with '1'
         
     | 
| 
       302 
302 
     | 
    
         
             
             # About to replace 'succ(0)' at position [1] with '1'
         
     | 
| 
       303 
     | 
    
         
            -
             # => 
     | 
| 
      
 303 
     | 
    
         
            +
             # =>
         
     | 
| 
       304 
304 
     | 
    
         
             
            ```
         
     | 
| 
       305 
305 
     | 
    
         | 
| 
       306 
306 
     | 
    
         
             
            #### Derivations
         
     | 
| 
         @@ -313,11 +313,11 @@ For example, suppose that we wish to create a rewriter that pluralises any liter 
     | 
|
| 
       313 
313 
     | 
    
         
             
            class PluraliseRewriter
         
     | 
| 
       314 
314 
     | 
    
         
             
              include Metamorpher::Rewriter
         
     | 
| 
       315 
315 
     | 
    
         
             
              include Metamorpher::Builders::AST
         
     | 
| 
       316 
     | 
    
         
            -
             
     | 
| 
      
 316 
     | 
    
         
            +
             
     | 
| 
       317 
317 
     | 
    
         
             
              def pattern
         
     | 
| 
       318 
318 
     | 
    
         
             
                builder.SINGULAR
         
     | 
| 
       319 
319 
     | 
    
         
             
              end
         
     | 
| 
       320 
     | 
    
         
            -
             
     | 
| 
      
 320 
     | 
    
         
            +
             
     | 
| 
       321 
321 
     | 
    
         
             
              def replacement
         
     | 
| 
       322 
322 
     | 
    
         
             
                builder.derivation! :singular do |singular|
         
     | 
| 
       323 
323 
     | 
    
         
             
                  builder.literal!(singular.name + "s")
         
     | 
| 
         @@ -398,11 +398,23 @@ builder 
     | 
|
| 
       398 
398 
     | 
    
         
             
             # [KEY, VALUE] -> ...
         
     | 
| 
       399 
399 
     | 
    
         
             
            ```
         
     | 
| 
       400 
400 
     | 
    
         | 
| 
       401 
     | 
    
         
            -
            ###  
     | 
| 
      
 401 
     | 
    
         
            +
            ### Transformers
         
     | 
| 
      
 402 
     | 
    
         
            +
             
     | 
| 
      
 403 
     | 
    
         
            +
            Transformers are [rewriters](#rewriters) that are specialised for rewriting program source code. A transformer parses a program's source code, rewrites the source code, and returns the unparsed, rewritten source code.
         
     | 
| 
      
 404 
     | 
    
         
            +
             
     | 
| 
      
 405 
     | 
    
         
            +
            Metamorpher provides two types of transformers:
         
     | 
| 
      
 406 
     | 
    
         
            +
             
     | 
| 
      
 407 
     | 
    
         
            +
            * Refactorer - produces a single transformed program that contains all rewritings together
         
     | 
| 
      
 408 
     | 
    
         
            +
            * Mutator - produces a set of transformed programs where each program contains a single rewriting
         
     | 
| 
      
 409 
     | 
    
         
            +
             
     | 
| 
      
 410 
     | 
    
         
            +
            For example, for the pattern `1 + 1`, the replacement `2` and the input program `(1 + 1) * (1 + 1)`:
         
     | 
| 
       402 
411 
     | 
    
         | 
| 
       403 
     | 
    
         
            -
             
     | 
| 
      
 412 
     | 
    
         
            +
            * A refactorer will produce `(2) * (2)`
         
     | 
| 
      
 413 
     | 
    
         
            +
            * A mutator will produce `[(2) * (1 + 1), (1 + 1) * (2)].`
         
     | 
| 
       404 
414 
     | 
    
         | 
| 
       405 
     | 
    
         
            -
            Metamorpher provides the `Metamorpher::Refactorer`  
     | 
| 
      
 415 
     | 
    
         
            +
            Metamorpher provides the `Metamorpher::Refactorer` and `Metamorpher::Mutator` modules for constructing classes that perform refactorings or mutations.
         
     | 
| 
      
 416 
     | 
    
         
            +
             
     | 
| 
      
 417 
     | 
    
         
            +
            To construct a refactorer, include the relevant module, specify a `pattern` and a `replacement`, and then call `refactor(src)`:
         
     | 
| 
       406 
418 
     | 
    
         | 
| 
       407 
419 
     | 
    
         
             
            ```ruby
         
     | 
| 
       408 
420 
     | 
    
         
             
            require "metamorpher"
         
     | 
| 
         @@ -420,11 +432,42 @@ class UnnecessaryConditionalRefactorer 
     | 
|
| 
       420 
432 
     | 
    
         
             
              end
         
     | 
| 
       421 
433 
     | 
    
         
             
            end
         
     | 
| 
       422 
434 
     | 
    
         | 
| 
       423 
     | 
    
         
            -
            program = "a = if some_predicate then true else false end"
         
     | 
| 
      
 435 
     | 
    
         
            +
            program = "a = if some_predicate then true else false end; " \
         
     | 
| 
      
 436 
     | 
    
         
            +
                      "b = if another_predicate then true else false end"
         
     | 
| 
       424 
437 
     | 
    
         
             
            UnnecessaryConditionalRefactorer.new.refactor(program)
         
     | 
| 
       425 
     | 
    
         
            -
             # => "a = some_predicate"
         
     | 
| 
      
 438 
     | 
    
         
            +
             # => "a = some_predicate; b = another_predicate"
         
     | 
| 
       426 
439 
     | 
    
         
             
            ```
         
     | 
| 
       427 
440 
     | 
    
         | 
| 
      
 441 
     | 
    
         
            +
            Similarly to construct a mutator, include the relevant module, specify a `pattern` and an array of `replacements`, and then call `mutate(src)`:
         
     | 
| 
      
 442 
     | 
    
         
            +
             
     | 
| 
      
 443 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 444 
     | 
    
         
            +
            require "metamorpher"
         
     | 
| 
      
 445 
     | 
    
         
            +
             
     | 
| 
      
 446 
     | 
    
         
            +
            class LessThanMutator
         
     | 
| 
      
 447 
     | 
    
         
            +
              include Metamorpher::Mutator
         
     | 
| 
      
 448 
     | 
    
         
            +
              include Metamorpher::Builders::Ruby
         
     | 
| 
      
 449 
     | 
    
         
            +
             
     | 
| 
      
 450 
     | 
    
         
            +
              def pattern
         
     | 
| 
      
 451 
     | 
    
         
            +
                builder.build("A < B")
         
     | 
| 
      
 452 
     | 
    
         
            +
              end
         
     | 
| 
      
 453 
     | 
    
         
            +
             
     | 
| 
      
 454 
     | 
    
         
            +
              def replacements
         
     | 
| 
      
 455 
     | 
    
         
            +
                builder.build_all("A > B", "A == B")
         
     | 
| 
      
 456 
     | 
    
         
            +
              end
         
     | 
| 
      
 457 
     | 
    
         
            +
            end
         
     | 
| 
      
 458 
     | 
    
         
            +
             
     | 
| 
      
 459 
     | 
    
         
            +
            program = "a = foo < bar; b = bar < baz"
         
     | 
| 
      
 460 
     | 
    
         
            +
            LessThanMutator.new.mutate(program)
         
     | 
| 
      
 461 
     | 
    
         
            +
             # => [
         
     | 
| 
      
 462 
     | 
    
         
            +
             #       "a = foo > bar; b = bar < baz",
         
     | 
| 
      
 463 
     | 
    
         
            +
             #       "a = foo == bar; b = bar < baz",
         
     | 
| 
      
 464 
     | 
    
         
            +
             #       "a = foo < bar; b = bar > baz",
         
     | 
| 
      
 465 
     | 
    
         
            +
             #      "a = foo < bar; b = bar == baz"
         
     | 
| 
      
 466 
     | 
    
         
            +
             #    ]
         
     | 
| 
      
 467 
     | 
    
         
            +
            ```
         
     | 
| 
      
 468 
     | 
    
         
            +
             
     | 
| 
      
 469 
     | 
    
         
            +
            The remainder of this section discusses only refactorers, but note that mutators have all of the same functionality as refactorers (but provides methods prefixed with `mutate` rather than `refactor`).
         
     | 
| 
      
 470 
     | 
    
         
            +
             
     | 
| 
       428 
471 
     | 
    
         
             
            The `refactor` method can optionally take a block, which is called immediately before the matching code is replaced with the refactored code:
         
     | 
| 
       429 
472 
     | 
    
         | 
| 
       430 
473 
     | 
    
         
             
            ```ruby
         
     | 
| 
         @@ -445,11 +488,11 @@ The `Metamorpher::Refactorer` module also defines a `refactor_file(path)` method 
     | 
|
| 
       445 
488 
     | 
    
         | 
| 
       446 
489 
     | 
    
         
             
            ```ruby
         
     | 
| 
       447 
490 
     | 
    
         
             
            path = File.expand_path("refactorable.rb", "/Users/louis/code/mutiny")
         
     | 
| 
       448 
     | 
    
         
            -
             # => "/Users/louis/code/mutiny/refactorable.rb" 
     | 
| 
      
 491 
     | 
    
         
            +
             # => "/Users/louis/code/mutiny/refactorable.rb"
         
     | 
| 
       449 
492 
     | 
    
         | 
| 
       450 
493 
     | 
    
         
             
            UnnecessaryConditionalRefactorer.new.refactor_file(path)
         
     | 
| 
       451 
494 
     | 
    
         
             
             # => ... (refactored code)
         
     | 
| 
       452 
     | 
    
         
            -
             
     | 
| 
      
 495 
     | 
    
         
            +
             
     | 
| 
       453 
496 
     | 
    
         
             
            UnnecessaryConditionalRefactorer.new.refactor_file(path) do |refactoring|
         
     | 
| 
       454 
497 
     | 
    
         
             
              # works just like the block passed to refactor
         
     | 
| 
       455 
498 
     | 
    
         
             
            end
         
     | 
| 
         @@ -460,7 +503,7 @@ You might prefer the `refactor_files(paths)` method, if you'd like to refactor s 
     | 
|
| 
       460 
503 
     | 
    
         | 
| 
       461 
504 
     | 
    
         
             
            ```ruby
         
     | 
| 
       462 
505 
     | 
    
         
             
            paths = Dir.glob(File.expand_path(File.join("**", "*.rb"), "/Users/louis/code/mutiny"))
         
     | 
| 
       463 
     | 
    
         
            -
             # => ["/Users/louis/code/mutiny/lib/mutiny.rb", ...] 
     | 
| 
      
 506 
     | 
    
         
            +
             # => ["/Users/louis/code/mutiny/lib/mutiny.rb", ...]
         
     | 
| 
       464 
507 
     | 
    
         | 
| 
       465 
508 
     | 
    
         
             
             # Note that refactor_files returns a Hash rather than a String
         
     | 
| 
       466 
509 
     | 
    
         
             
            UnnecessaryConditionalRefactorer.new.refactor_files(paths)
         
     | 
| 
         @@ -489,22 +532,22 @@ By default, `Metamorpher::Refactorer` assumes that you wish to refactor Ruby pro 
     | 
|
| 
       489 
532 
     | 
    
         
             
            ```ruby
         
     | 
| 
       490 
533 
     | 
    
         
             
            class JavaRefactorer
         
     | 
| 
       491 
534 
     | 
    
         
             
              include Metamorpher::Refactorer
         
     | 
| 
       492 
     | 
    
         
            -
             
     | 
| 
      
 535 
     | 
    
         
            +
             
     | 
| 
       493 
536 
     | 
    
         
             
              def driver
         
     | 
| 
       494 
537 
     | 
    
         
             
                YourTool::MetamorpherDrivers::Java.new
         
     | 
| 
       495 
538 
     | 
    
         
             
              end
         
     | 
| 
       496 
     | 
    
         
            -
             
     | 
| 
      
 539 
     | 
    
         
            +
             
     | 
| 
       497 
540 
     | 
    
         
             
              def pattern
         
     | 
| 
       498 
541 
     | 
    
         
             
                ...
         
     | 
| 
       499 
542 
     | 
    
         
             
              end
         
     | 
| 
       500 
     | 
    
         
            -
             
     | 
| 
      
 543 
     | 
    
         
            +
             
     | 
| 
       501 
544 
     | 
    
         
             
              def replacement
         
     | 
| 
       502 
545 
     | 
    
         
             
                ...
         
     | 
| 
       503 
546 
     | 
    
         
             
              end
         
     | 
| 
       504 
547 
     | 
    
         
             
            end
         
     | 
| 
       505 
548 
     | 
    
         
             
            ```
         
     | 
| 
       506 
549 
     | 
    
         | 
| 
       507 
     | 
    
         
            -
            #### Examples 
     | 
| 
      
 550 
     | 
    
         
            +
            #### Examples
         
     | 
| 
       508 
551 
     | 
    
         | 
| 
       509 
552 
     | 
    
         
             
            Below are a few examples of using metamorpher to perform refactorings on Ruby code.
         
     | 
| 
       510 
553 
     | 
    
         | 
| 
         @@ -558,21 +601,21 @@ class RefactorWhereFirstToFindBy 
     | 
|
| 
       558 
601 
     | 
    
         
             
                   builder.build(create_hash_string(keys, values))
         
     | 
| 
       559 
602 
     | 
    
         
             
                 end
         
     | 
| 
       560 
603 
     | 
    
         
             
              end
         
     | 
| 
       561 
     | 
    
         
            -
             
     | 
| 
      
 604 
     | 
    
         
            +
             
     | 
| 
       562 
605 
     | 
    
         
             
              private
         
     | 
| 
       563 
     | 
    
         
            -
             
     | 
| 
      
 606 
     | 
    
         
            +
             
     | 
| 
       564 
607 
     | 
    
         
             
              # Extracts an array of attributes from the name of a dynamic
         
     | 
| 
       565 
608 
     | 
    
         
             
              # finder, such as find_by_asset_id_and_object_path.
         
     | 
| 
       566 
609 
     | 
    
         
             
              def attributes_from_dynamic_finder(dynamic_finder)
         
     | 
| 
       567 
610 
     | 
    
         
             
                dynamic_finder["find_by_".length..-1].split("_and_")
         
     | 
| 
       568 
611 
     | 
    
         
             
              end
         
     | 
| 
       569 
     | 
    
         
            -
             
     | 
| 
      
 612 
     | 
    
         
            +
             
     | 
| 
       570 
613 
     | 
    
         
             
              # Builds a string representation of a hash from a set of keys
         
     | 
| 
       571 
614 
     | 
    
         
             
              # and a corresponding set of values
         
     | 
| 
       572 
615 
     | 
    
         
             
              def create_hash_string(keys, values)
         
     | 
| 
       573 
616 
     | 
    
         
             
                "{" + create_pairs_string(keys, values) + "}"
         
     | 
| 
       574 
617 
     | 
    
         
             
              end
         
     | 
| 
       575 
     | 
    
         
            -
             
     | 
| 
      
 618 
     | 
    
         
            +
             
     | 
| 
       576 
619 
     | 
    
         
             
              def create_pairs_string(keys, values)
         
     | 
| 
       577 
620 
     | 
    
         
             
                keys
         
     | 
| 
       578 
621 
     | 
    
         
             
                 .zip(values)
         
     | 
    
        data/RELEASES.md
    ADDED
    
    | 
         @@ -0,0 +1,14 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Release History
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            ## v0.2.0 (9 May 2015)
         
     | 
| 
      
 4 
     | 
    
         
            +
            * Provide support for mutators which are similar to refactorers but produce multiple transformed programs
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            ## v0.1.1 (8 May 2015)
         
     | 
| 
      
 7 
     | 
    
         
            +
            * Update dependencies
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            ## v0.1.0 (6 May 2014)
         
     | 
| 
      
 10 
     | 
    
         
            +
            Provide support for:
         
     | 
| 
      
 11 
     | 
    
         
            +
            * A generic mechanism for specifying terms
         
     | 
| 
      
 12 
     | 
    
         
            +
            * Language-independent term matching and rewriting
         
     | 
| 
      
 13 
     | 
    
         
            +
            * Language-specific refactoring
         
     | 
| 
      
 14 
     | 
    
         
            +
            * A Ruby builder that enables program matching, rewriting and refactoring of Ruby programs.
         
     | 
    
        data/lib/metamorpher.rb
    CHANGED
    
    
| 
         @@ -1,29 +1,15 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require "metamorpher/builders/ast"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "metamorpher/builders/ruby/uppercase_rewriter"
         
     | 
| 
       2 
3 
     | 
    
         | 
| 
       3 
4 
     | 
    
         
             
            module Metamorpher
         
     | 
| 
       4 
5 
     | 
    
         
             
              module Builders
         
     | 
| 
       5 
6 
     | 
    
         
             
                module Ruby
         
     | 
| 
       6 
     | 
    
         
            -
                  class UppercaseConstantRewriter
         
     | 
| 
      
 7 
     | 
    
         
            +
                  class UppercaseConstantRewriter < UppercaseRewriter
         
     | 
| 
       7 
8 
     | 
    
         
             
                    include Metamorpher::Rewriter
         
     | 
| 
       8 
9 
     | 
    
         
             
                    include Metamorpher::Builders::AST
         
     | 
| 
       9 
10 
     | 
    
         | 
| 
       10 
11 
     | 
    
         
             
                    def pattern
         
     | 
| 
       11 
     | 
    
         
            -
                      builder.const(
         
     | 
| 
       12 
     | 
    
         
            -
                        builder.literal!(nil),
         
     | 
| 
       13 
     | 
    
         
            -
                        builder.VARIABLE_TO_BE { |v| v.name && v.name.to_s[/^[A-Z_]*$/] }
         
     | 
| 
       14 
     | 
    
         
            -
                      )
         
     | 
| 
       15 
     | 
    
         
            -
                    end
         
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
                    def replacement
         
     | 
| 
       18 
     | 
    
         
            -
                      builder.derivation!(:variable_to_be) do |variable_to_be, builder|
         
     | 
| 
       19 
     | 
    
         
            -
                        name = variable_to_be.name.to_s
         
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
                        if name.end_with?("_")
         
     | 
| 
       22 
     | 
    
         
            -
                          builder.greedy_variable! name.chomp("_").downcase.to_sym
         
     | 
| 
       23 
     | 
    
         
            -
                        else
         
     | 
| 
       24 
     | 
    
         
            -
                          builder.variable! name.downcase.to_sym
         
     | 
| 
       25 
     | 
    
         
            -
                        end
         
     | 
| 
       26 
     | 
    
         
            -
                      end
         
     | 
| 
      
 12 
     | 
    
         
            +
                      builder.const(builder.literal!(nil), super)
         
     | 
| 
       27 
13 
     | 
    
         
             
                    end
         
     | 
| 
       28 
14 
     | 
    
         
             
                  end
         
     | 
| 
       29 
15 
     | 
    
         
             
                end
         
     | 
| 
         @@ -0,0 +1,15 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "metamorpher/transformer/base"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "metamorpher/transformer/merger"
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Metamorpher
         
     | 
| 
      
 5 
     | 
    
         
            +
              module Mutator
         
     | 
| 
      
 6 
     | 
    
         
            +
                include Transformer::Base
         
     | 
| 
      
 7 
     | 
    
         
            +
                alias_method :mutate, :transform
         
     | 
| 
      
 8 
     | 
    
         
            +
                alias_method :mutate_file, :transform_file
         
     | 
| 
      
 9 
     | 
    
         
            +
                alias_method :mutate_files, :transform_files
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def merge(src, replacements, &block)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  replacements.map { |replacement| Transformer::Merger.new(src).merge(replacement, &block) }
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,47 +1,21 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require "metamorpher/ 
     | 
| 
       2 
     | 
    
         
            -
            require "metamorpher/ 
     | 
| 
       3 
     | 
    
         
            -
            require "metamorpher/rewriter/rule"
         
     | 
| 
       4 
     | 
    
         
            -
            require "metamorpher/drivers/ruby"
         
     | 
| 
      
 1 
     | 
    
         
            +
            require "metamorpher/transformer/base"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "metamorpher/transformer/merger"
         
     | 
| 
       5 
3 
     | 
    
         | 
| 
       6 
4 
     | 
    
         
             
            module Metamorpher
         
     | 
| 
       7 
5 
     | 
    
         
             
              module Refactorer
         
     | 
| 
       8 
     | 
    
         
            -
                 
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
                end
         
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
                def refactor_file(path, &block)
         
     | 
| 
       15 
     | 
    
         
            -
                  refactor(File.read(path), &block)
         
     | 
| 
       16 
     | 
    
         
            -
                end
         
     | 
| 
      
 6 
     | 
    
         
            +
                include Transformer::Base
         
     | 
| 
      
 7 
     | 
    
         
            +
                alias_method :refactor, :transform
         
     | 
| 
      
 8 
     | 
    
         
            +
                alias_method :refactor_file, :transform_file
         
     | 
| 
      
 9 
     | 
    
         
            +
                alias_method :refactor_files, :transform_files
         
     | 
| 
       17 
10 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
                def  
     | 
| 
       19 
     | 
    
         
            -
                   
     | 
| 
       20 
     | 
    
         
            -
                    changes = []
         
     | 
| 
       21 
     | 
    
         
            -
                    result[path] = refactor_file(path) { |change| changes << change }
         
     | 
| 
       22 
     | 
    
         
            -
                    block.call(path, result[path], changes) if block
         
     | 
| 
       23 
     | 
    
         
            -
                  end
         
     | 
| 
       24 
     | 
    
         
            -
                end
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
                def driver
         
     | 
| 
       27 
     | 
    
         
            -
                  @driver ||= Metamorpher::Drivers::Ruby.new
         
     | 
| 
      
 11 
     | 
    
         
            +
                def merge(src, replacements, &block)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  Transformer::Merger.new(src).merge(*replacements, &block)
         
     | 
| 
       28 
13 
     | 
    
         
             
                end
         
     | 
| 
       29 
14 
     | 
    
         | 
| 
       30 
15 
     | 
    
         
             
                private
         
     | 
| 
       31 
16 
     | 
    
         | 
| 
       32 
     | 
    
         
            -
                def  
     | 
| 
       33 
     | 
    
         
            -
                  [] 
     | 
| 
       34 
     | 
    
         
            -
                    rule.reduce(literal) do |original, rewritten|
         
     | 
| 
       35 
     | 
    
         
            -
                      original_position = driver.source_location_for(original)
         
     | 
| 
       36 
     | 
    
         
            -
                      original_code = src[original_position]
         
     | 
| 
       37 
     | 
    
         
            -
                      refactored_code = driver.unparse(rewritten)
         
     | 
| 
       38 
     | 
    
         
            -
                      replacements << Site.new(original_position, original_code, refactored_code)
         
     | 
| 
       39 
     | 
    
         
            -
                    end
         
     | 
| 
       40 
     | 
    
         
            -
                  end
         
     | 
| 
       41 
     | 
    
         
            -
                end
         
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
                def rule
         
     | 
| 
       44 
     | 
    
         
            -
                  @rule ||= Rewriter::Rule.new(pattern: pattern, replacement: replacement)
         
     | 
| 
      
 17 
     | 
    
         
            +
                def replacements
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @replacements ||= [replacement]
         
     | 
| 
       45 
19 
     | 
    
         
             
                end
         
     | 
| 
       46 
20 
     | 
    
         
             
              end
         
     | 
| 
       47 
21 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,51 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "metamorpher/transformer/merger"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "metamorpher/transformer/site"
         
     | 
| 
      
 3 
     | 
    
         
            +
            require "metamorpher/rewriter/rule"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "metamorpher/drivers/ruby"
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module Metamorpher
         
     | 
| 
      
 7 
     | 
    
         
            +
              module Transformer
         
     | 
| 
      
 8 
     | 
    
         
            +
                module Base
         
     | 
| 
      
 9 
     | 
    
         
            +
                  def transform(src, &block)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    literal = driver.parse(src)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    replacements = reduce_to_replacements(src, literal)
         
     | 
| 
      
 12 
     | 
    
         
            +
                    merge(src, replacements, &block)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  def transform_file(path, &block)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    transform(File.read(path), &block)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  def transform_files(paths, &block)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    paths.each_with_object({}) do |path, result|
         
     | 
| 
      
 21 
     | 
    
         
            +
                      changes = []
         
     | 
| 
      
 22 
     | 
    
         
            +
                      result[path] = transform_file(path) { |change| changes << change }
         
     | 
| 
      
 23 
     | 
    
         
            +
                      block.call(path, result[path], changes) if block
         
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  def driver
         
     | 
| 
      
 28 
     | 
    
         
            +
                    @driver ||= Metamorpher::Drivers::Ruby.new
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  private
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  def reduce_to_replacements(src, literal)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    [].tap do |replacements|
         
     | 
| 
      
 35 
     | 
    
         
            +
                      rules.each do |rule| # FIXME : change to inject?
         
     | 
| 
      
 36 
     | 
    
         
            +
                        rule.reduce(literal) do |original, rewritten|
         
     | 
| 
      
 37 
     | 
    
         
            +
                          original_position = driver.source_location_for(original)
         
     | 
| 
      
 38 
     | 
    
         
            +
                          original_code = src[original_position]
         
     | 
| 
      
 39 
     | 
    
         
            +
                          transformed_code = driver.unparse(rewritten)
         
     | 
| 
      
 40 
     | 
    
         
            +
                          replacements << Site.new(original_position, original_code, transformed_code)
         
     | 
| 
      
 41 
     | 
    
         
            +
                        end
         
     | 
| 
      
 42 
     | 
    
         
            +
                      end
         
     | 
| 
      
 43 
     | 
    
         
            +
                    end
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  def rules
         
     | 
| 
      
 47 
     | 
    
         
            +
                    @rules ||= replacements.map { |r| Rewriter::Rule.new(pattern: pattern, replacement: r) }
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require "attributable"
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module Metamorpher
         
     | 
| 
       4 
     | 
    
         
            -
              module  
     | 
| 
      
 4 
     | 
    
         
            +
              module Transformer
         
     | 
| 
       5 
5 
     | 
    
         
             
                Site = Struct.new(:original_position, :original_code, :refactored_code) do
         
     | 
| 
       6 
6 
     | 
    
         
             
                  def slide(offset)
         
     | 
| 
       7 
7 
     | 
    
         
             
                    new_position = (original_position.begin + offset)..(original_position.end + offset)
         
     | 
    
        data/lib/metamorpher/version.rb
    CHANGED
    
    
| 
         @@ -0,0 +1,215 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "metamorpher"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "tempfile"
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            describe "Mutator" do
         
     | 
| 
      
 5 
     | 
    
         
            +
              describe "for Ruby" do
         
     | 
| 
      
 6 
     | 
    
         
            +
                class LessThanMutator
         
     | 
| 
      
 7 
     | 
    
         
            +
                  include Metamorpher::Mutator
         
     | 
| 
      
 8 
     | 
    
         
            +
                  include Metamorpher::Builders::Ruby
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def pattern
         
     | 
| 
      
 11 
     | 
    
         
            +
                    builder.build("A < B")
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def replacements
         
     | 
| 
      
 15 
     | 
    
         
            +
                    builder.build_all("A > B", "A == B")
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                subject { LessThanMutator.new }
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                let(:mutatable) do
         
     | 
| 
      
 22 
     | 
    
         
            +
                  "def compare\n" \
         
     | 
| 
      
 23 
     | 
    
         
            +
                  "  foo < bar\n" \
         
     | 
| 
      
 24 
     | 
    
         
            +
                  "  bar < baz\n" \
         
     | 
| 
      
 25 
     | 
    
         
            +
                  "end"
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                let(:mutated) do
         
     | 
| 
      
 29 
     | 
    
         
            +
                  [
         
     | 
| 
      
 30 
     | 
    
         
            +
                    "def compare\n" \
         
     | 
| 
      
 31 
     | 
    
         
            +
                    "  foo > bar\n" \
         
     | 
| 
      
 32 
     | 
    
         
            +
                    "  bar < baz\n" \
         
     | 
| 
      
 33 
     | 
    
         
            +
                    "end",
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                    "def compare\n" \
         
     | 
| 
      
 36 
     | 
    
         
            +
                    "  foo < bar\n" \
         
     | 
| 
      
 37 
     | 
    
         
            +
                    "  bar > baz\n" \
         
     | 
| 
      
 38 
     | 
    
         
            +
                    "end",
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                    "def compare\n" \
         
     | 
| 
      
 41 
     | 
    
         
            +
                    "  foo == bar\n" \
         
     | 
| 
      
 42 
     | 
    
         
            +
                    "  bar < baz\n" \
         
     | 
| 
      
 43 
     | 
    
         
            +
                    "end",
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                    "def compare\n" \
         
     | 
| 
      
 46 
     | 
    
         
            +
                    "  foo < bar\n" \
         
     | 
| 
      
 47 
     | 
    
         
            +
                    "  bar == baz\n" \
         
     | 
| 
      
 48 
     | 
    
         
            +
                    "end"
         
     | 
| 
      
 49 
     | 
    
         
            +
                  ]
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                let(:not_mutatable) { "foo == bar" }
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                describe "by calling mutate" do
         
     | 
| 
      
 55 
     | 
    
         
            +
                  describe "for code that can be mutated"do
         
     | 
| 
      
 56 
     | 
    
         
            +
                    it "should return the mutated code" do
         
     | 
| 
      
 57 
     | 
    
         
            +
                      expect(subject.mutate(mutatable)).to eq(mutated)
         
     | 
| 
      
 58 
     | 
    
         
            +
                    end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                    it "should yield for each mutation site" do
         
     | 
| 
      
 61 
     | 
    
         
            +
                      expect { |b| subject.mutate(mutatable, &b) }.to yield_successive_args(
         
     | 
| 
      
 62 
     | 
    
         
            +
                        site_for(14..22, "foo < bar", "foo > bar"),
         
     | 
| 
      
 63 
     | 
    
         
            +
                        site_for(26..34, "bar < baz", "bar > baz"),
         
     | 
| 
      
 64 
     | 
    
         
            +
                        site_for(14..22, "foo < bar", "foo == bar"),
         
     | 
| 
      
 65 
     | 
    
         
            +
                        site_for(26..34, "bar < baz", "bar == baz")
         
     | 
| 
      
 66 
     | 
    
         
            +
                      )
         
     | 
| 
      
 67 
     | 
    
         
            +
                    end
         
     | 
| 
      
 68 
     | 
    
         
            +
                  end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                  describe "for code that cannot be mutated" do
         
     | 
| 
      
 71 
     | 
    
         
            +
                    it "should return no mutants" do
         
     | 
| 
      
 72 
     | 
    
         
            +
                      expect(subject.mutate(not_mutatable)).to eq([])
         
     | 
| 
      
 73 
     | 
    
         
            +
                    end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                    it "should not yield when there are no mutants" do
         
     | 
| 
      
 76 
     | 
    
         
            +
                      expect { |b| subject.mutate(not_mutatable, &b) }.not_to yield_control
         
     | 
| 
      
 77 
     | 
    
         
            +
                    end
         
     | 
| 
      
 78 
     | 
    
         
            +
                  end
         
     | 
| 
      
 79 
     | 
    
         
            +
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                describe "mutate_file" do
         
     | 
| 
      
 82 
     | 
    
         
            +
                  describe "for code that can be mutated" do
         
     | 
| 
      
 83 
     | 
    
         
            +
                    let(:mutatable_file) { create_temporary_ruby_file("mutatable", mutatable) }
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                    it "should return the mutated code" do
         
     | 
| 
      
 86 
     | 
    
         
            +
                      expect(subject.mutate_file(mutatable_file)).to eq(mutated)
         
     | 
| 
      
 87 
     | 
    
         
            +
                    end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                    it "should yield for each mutating site" do
         
     | 
| 
      
 90 
     | 
    
         
            +
                      expect { |b| subject.mutate_file(mutatable_file, &b) }.to yield_successive_args(
         
     | 
| 
      
 91 
     | 
    
         
            +
                        site_for(14..22, "foo < bar", "foo > bar"),
         
     | 
| 
      
 92 
     | 
    
         
            +
                        site_for(26..34, "bar < baz", "bar > baz"),
         
     | 
| 
      
 93 
     | 
    
         
            +
                        site_for(14..22, "foo < bar", "foo == bar"),
         
     | 
| 
      
 94 
     | 
    
         
            +
                        site_for(26..34, "bar < baz", "bar == baz")
         
     | 
| 
      
 95 
     | 
    
         
            +
                      )
         
     | 
| 
      
 96 
     | 
    
         
            +
                    end
         
     | 
| 
      
 97 
     | 
    
         
            +
                  end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                  describe "for code that cannot be mutated" do
         
     | 
| 
      
 100 
     | 
    
         
            +
                    let(:not_mutatable_file) do
         
     | 
| 
      
 101 
     | 
    
         
            +
                      create_temporary_ruby_file("not_mutatable", not_mutatable)
         
     | 
| 
      
 102 
     | 
    
         
            +
                    end
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                    it "should return no mutants" do
         
     | 
| 
      
 105 
     | 
    
         
            +
                      expect(subject.mutate_file(not_mutatable_file)).to eq([])
         
     | 
| 
      
 106 
     | 
    
         
            +
                    end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                    it "should not yield when there are no mutating site" do
         
     | 
| 
      
 109 
     | 
    
         
            +
                      expect { |b| subject.mutate_file(not_mutatable_file, &b) }.not_to yield_control
         
     | 
| 
      
 110 
     | 
    
         
            +
                    end
         
     | 
| 
      
 111 
     | 
    
         
            +
                  end
         
     | 
| 
      
 112 
     | 
    
         
            +
                end
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                describe "mutate_files" do
         
     | 
| 
      
 115 
     | 
    
         
            +
                  let(:mutatable_file) { create_temporary_ruby_file("mutatable", mutatable) }
         
     | 
| 
      
 116 
     | 
    
         
            +
                  let(:clone_of_mutatable_file) { create_temporary_ruby_file("mutatable", mutatable) }
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                  let(:different_mutating_sites_file) do
         
     | 
| 
      
 119 
     | 
    
         
            +
                    create_temporary_ruby_file(
         
     | 
| 
      
 120 
     | 
    
         
            +
                      "differently_mutatable",
         
     | 
| 
      
 121 
     | 
    
         
            +
                      "result = foo < bar"
         
     | 
| 
      
 122 
     | 
    
         
            +
                    )
         
     | 
| 
      
 123 
     | 
    
         
            +
                  end
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                  let(:not_mutatable_file) do
         
     | 
| 
      
 126 
     | 
    
         
            +
                    create_temporary_ruby_file(
         
     | 
| 
      
 127 
     | 
    
         
            +
                      "not_mutatable",
         
     | 
| 
      
 128 
     | 
    
         
            +
                      "nothing_to_see_here = 42"
         
     | 
| 
      
 129 
     | 
    
         
            +
                    )
         
     | 
| 
      
 130 
     | 
    
         
            +
                  end
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                  let(:files) do
         
     | 
| 
      
 133 
     | 
    
         
            +
                    [
         
     | 
| 
      
 134 
     | 
    
         
            +
                      mutatable_file,
         
     | 
| 
      
 135 
     | 
    
         
            +
                      clone_of_mutatable_file,
         
     | 
| 
      
 136 
     | 
    
         
            +
                      different_mutating_sites_file,
         
     | 
| 
      
 137 
     | 
    
         
            +
                      not_mutatable_file
         
     | 
| 
      
 138 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 139 
     | 
    
         
            +
                  end
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                  it "should return a map of the paths and mutated code" do
         
     | 
| 
      
 142 
     | 
    
         
            +
                    mutated_files = {
         
     | 
| 
      
 143 
     | 
    
         
            +
                      mutatable_file => mutated,
         
     | 
| 
      
 144 
     | 
    
         
            +
                      clone_of_mutatable_file => mutated,
         
     | 
| 
      
 145 
     | 
    
         
            +
                      different_mutating_sites_file => ["result = foo > bar", "result = foo == bar"],
         
     | 
| 
      
 146 
     | 
    
         
            +
                      not_mutatable_file => []
         
     | 
| 
      
 147 
     | 
    
         
            +
                    }
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
                    expect(subject.mutate_files(files)).to eq(mutated_files)
         
     | 
| 
      
 150 
     | 
    
         
            +
                  end
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                  it "should yield for each file" do
         
     | 
| 
      
 153 
     | 
    
         
            +
                    mutatable_file_details = [
         
     | 
| 
      
 154 
     | 
    
         
            +
                      mutatable_file,
         
     | 
| 
      
 155 
     | 
    
         
            +
                      mutated,
         
     | 
| 
      
 156 
     | 
    
         
            +
                      [
         
     | 
| 
      
 157 
     | 
    
         
            +
                        site_for(14..22, "foo < bar", "foo > bar"),
         
     | 
| 
      
 158 
     | 
    
         
            +
                        site_for(26..34, "bar < baz", "bar > baz"),
         
     | 
| 
      
 159 
     | 
    
         
            +
                        site_for(14..22, "foo < bar", "foo == bar"),
         
     | 
| 
      
 160 
     | 
    
         
            +
                        site_for(26..34, "bar < baz", "bar == baz")
         
     | 
| 
      
 161 
     | 
    
         
            +
                      ]
         
     | 
| 
      
 162 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
                    clone_of_mutatable_file_details = [
         
     | 
| 
      
 165 
     | 
    
         
            +
                      clone_of_mutatable_file,
         
     | 
| 
      
 166 
     | 
    
         
            +
                      mutated,
         
     | 
| 
      
 167 
     | 
    
         
            +
                      [
         
     | 
| 
      
 168 
     | 
    
         
            +
                        site_for(14..22, "foo < bar", "foo > bar"),
         
     | 
| 
      
 169 
     | 
    
         
            +
                        site_for(26..34, "bar < baz", "bar > baz"),
         
     | 
| 
      
 170 
     | 
    
         
            +
                        site_for(14..22, "foo < bar", "foo == bar"),
         
     | 
| 
      
 171 
     | 
    
         
            +
                        site_for(26..34, "bar < baz", "bar == baz")
         
     | 
| 
      
 172 
     | 
    
         
            +
                      ]
         
     | 
| 
      
 173 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
                    different_mutating_sites_file_details = [
         
     | 
| 
      
 176 
     | 
    
         
            +
                      different_mutating_sites_file,
         
     | 
| 
      
 177 
     | 
    
         
            +
                      ["result = foo > bar", "result = foo == bar"],
         
     | 
| 
      
 178 
     | 
    
         
            +
                      [
         
     | 
| 
      
 179 
     | 
    
         
            +
                        site_for(9..17, "foo < bar", "foo > bar"),
         
     | 
| 
      
 180 
     | 
    
         
            +
                        site_for(9..17, "foo < bar", "foo == bar")
         
     | 
| 
      
 181 
     | 
    
         
            +
                      ]
         
     | 
| 
      
 182 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 183 
     | 
    
         
            +
             
     | 
| 
      
 184 
     | 
    
         
            +
                    not_mutatable_file_details = [
         
     | 
| 
      
 185 
     | 
    
         
            +
                      not_mutatable_file,
         
     | 
| 
      
 186 
     | 
    
         
            +
                      [],
         
     | 
| 
      
 187 
     | 
    
         
            +
                      []
         
     | 
| 
      
 188 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
      
 190 
     | 
    
         
            +
                    summary = []
         
     | 
| 
      
 191 
     | 
    
         
            +
                    subject.mutate_files(files) { |*args| summary << args }
         
     | 
| 
      
 192 
     | 
    
         
            +
             
     | 
| 
      
 193 
     | 
    
         
            +
                    expect(summary[0]).to eq(mutatable_file_details)
         
     | 
| 
      
 194 
     | 
    
         
            +
                    expect(summary[1]).to eq(clone_of_mutatable_file_details)
         
     | 
| 
      
 195 
     | 
    
         
            +
                    expect(summary[2]).to eq(different_mutating_sites_file_details)
         
     | 
| 
      
 196 
     | 
    
         
            +
                    expect(summary[3]).to eq(not_mutatable_file_details)
         
     | 
| 
      
 197 
     | 
    
         
            +
                  end
         
     | 
| 
      
 198 
     | 
    
         
            +
                end
         
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
      
 200 
     | 
    
         
            +
                def site_for(original_position, original_code, mutated_code)
         
     | 
| 
      
 201 
     | 
    
         
            +
                  Metamorpher::Transformer::Site.new(
         
     | 
| 
      
 202 
     | 
    
         
            +
                    original_position,
         
     | 
| 
      
 203 
     | 
    
         
            +
                    original_code,
         
     | 
| 
      
 204 
     | 
    
         
            +
                    mutated_code
         
     | 
| 
      
 205 
     | 
    
         
            +
                  )
         
     | 
| 
      
 206 
     | 
    
         
            +
                end
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
                def create_temporary_ruby_file(filename, contents)
         
     | 
| 
      
 209 
     | 
    
         
            +
                  Tempfile.new([filename, ".rb"]).tap do |tempfile|
         
     | 
| 
      
 210 
     | 
    
         
            +
                    tempfile.write(contents)
         
     | 
| 
      
 211 
     | 
    
         
            +
                    tempfile.close
         
     | 
| 
      
 212 
     | 
    
         
            +
                  end.path
         
     | 
| 
      
 213 
     | 
    
         
            +
                end
         
     | 
| 
      
 214 
     | 
    
         
            +
              end
         
     | 
| 
      
 215 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,8 +1,8 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require "metamorpher/ 
     | 
| 
       2 
     | 
    
         
            -
            require "metamorpher/ 
     | 
| 
      
 1 
     | 
    
         
            +
            require "metamorpher/transformer/merger"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "metamorpher/transformer/site"
         
     | 
| 
       3 
3 
     | 
    
         | 
| 
       4 
4 
     | 
    
         
             
            module Metamorpher
         
     | 
| 
       5 
     | 
    
         
            -
              module  
     | 
| 
      
 5 
     | 
    
         
            +
              module Transformer
         
     | 
| 
       6 
6 
     | 
    
         
             
                describe Merger do
         
     | 
| 
       7 
7 
     | 
    
         
             
                  let(:original) { "The quick brown fox jumps over the lazy dog." }
         
     | 
| 
       8 
8 
     | 
    
         
             
                  subject { Merger.new(original) }
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: metamorpher
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.2.0
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Louis Rose
         
     | 
| 
         @@ -138,6 +138,7 @@ files: 
     | 
|
| 
       138 
138 
     | 
    
         
             
            - Gemfile
         
     | 
| 
       139 
139 
     | 
    
         
             
            - LICENSE.txt
         
     | 
| 
       140 
140 
     | 
    
         
             
            - README.md
         
     | 
| 
      
 141 
     | 
    
         
            +
            - RELEASES.md
         
     | 
| 
       141 
142 
     | 
    
         
             
            - Rakefile
         
     | 
| 
       142 
143 
     | 
    
         
             
            - examples/refactorings/rails/where_first/app.rb
         
     | 
| 
       143 
144 
     | 
    
         
             
            - examples/refactorings/rails/where_first/refactorers/refactor_where_first_mocks.rb
         
     | 
| 
         @@ -166,9 +167,8 @@ files: 
     | 
|
| 
       166 
167 
     | 
    
         
             
            - lib/metamorpher/matcher/match.rb
         
     | 
| 
       167 
168 
     | 
    
         
             
            - lib/metamorpher/matcher/matching.rb
         
     | 
| 
       168 
169 
     | 
    
         
             
            - lib/metamorpher/matcher/no_match.rb
         
     | 
| 
      
 170 
     | 
    
         
            +
            - lib/metamorpher/mutator.rb
         
     | 
| 
       169 
171 
     | 
    
         
             
            - lib/metamorpher/refactorer.rb
         
     | 
| 
       170 
     | 
    
         
            -
            - lib/metamorpher/refactorer/merger.rb
         
     | 
| 
       171 
     | 
    
         
            -
            - lib/metamorpher/refactorer/site.rb
         
     | 
| 
       172 
172 
     | 
    
         
             
            - lib/metamorpher/rewriter.rb
         
     | 
| 
       173 
173 
     | 
    
         
             
            - lib/metamorpher/rewriter/replacement.rb
         
     | 
| 
       174 
174 
     | 
    
         
             
            - lib/metamorpher/rewriter/rule.rb
         
     | 
| 
         @@ -179,6 +179,9 @@ files: 
     | 
|
| 
       179 
179 
     | 
    
         
             
            - lib/metamorpher/terms/literal.rb
         
     | 
| 
       180 
180 
     | 
    
         
             
            - lib/metamorpher/terms/term.rb
         
     | 
| 
       181 
181 
     | 
    
         
             
            - lib/metamorpher/terms/variable.rb
         
     | 
| 
      
 182 
     | 
    
         
            +
            - lib/metamorpher/transformer/base.rb
         
     | 
| 
      
 183 
     | 
    
         
            +
            - lib/metamorpher/transformer/merger.rb
         
     | 
| 
      
 184 
     | 
    
         
            +
            - lib/metamorpher/transformer/site.rb
         
     | 
| 
       182 
185 
     | 
    
         
             
            - lib/metamorpher/version.rb
         
     | 
| 
       183 
186 
     | 
    
         
             
            - lib/metamorpher/visitable/visitable.rb
         
     | 
| 
       184 
187 
     | 
    
         
             
            - lib/metamorpher/visitable/visitor.rb
         
     | 
| 
         @@ -187,6 +190,7 @@ files: 
     | 
|
| 
       187 
190 
     | 
    
         
             
            - spec/integration/ast/matcher_spec.rb
         
     | 
| 
       188 
191 
     | 
    
         
             
            - spec/integration/ast/rewriter_spec.rb
         
     | 
| 
       189 
192 
     | 
    
         
             
            - spec/integration/ruby/builder_spec.rb
         
     | 
| 
      
 193 
     | 
    
         
            +
            - spec/integration/ruby/mutator_spec.rb
         
     | 
| 
       190 
194 
     | 
    
         
             
            - spec/integration/ruby/refactorer_spec.rb
         
     | 
| 
       191 
195 
     | 
    
         
             
            - spec/spec_helper.rb
         
     | 
| 
       192 
196 
     | 
    
         
             
            - spec/support/helpers/silence_stream.rb
         
     | 
| 
         @@ -204,14 +208,14 @@ files: 
     | 
|
| 
       204 
208 
     | 
    
         
             
            - spec/unit/drivers/ruby_spec.rb
         
     | 
| 
       205 
209 
     | 
    
         
             
            - spec/unit/matcher/matching_spec.rb
         
     | 
| 
       206 
210 
     | 
    
         
             
            - spec/unit/metamorpher_spec.rb
         
     | 
| 
       207 
     | 
    
         
            -
            - spec/unit/refactorer/merger_spec.rb
         
     | 
| 
       208 
     | 
    
         
            -
            - spec/unit/refactorer/site_spec.rb
         
     | 
| 
       209 
211 
     | 
    
         
             
            - spec/unit/rewriter/replacement_spec.rb
         
     | 
| 
       210 
212 
     | 
    
         
             
            - spec/unit/rewriter/substitution_spec.rb
         
     | 
| 
       211 
213 
     | 
    
         
             
            - spec/unit/rewriter/traverser_spec.rb
         
     | 
| 
       212 
214 
     | 
    
         
             
            - spec/unit/support/map_at_spec.rb
         
     | 
| 
       213 
215 
     | 
    
         
             
            - spec/unit/terms/literal_spec.rb
         
     | 
| 
       214 
216 
     | 
    
         
             
            - spec/unit/terms/term_spec.rb
         
     | 
| 
      
 217 
     | 
    
         
            +
            - spec/unit/transformer/merger_spec.rb
         
     | 
| 
      
 218 
     | 
    
         
            +
            - spec/unit/transformer/site_spec.rb
         
     | 
| 
       215 
219 
     | 
    
         
             
            - spec/unit/visitable/visitor_spec.rb
         
     | 
| 
       216 
220 
     | 
    
         
             
            homepage: https://github.com/mutiny/metamorpher
         
     | 
| 
       217 
221 
     | 
    
         
             
            licenses:
         
     | 
| 
         @@ -242,6 +246,7 @@ test_files: 
     | 
|
| 
       242 
246 
     | 
    
         
             
            - spec/integration/ast/matcher_spec.rb
         
     | 
| 
       243 
247 
     | 
    
         
             
            - spec/integration/ast/rewriter_spec.rb
         
     | 
| 
       244 
248 
     | 
    
         
             
            - spec/integration/ruby/builder_spec.rb
         
     | 
| 
      
 249 
     | 
    
         
            +
            - spec/integration/ruby/mutator_spec.rb
         
     | 
| 
       245 
250 
     | 
    
         
             
            - spec/integration/ruby/refactorer_spec.rb
         
     | 
| 
       246 
251 
     | 
    
         
             
            - spec/spec_helper.rb
         
     | 
| 
       247 
252 
     | 
    
         
             
            - spec/support/helpers/silence_stream.rb
         
     | 
| 
         @@ -259,12 +264,12 @@ test_files: 
     | 
|
| 
       259 
264 
     | 
    
         
             
            - spec/unit/drivers/ruby_spec.rb
         
     | 
| 
       260 
265 
     | 
    
         
             
            - spec/unit/matcher/matching_spec.rb
         
     | 
| 
       261 
266 
     | 
    
         
             
            - spec/unit/metamorpher_spec.rb
         
     | 
| 
       262 
     | 
    
         
            -
            - spec/unit/refactorer/merger_spec.rb
         
     | 
| 
       263 
     | 
    
         
            -
            - spec/unit/refactorer/site_spec.rb
         
     | 
| 
       264 
267 
     | 
    
         
             
            - spec/unit/rewriter/replacement_spec.rb
         
     | 
| 
       265 
268 
     | 
    
         
             
            - spec/unit/rewriter/substitution_spec.rb
         
     | 
| 
       266 
269 
     | 
    
         
             
            - spec/unit/rewriter/traverser_spec.rb
         
     | 
| 
       267 
270 
     | 
    
         
             
            - spec/unit/support/map_at_spec.rb
         
     | 
| 
       268 
271 
     | 
    
         
             
            - spec/unit/terms/literal_spec.rb
         
     | 
| 
       269 
272 
     | 
    
         
             
            - spec/unit/terms/term_spec.rb
         
     | 
| 
      
 273 
     | 
    
         
            +
            - spec/unit/transformer/merger_spec.rb
         
     | 
| 
      
 274 
     | 
    
         
            +
            - spec/unit/transformer/site_spec.rb
         
     | 
| 
       270 
275 
     | 
    
         
             
            - spec/unit/visitable/visitor_spec.rb
         
     |