rubocop-performance 1.6.1 → 1.7.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/config/default.yml +50 -1
 - data/lib/rubocop/cop/mixin/sort_block.rb +28 -0
 - data/lib/rubocop/cop/performance/ancestors_include.rb +45 -0
 - data/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb +43 -0
 - data/lib/rubocop/cop/performance/io_readlines.rb +127 -0
 - data/lib/rubocop/cop/performance/range_include.rb +9 -7
 - data/lib/rubocop/cop/performance/redundant_sort_block.rb +53 -0
 - data/lib/rubocop/cop/performance/redundant_string_chars.rb +137 -0
 - data/lib/rubocop/cop/performance/reverse_first.rb +78 -0
 - data/lib/rubocop/cop/performance/size.rb +35 -37
 - data/lib/rubocop/cop/performance/sort_reverse.rb +54 -0
 - data/lib/rubocop/cop/performance/squeeze.rb +70 -0
 - data/lib/rubocop/cop/performance/string_include.rb +57 -0
 - data/lib/rubocop/cop/performance_cops.rb +10 -0
 - data/lib/rubocop/performance/version.rb +1 -1
 - metadata +15 -5
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 5be372d62d20424e05201d4b78bb06bf19fc707d845d6b799599ba72958f72b7
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 87c59d78e37de238add70195fa26c95d31b23eb3065695f443a1694d3acf9145
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: d6caf119ca1a8b11d829ed555f3a0653a1087d3a3ee3be078460c9ecfb5a5fb236a7abf2c058f57647d4f74dffccc66aebcf4d330f5a6a5bd5deaa12a8fea480
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: d8a6e634d4453300d24e5869bffa690457d07048b1e2978cc00dbc930c40e2dc80789a6faa95823e63414e5c579f8784cbe4f743607e2fd9598cf478aa1801ed
         
     | 
    
        data/config/default.yml
    CHANGED
    
    | 
         @@ -1,5 +1,16 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # This is the default configuration file.
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            Performance/AncestorsInclude:
         
     | 
| 
      
 4 
     | 
    
         
            +
              Description: 'Use `A <= B` instead of `A.ancestors.include?(B)`.'
         
     | 
| 
      
 5 
     | 
    
         
            +
              Reference: 'https://github.com/JuanitoFatas/fast-ruby#ancestorsinclude-vs--code'
         
     | 
| 
      
 6 
     | 
    
         
            +
              Enabled: 'pending'
         
     | 
| 
      
 7 
     | 
    
         
            +
              VersionAdded: '1.7'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            Performance/BigDecimalWithNumericArgument:
         
     | 
| 
      
 10 
     | 
    
         
            +
              Description: 'Convert numeric argument to string before passing to BigDecimal.'
         
     | 
| 
      
 11 
     | 
    
         
            +
              Enabled: 'pending'
         
     | 
| 
      
 12 
     | 
    
         
            +
              VersionAdded: '1.7'
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
       3 
14 
     | 
    
         
             
            Performance/BindCall:
         
     | 
| 
       4 
15 
     | 
    
         
             
              Description: 'Use `bind_call(obj, args, ...)` instead of `bind(obj).call(args, ...)`.'
         
     | 
| 
       5 
16 
     | 
    
         
             
              Enabled: true
         
     | 
| 
         @@ -131,6 +142,12 @@ Performance/InefficientHashSearch: 
     | 
|
| 
       131 
142 
     | 
    
         
             
              VersionAdded: '0.56'
         
     | 
| 
       132 
143 
     | 
    
         
             
              Safe: false
         
     | 
| 
       133 
144 
     | 
    
         | 
| 
      
 145 
     | 
    
         
            +
            Performance/IoReadlines:
         
     | 
| 
      
 146 
     | 
    
         
            +
              Description: 'Use `IO.each_line` (`IO#each_line`) instead of `IO.readlines` (`IO#readlines`).'
         
     | 
| 
      
 147 
     | 
    
         
            +
              Reference: 'https://docs.gitlab.com/ee/development/performance.html#reading-from-files-and-other-data-sources'
         
     | 
| 
      
 148 
     | 
    
         
            +
              Enabled: false
         
     | 
| 
      
 149 
     | 
    
         
            +
              VersionAdded: '1.7'
         
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
       134 
151 
     | 
    
         
             
            Performance/OpenStruct:
         
     | 
| 
       135 
152 
     | 
    
         
             
              Description: 'Use `Struct` instead of `OpenStruct`.'
         
     | 
| 
       136 
153 
     | 
    
         
             
              Enabled: false
         
     | 
| 
         @@ -138,10 +155,11 @@ Performance/OpenStruct: 
     | 
|
| 
       138 
155 
     | 
    
         
             
              Safe: false
         
     | 
| 
       139 
156 
     | 
    
         | 
| 
       140 
157 
     | 
    
         
             
            Performance/RangeInclude:
         
     | 
| 
       141 
     | 
    
         
            -
              Description: 'Use `Range#cover?` instead of `Range#include 
     | 
| 
      
 158 
     | 
    
         
            +
              Description: 'Use `Range#cover?` instead of `Range#include?` (or `Range#member?`).'
         
     | 
| 
       142 
159 
     | 
    
         
             
              Reference: 'https://github.com/JuanitoFatas/fast-ruby#cover-vs-include-code'
         
     | 
| 
       143 
160 
     | 
    
         
             
              Enabled: true
         
     | 
| 
       144 
161 
     | 
    
         
             
              VersionAdded: '0.36'
         
     | 
| 
      
 162 
     | 
    
         
            +
              VersionChanged: '1.7'
         
     | 
| 
       145 
163 
     | 
    
         
             
              Safe: false
         
     | 
| 
       146 
164 
     | 
    
         | 
| 
       147 
165 
     | 
    
         
             
            Performance/RedundantBlockCall:
         
     | 
| 
         @@ -165,6 +183,16 @@ Performance/RedundantMerge: 
     | 
|
| 
       165 
183 
     | 
    
         
             
              # Max number of key-value pairs to consider an offense
         
     | 
| 
       166 
184 
     | 
    
         
             
              MaxKeyValuePairs: 2
         
     | 
| 
       167 
185 
     | 
    
         | 
| 
      
 186 
     | 
    
         
            +
            Performance/RedundantSortBlock:
         
     | 
| 
      
 187 
     | 
    
         
            +
              Description: 'Use `sort` instead of `sort { |a, b| a <=> b }`.'
         
     | 
| 
      
 188 
     | 
    
         
            +
              Enabled: 'pending'
         
     | 
| 
      
 189 
     | 
    
         
            +
              VersionAdded: '1.7'
         
     | 
| 
      
 190 
     | 
    
         
            +
             
     | 
| 
      
 191 
     | 
    
         
            +
            Performance/RedundantStringChars:
         
     | 
| 
      
 192 
     | 
    
         
            +
              Description: 'Checks for redundant `String#chars`.'
         
     | 
| 
      
 193 
     | 
    
         
            +
              Enabled: 'pending'
         
     | 
| 
      
 194 
     | 
    
         
            +
              VersionAdded: '1.7'
         
     | 
| 
      
 195 
     | 
    
         
            +
             
     | 
| 
       168 
196 
     | 
    
         
             
            Performance/RegexpMatch:
         
     | 
| 
       169 
197 
     | 
    
         
             
              Description: >-
         
     | 
| 
       170 
198 
     | 
    
         
             
                              Use `match?` instead of `Regexp#match`, `String#match`, `Symbol#match`,
         
     | 
| 
         @@ -179,6 +207,11 @@ Performance/ReverseEach: 
     | 
|
| 
       179 
207 
     | 
    
         
             
              Enabled: true
         
     | 
| 
       180 
208 
     | 
    
         
             
              VersionAdded: '0.30'
         
     | 
| 
       181 
209 
     | 
    
         | 
| 
      
 210 
     | 
    
         
            +
            Performance/ReverseFirst:
         
     | 
| 
      
 211 
     | 
    
         
            +
              Description: 'Use `last(n).reverse` instead of `reverse.first(n)`.'
         
     | 
| 
      
 212 
     | 
    
         
            +
              Enabled: 'pending'
         
     | 
| 
      
 213 
     | 
    
         
            +
              VersionAdded: '1.7'
         
     | 
| 
      
 214 
     | 
    
         
            +
             
     | 
| 
       182 
215 
     | 
    
         
             
            Performance/Size:
         
     | 
| 
       183 
216 
     | 
    
         
             
              Description: >-
         
     | 
| 
       184 
217 
     | 
    
         
             
                              Use `size` instead of `count` for counting
         
     | 
| 
         @@ -187,6 +220,17 @@ Performance/Size: 
     | 
|
| 
       187 
220 
     | 
    
         
             
              Enabled: true
         
     | 
| 
       188 
221 
     | 
    
         
             
              VersionAdded: '0.30'
         
     | 
| 
       189 
222 
     | 
    
         | 
| 
      
 223 
     | 
    
         
            +
            Performance/SortReverse:
         
     | 
| 
      
 224 
     | 
    
         
            +
              Description: 'Use `sort.reverse` instead of `sort { |a, b| b <=> a }`.'
         
     | 
| 
      
 225 
     | 
    
         
            +
              Enabled: 'pending'
         
     | 
| 
      
 226 
     | 
    
         
            +
              VersionAdded: '1.7'
         
     | 
| 
      
 227 
     | 
    
         
            +
             
     | 
| 
      
 228 
     | 
    
         
            +
            Performance/Squeeze:
         
     | 
| 
      
 229 
     | 
    
         
            +
              Description: "Use `squeeze('a')` instead of `gsub(/a+/, 'a')`."
         
     | 
| 
      
 230 
     | 
    
         
            +
              Reference: 'https://github.com/JuanitoFatas/fast-ruby#remove-extra-spaces-or-other-contiguous-characters-code'
         
     | 
| 
      
 231 
     | 
    
         
            +
              Enabled: 'pending'
         
     | 
| 
      
 232 
     | 
    
         
            +
              VersionAdded: '1.7'
         
     | 
| 
      
 233 
     | 
    
         
            +
             
     | 
| 
       190 
234 
     | 
    
         
             
            Performance/StartWith:
         
     | 
| 
       191 
235 
     | 
    
         
             
              Description: 'Use `start_with?` instead of a regex match anchored to the beginning of a string.'
         
     | 
| 
       192 
236 
     | 
    
         
             
              Reference: 'https://github.com/JuanitoFatas/fast-ruby#stringmatch-vs-stringstart_withstringend_with-code-start-code-end'
         
     | 
| 
         @@ -200,6 +244,11 @@ Performance/StartWith: 
     | 
|
| 
       200 
244 
     | 
    
         
             
              VersionAdded: '0.36'
         
     | 
| 
       201 
245 
     | 
    
         
             
              VersionChanged: '1.6'
         
     | 
| 
       202 
246 
     | 
    
         | 
| 
      
 247 
     | 
    
         
            +
            Performance/StringInclude:
         
     | 
| 
      
 248 
     | 
    
         
            +
              Description: 'Use `String#include?` instead of a regex match with literal-only pattern.'
         
     | 
| 
      
 249 
     | 
    
         
            +
              Enabled: 'pending'
         
     | 
| 
      
 250 
     | 
    
         
            +
              VersionAdded: '1.7'
         
     | 
| 
      
 251 
     | 
    
         
            +
             
     | 
| 
       203 
252 
     | 
    
         
             
            Performance/StringReplacement:
         
     | 
| 
       204 
253 
     | 
    
         
             
              Description: >-
         
     | 
| 
       205 
254 
     | 
    
         
             
                              Use `tr` instead of `gsub` when you are replacing the same
         
     | 
| 
         @@ -0,0 +1,28 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module RuboCop
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Cop
         
     | 
| 
      
 5 
     | 
    
         
            +
                # Common functionality for cops checking `Enumerable#sort` blocks.
         
     | 
| 
      
 6 
     | 
    
         
            +
                module SortBlock
         
     | 
| 
      
 7 
     | 
    
         
            +
                  extend NodePattern::Macros
         
     | 
| 
      
 8 
     | 
    
         
            +
                  include RangeHelp
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def_node_matcher :sort_with_block?, <<~PATTERN
         
     | 
| 
      
 11 
     | 
    
         
            +
                    (block
         
     | 
| 
      
 12 
     | 
    
         
            +
                      $(send _ :sort)
         
     | 
| 
      
 13 
     | 
    
         
            +
                      (args (arg $_a) (arg $_b))
         
     | 
| 
      
 14 
     | 
    
         
            +
                      $send)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  PATTERN
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  def_node_matcher :replaceable_body?, <<~PATTERN
         
     | 
| 
      
 18 
     | 
    
         
            +
                    (send (lvar %1) :<=> (lvar %2))
         
     | 
| 
      
 19 
     | 
    
         
            +
                  PATTERN
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  private
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  def sort_range(send, node)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    range_between(send.loc.selector.begin_pos, node.loc.end.end_pos)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,45 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module RuboCop
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Cop
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Performance
         
     | 
| 
      
 6 
     | 
    
         
            +
                  # This cop is used to identify usages of `ancestors.include?` and
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # change them to use `<=` instead.
         
     | 
| 
      
 8 
     | 
    
         
            +
                  #
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # @example
         
     | 
| 
      
 10 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 11 
     | 
    
         
            +
                  #   A.ancestors.include?(B)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  #
         
     | 
| 
      
 13 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 14 
     | 
    
         
            +
                  #   A <= B
         
     | 
| 
      
 15 
     | 
    
         
            +
                  #
         
     | 
| 
      
 16 
     | 
    
         
            +
                  class AncestorsInclude < Cop
         
     | 
| 
      
 17 
     | 
    
         
            +
                    include RangeHelp
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                    MSG = 'Use `<=` instead of `ancestors.include?`.'
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                    def_node_matcher :ancestors_include_candidate?, <<~PATTERN
         
     | 
| 
      
 22 
     | 
    
         
            +
                      (send (send $_subclass :ancestors) :include? $_superclass)
         
     | 
| 
      
 23 
     | 
    
         
            +
                    PATTERN
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    def on_send(node)
         
     | 
| 
      
 26 
     | 
    
         
            +
                      return unless ancestors_include_candidate?(node)
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                      location_of_ancestors = node.children[0].loc.selector.begin_pos
         
     | 
| 
      
 29 
     | 
    
         
            +
                      end_location = node.loc.selector.end_pos
         
     | 
| 
      
 30 
     | 
    
         
            +
                      range = range_between(location_of_ancestors, end_location)
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                      add_offense(node, location: range)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                    def autocorrect(node)
         
     | 
| 
      
 36 
     | 
    
         
            +
                      ancestors_include_candidate?(node) do |subclass, superclass|
         
     | 
| 
      
 37 
     | 
    
         
            +
                        lambda do |corrector|
         
     | 
| 
      
 38 
     | 
    
         
            +
                          corrector.replace(node, "#{subclass.source} <= #{superclass.source}")
         
     | 
| 
      
 39 
     | 
    
         
            +
                        end
         
     | 
| 
      
 40 
     | 
    
         
            +
                      end
         
     | 
| 
      
 41 
     | 
    
         
            +
                    end
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
      
 45 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,43 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module RuboCop
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Cop
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Performance
         
     | 
| 
      
 6 
     | 
    
         
            +
                  # This cop identifies places where numeric argument to BigDecimal should be
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # converted to string. Initializing from String is faster
         
     | 
| 
      
 8 
     | 
    
         
            +
                  # than from Numeric for BigDecimal.
         
     | 
| 
      
 9 
     | 
    
         
            +
                  #
         
     | 
| 
      
 10 
     | 
    
         
            +
                  # @example
         
     | 
| 
      
 11 
     | 
    
         
            +
                  #
         
     | 
| 
      
 12 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 13 
     | 
    
         
            +
                  # BigDecimal(1, 2)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  # BigDecimal(1.2, 3, exception: true)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  #
         
     | 
| 
      
 16 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 17 
     | 
    
         
            +
                  # BigDecimal('1', 2)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  # BigDecimal('1.2', 3, exception: true)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  #
         
     | 
| 
      
 20 
     | 
    
         
            +
                  class BigDecimalWithNumericArgument < Cop
         
     | 
| 
      
 21 
     | 
    
         
            +
                    MSG = 'Convert numeric argument to string before passing to `BigDecimal`.'
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                    def_node_matcher :big_decimal_with_numeric_argument?, <<~PATTERN
         
     | 
| 
      
 24 
     | 
    
         
            +
                      (send nil? :BigDecimal $numeric_type? ...)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    PATTERN
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    def on_send(node)
         
     | 
| 
      
 28 
     | 
    
         
            +
                      big_decimal_with_numeric_argument?(node) do |numeric|
         
     | 
| 
      
 29 
     | 
    
         
            +
                        add_offense(node, location: numeric.source_range)
         
     | 
| 
      
 30 
     | 
    
         
            +
                      end
         
     | 
| 
      
 31 
     | 
    
         
            +
                    end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                    def autocorrect(node)
         
     | 
| 
      
 34 
     | 
    
         
            +
                      big_decimal_with_numeric_argument?(node) do |numeric|
         
     | 
| 
      
 35 
     | 
    
         
            +
                        lambda do |corrector|
         
     | 
| 
      
 36 
     | 
    
         
            +
                          corrector.wrap(numeric, "'", "'")
         
     | 
| 
      
 37 
     | 
    
         
            +
                        end
         
     | 
| 
      
 38 
     | 
    
         
            +
                      end
         
     | 
| 
      
 39 
     | 
    
         
            +
                    end
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,127 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module RuboCop
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Cop
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Performance
         
     | 
| 
      
 6 
     | 
    
         
            +
                  # This cop identifies places where inefficient `readlines` method
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # can be replaced by `each_line` to avoid fully loading file content into memory.
         
     | 
| 
      
 8 
     | 
    
         
            +
                  #
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # @example
         
     | 
| 
      
 10 
     | 
    
         
            +
                  #
         
     | 
| 
      
 11 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 12 
     | 
    
         
            +
                  #   File.readlines('testfile').each { |l| puts l }
         
     | 
| 
      
 13 
     | 
    
         
            +
                  #   IO.readlines('testfile', chomp: true).each { |l| puts l }
         
     | 
| 
      
 14 
     | 
    
         
            +
                  #
         
     | 
| 
      
 15 
     | 
    
         
            +
                  #   conn.readlines(10).map { |l| l.size }
         
     | 
| 
      
 16 
     | 
    
         
            +
                  #   file.readlines.find { |l| l.start_with?('#') }
         
     | 
| 
      
 17 
     | 
    
         
            +
                  #   file.readlines.each { |l| puts l }
         
     | 
| 
      
 18 
     | 
    
         
            +
                  #
         
     | 
| 
      
 19 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 20 
     | 
    
         
            +
                  #   File.open('testfile', 'r').each_line { |l| puts l }
         
     | 
| 
      
 21 
     | 
    
         
            +
                  #   IO.open('testfile').each_line(chomp: true) { |l| puts l }
         
     | 
| 
      
 22 
     | 
    
         
            +
                  #
         
     | 
| 
      
 23 
     | 
    
         
            +
                  #   conn.each_line(10).map { |l| l.size }
         
     | 
| 
      
 24 
     | 
    
         
            +
                  #   file.each_line.find { |l| l.start_with?('#') }
         
     | 
| 
      
 25 
     | 
    
         
            +
                  #   file.each_line { |l| puts l }
         
     | 
| 
      
 26 
     | 
    
         
            +
                  #
         
     | 
| 
      
 27 
     | 
    
         
            +
                  class IoReadlines < Cop
         
     | 
| 
      
 28 
     | 
    
         
            +
                    include RangeHelp
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                    MSG = 'Use `%<good>s` instead of `%<bad>s`.'
         
     | 
| 
      
 31 
     | 
    
         
            +
                    ENUMERABLE_METHODS = (Enumerable.instance_methods + [:each]).freeze
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                    def_node_matcher :readlines_on_class?, <<~PATTERN
         
     | 
| 
      
 34 
     | 
    
         
            +
                      $(send $(send (const nil? {:IO :File}) :readlines ...) #enumerable_method?)
         
     | 
| 
      
 35 
     | 
    
         
            +
                    PATTERN
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                    def_node_matcher :readlines_on_instance?, <<~PATTERN
         
     | 
| 
      
 38 
     | 
    
         
            +
                      $(send $(send ${nil? !const_type?} :readlines ...) #enumerable_method? ...)
         
     | 
| 
      
 39 
     | 
    
         
            +
                    PATTERN
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                    def on_send(node)
         
     | 
| 
      
 42 
     | 
    
         
            +
                      readlines_on_class?(node) do |enumerable_call, readlines_call|
         
     | 
| 
      
 43 
     | 
    
         
            +
                        offense(node, enumerable_call, readlines_call)
         
     | 
| 
      
 44 
     | 
    
         
            +
                      end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                      readlines_on_instance?(node) do |enumerable_call, readlines_call, _|
         
     | 
| 
      
 47 
     | 
    
         
            +
                        offense(node, enumerable_call, readlines_call)
         
     | 
| 
      
 48 
     | 
    
         
            +
                      end
         
     | 
| 
      
 49 
     | 
    
         
            +
                    end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                    def autocorrect(node)
         
     | 
| 
      
 52 
     | 
    
         
            +
                      readlines_on_instance?(node) do |enumerable_call, readlines_call, receiver|
         
     | 
| 
      
 53 
     | 
    
         
            +
                        # We cannot safely correct `.readlines` method called on IO/File classes
         
     | 
| 
      
 54 
     | 
    
         
            +
                        # due to its signature and we are not sure with implicit receiver
         
     | 
| 
      
 55 
     | 
    
         
            +
                        # if it is called in the context of some instance or mentioned class.
         
     | 
| 
      
 56 
     | 
    
         
            +
                        return if receiver.nil?
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                        lambda do |corrector|
         
     | 
| 
      
 59 
     | 
    
         
            +
                          range = correction_range(enumerable_call, readlines_call)
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                          if readlines_call.arguments?
         
     | 
| 
      
 62 
     | 
    
         
            +
                            call_args = build_call_args(readlines_call.arguments)
         
     | 
| 
      
 63 
     | 
    
         
            +
                            replacement = "each_line(#{call_args})"
         
     | 
| 
      
 64 
     | 
    
         
            +
                          else
         
     | 
| 
      
 65 
     | 
    
         
            +
                            replacement = 'each_line'
         
     | 
| 
      
 66 
     | 
    
         
            +
                          end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                          corrector.replace(range, replacement)
         
     | 
| 
      
 69 
     | 
    
         
            +
                        end
         
     | 
| 
      
 70 
     | 
    
         
            +
                      end
         
     | 
| 
      
 71 
     | 
    
         
            +
                    end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                    private
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                    def enumerable_method?(node)
         
     | 
| 
      
 76 
     | 
    
         
            +
                      ENUMERABLE_METHODS.include?(node.to_sym)
         
     | 
| 
      
 77 
     | 
    
         
            +
                    end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                    def offense(node, enumerable_call, readlines_call)
         
     | 
| 
      
 80 
     | 
    
         
            +
                      range = offense_range(enumerable_call, readlines_call)
         
     | 
| 
      
 81 
     | 
    
         
            +
                      good_method = build_good_method(enumerable_call)
         
     | 
| 
      
 82 
     | 
    
         
            +
                      bad_method = build_bad_method(enumerable_call)
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                      add_offense(
         
     | 
| 
      
 85 
     | 
    
         
            +
                        node,
         
     | 
| 
      
 86 
     | 
    
         
            +
                        location: range,
         
     | 
| 
      
 87 
     | 
    
         
            +
                        message: format(MSG, good: good_method, bad: bad_method)
         
     | 
| 
      
 88 
     | 
    
         
            +
                      )
         
     | 
| 
      
 89 
     | 
    
         
            +
                    end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                    def offense_range(enumerable_call, readlines_call)
         
     | 
| 
      
 92 
     | 
    
         
            +
                      readlines_pos = readlines_call.loc.selector.begin_pos
         
     | 
| 
      
 93 
     | 
    
         
            +
                      enumerable_pos = enumerable_call.loc.selector.end_pos
         
     | 
| 
      
 94 
     | 
    
         
            +
                      range_between(readlines_pos, enumerable_pos)
         
     | 
| 
      
 95 
     | 
    
         
            +
                    end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                    def build_good_method(enumerable_call)
         
     | 
| 
      
 98 
     | 
    
         
            +
                      if enumerable_call.method?(:each)
         
     | 
| 
      
 99 
     | 
    
         
            +
                        'each_line'
         
     | 
| 
      
 100 
     | 
    
         
            +
                      else
         
     | 
| 
      
 101 
     | 
    
         
            +
                        "each_line.#{enumerable_call.method_name}"
         
     | 
| 
      
 102 
     | 
    
         
            +
                      end
         
     | 
| 
      
 103 
     | 
    
         
            +
                    end
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                    def build_bad_method(enumerable_call)
         
     | 
| 
      
 106 
     | 
    
         
            +
                      "readlines.#{enumerable_call.method_name}"
         
     | 
| 
      
 107 
     | 
    
         
            +
                    end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                    def correction_range(enumerable_call, readlines_call)
         
     | 
| 
      
 110 
     | 
    
         
            +
                      begin_pos = readlines_call.loc.selector.begin_pos
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                      end_pos = if enumerable_call.method?(:each)
         
     | 
| 
      
 113 
     | 
    
         
            +
                                  enumerable_call.loc.expression.end_pos
         
     | 
| 
      
 114 
     | 
    
         
            +
                                else
         
     | 
| 
      
 115 
     | 
    
         
            +
                                  enumerable_call.loc.dot.begin_pos
         
     | 
| 
      
 116 
     | 
    
         
            +
                                end
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                      range_between(begin_pos, end_pos)
         
     | 
| 
      
 119 
     | 
    
         
            +
                    end
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                    def build_call_args(call_args_node)
         
     | 
| 
      
 122 
     | 
    
         
            +
                      call_args_node.map(&:source).join(', ')
         
     | 
| 
      
 123 
     | 
    
         
            +
                    end
         
     | 
| 
      
 124 
     | 
    
         
            +
                  end
         
     | 
| 
      
 125 
     | 
    
         
            +
                end
         
     | 
| 
      
 126 
     | 
    
         
            +
              end
         
     | 
| 
      
 127 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -3,18 +3,19 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            module RuboCop
         
     | 
| 
       4 
4 
     | 
    
         
             
              module Cop
         
     | 
| 
       5 
5 
     | 
    
         
             
                module Performance
         
     | 
| 
       6 
     | 
    
         
            -
                  # This cop identifies uses of `Range#include?`, which iterates over each
         
     | 
| 
      
 6 
     | 
    
         
            +
                  # This cop identifies uses of `Range#include?` and `Range#member?`, which iterates over each
         
     | 
| 
       7 
7 
     | 
    
         
             
                  # item in a `Range` to see if a specified item is there. In contrast,
         
     | 
| 
       8 
8 
     | 
    
         
             
                  # `Range#cover?` simply compares the target item with the beginning and
         
     | 
| 
       9 
9 
     | 
    
         
             
                  # end points of the `Range`. In a great majority of cases, this is what
         
     | 
| 
       10 
10 
     | 
    
         
             
                  # is wanted.
         
     | 
| 
       11 
11 
     | 
    
         
             
                  #
         
     | 
| 
       12 
     | 
    
         
            -
                  # This cop is `Safe: false` by default because `Range#include?` and
         
     | 
| 
      
 12 
     | 
    
         
            +
                  # This cop is `Safe: false` by default because `Range#include?` (or `Range#member?`) and
         
     | 
| 
       13 
13 
     | 
    
         
             
                  # `Range#cover?` are not equivalent behaviour.
         
     | 
| 
       14 
14 
     | 
    
         
             
                  #
         
     | 
| 
       15 
15 
     | 
    
         
             
                  # @example
         
     | 
| 
       16 
16 
     | 
    
         
             
                  #   # bad
         
     | 
| 
       17 
17 
     | 
    
         
             
                  #   ('a'..'z').include?('b') # => true
         
     | 
| 
      
 18 
     | 
    
         
            +
                  #   ('a'..'z').member?('b')  # => true
         
     | 
| 
       18 
19 
     | 
    
         
             
                  #
         
     | 
| 
       19 
20 
     | 
    
         
             
                  #   # good
         
     | 
| 
       20 
21 
     | 
    
         
             
                  #   ('a'..'z').cover?('b') # => true
         
     | 
| 
         @@ -24,7 +25,7 @@ module RuboCop 
     | 
|
| 
       24 
25 
     | 
    
         
             
                  #
         
     | 
| 
       25 
26 
     | 
    
         
             
                  #   ('a'..'z').cover?('yellow') # => true
         
     | 
| 
       26 
27 
     | 
    
         
             
                  class RangeInclude < Cop
         
     | 
| 
       27 
     | 
    
         
            -
                    MSG = 'Use `Range#cover?` instead of `Range 
     | 
| 
      
 28 
     | 
    
         
            +
                    MSG = 'Use `Range#cover?` instead of `Range#%<bad_method>s`.'
         
     | 
| 
       28 
29 
     | 
    
         | 
| 
       29 
30 
     | 
    
         
             
                    # TODO: If we traced out assignments of variables to their uses, we
         
     | 
| 
       30 
31 
     | 
    
         
             
                    # might pick up on a few more instances of this issue
         
     | 
| 
         @@ -32,13 +33,14 @@ module RuboCop 
     | 
|
| 
       32 
33 
     | 
    
         
             
                    # (We don't even catch it if the Range is in double parens)
         
     | 
| 
       33 
34 
     | 
    
         | 
| 
       34 
35 
     | 
    
         
             
                    def_node_matcher :range_include, <<~PATTERN
         
     | 
| 
       35 
     | 
    
         
            -
                      (send {irange erange (begin {irange erange})} :include? ...)
         
     | 
| 
      
 36 
     | 
    
         
            +
                      (send {irange erange (begin {irange erange})} ${:include? :member?} ...)
         
     | 
| 
       36 
37 
     | 
    
         
             
                    PATTERN
         
     | 
| 
       37 
38 
     | 
    
         | 
| 
       38 
39 
     | 
    
         
             
                    def on_send(node)
         
     | 
| 
       39 
     | 
    
         
            -
                       
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
      
 40 
     | 
    
         
            +
                      range_include(node) do |bad_method|
         
     | 
| 
      
 41 
     | 
    
         
            +
                        message = format(MSG, bad_method: bad_method)
         
     | 
| 
      
 42 
     | 
    
         
            +
                        add_offense(node, location: :selector, message: message)
         
     | 
| 
      
 43 
     | 
    
         
            +
                      end
         
     | 
| 
       42 
44 
     | 
    
         
             
                    end
         
     | 
| 
       43 
45 
     | 
    
         | 
| 
       44 
46 
     | 
    
         
             
                    def autocorrect(node)
         
     | 
| 
         @@ -0,0 +1,53 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module RuboCop
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Cop
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Performance
         
     | 
| 
      
 6 
     | 
    
         
            +
                  # This cop identifies places where `sort { |a, b| a <=> b }`
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # can be replaced with `sort`.
         
     | 
| 
      
 8 
     | 
    
         
            +
                  #
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # @example
         
     | 
| 
      
 10 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 11 
     | 
    
         
            +
                  #   array.sort { |a, b| a <=> b }
         
     | 
| 
      
 12 
     | 
    
         
            +
                  #
         
     | 
| 
      
 13 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 14 
     | 
    
         
            +
                  #   array.sort
         
     | 
| 
      
 15 
     | 
    
         
            +
                  #
         
     | 
| 
      
 16 
     | 
    
         
            +
                  class RedundantSortBlock < Cop
         
     | 
| 
      
 17 
     | 
    
         
            +
                    include SortBlock
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                    MSG = 'Use `sort` instead of `%<bad_method>s`.'
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                    def on_block(node)
         
     | 
| 
      
 22 
     | 
    
         
            +
                      sort_with_block?(node) do |send, var_a, var_b, body|
         
     | 
| 
      
 23 
     | 
    
         
            +
                        replaceable_body?(body, var_a, var_b) do
         
     | 
| 
      
 24 
     | 
    
         
            +
                          range = sort_range(send, node)
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                          add_offense(
         
     | 
| 
      
 27 
     | 
    
         
            +
                            node,
         
     | 
| 
      
 28 
     | 
    
         
            +
                            location: range,
         
     | 
| 
      
 29 
     | 
    
         
            +
                            message: message(var_a, var_b)
         
     | 
| 
      
 30 
     | 
    
         
            +
                          )
         
     | 
| 
      
 31 
     | 
    
         
            +
                        end
         
     | 
| 
      
 32 
     | 
    
         
            +
                      end
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                    def autocorrect(node)
         
     | 
| 
      
 36 
     | 
    
         
            +
                      sort_with_block?(node) do |send, _var_a, _var_b, _body|
         
     | 
| 
      
 37 
     | 
    
         
            +
                        lambda do |corrector|
         
     | 
| 
      
 38 
     | 
    
         
            +
                          range = sort_range(send, node)
         
     | 
| 
      
 39 
     | 
    
         
            +
                          corrector.replace(range, 'sort')
         
     | 
| 
      
 40 
     | 
    
         
            +
                        end
         
     | 
| 
      
 41 
     | 
    
         
            +
                      end
         
     | 
| 
      
 42 
     | 
    
         
            +
                    end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                    private
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                    def message(var_a, var_b)
         
     | 
| 
      
 47 
     | 
    
         
            +
                      bad_method = "sort { |#{var_a}, #{var_b}| #{var_a} <=> #{var_b} }"
         
     | 
| 
      
 48 
     | 
    
         
            +
                      format(MSG, bad_method: bad_method)
         
     | 
| 
      
 49 
     | 
    
         
            +
                    end
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,137 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module RuboCop
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Cop
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Performance
         
     | 
| 
      
 6 
     | 
    
         
            +
                  # This cop checks for redundant `String#chars`.
         
     | 
| 
      
 7 
     | 
    
         
            +
                  #
         
     | 
| 
      
 8 
     | 
    
         
            +
                  # @example
         
     | 
| 
      
 9 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 10 
     | 
    
         
            +
                  #   str.chars[0..2]
         
     | 
| 
      
 11 
     | 
    
         
            +
                  #   str.chars.slice(0..2)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  #
         
     | 
| 
      
 13 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 14 
     | 
    
         
            +
                  #   str[0..2].chars
         
     | 
| 
      
 15 
     | 
    
         
            +
                  #
         
     | 
| 
      
 16 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 17 
     | 
    
         
            +
                  #   str.chars.first
         
     | 
| 
      
 18 
     | 
    
         
            +
                  #   str.chars.first(2)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  #   str.chars.last
         
     | 
| 
      
 20 
     | 
    
         
            +
                  #   str.chars.last(2)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  #
         
     | 
| 
      
 22 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 23 
     | 
    
         
            +
                  #   str[0]
         
     | 
| 
      
 24 
     | 
    
         
            +
                  #   str[0...2].chars
         
     | 
| 
      
 25 
     | 
    
         
            +
                  #   str[-1]
         
     | 
| 
      
 26 
     | 
    
         
            +
                  #   str[-2..-1].chars
         
     | 
| 
      
 27 
     | 
    
         
            +
                  #
         
     | 
| 
      
 28 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 29 
     | 
    
         
            +
                  #   str.chars.take(2)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  #   str.chars.drop(2)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  #   str.chars.length
         
     | 
| 
      
 32 
     | 
    
         
            +
                  #   str.chars.size
         
     | 
| 
      
 33 
     | 
    
         
            +
                  #   str.chars.empty?
         
     | 
| 
      
 34 
     | 
    
         
            +
                  #
         
     | 
| 
      
 35 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 36 
     | 
    
         
            +
                  #   str[0...2].chars
         
     | 
| 
      
 37 
     | 
    
         
            +
                  #   str[2..-1].chars
         
     | 
| 
      
 38 
     | 
    
         
            +
                  #   str.length
         
     | 
| 
      
 39 
     | 
    
         
            +
                  #   str.size
         
     | 
| 
      
 40 
     | 
    
         
            +
                  #   str.empty?
         
     | 
| 
      
 41 
     | 
    
         
            +
                  #
         
     | 
| 
      
 42 
     | 
    
         
            +
                  class RedundantStringChars < Cop
         
     | 
| 
      
 43 
     | 
    
         
            +
                    include RangeHelp
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                    MSG = 'Use `%<good_method>s` instead of `%<bad_method>s`.'
         
     | 
| 
      
 46 
     | 
    
         
            +
                    REPLACEABLE_METHODS = %i[[] slice first last take drop length size empty?].freeze
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                    def_node_matcher :redundant_chars_call?, <<~PATTERN
         
     | 
| 
      
 49 
     | 
    
         
            +
                      (send $(send _ :chars) $#replaceable_method? $...)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    PATTERN
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                    def on_send(node)
         
     | 
| 
      
 53 
     | 
    
         
            +
                      redundant_chars_call?(node) do |receiver, method, args|
         
     | 
| 
      
 54 
     | 
    
         
            +
                        range = offense_range(receiver, node)
         
     | 
| 
      
 55 
     | 
    
         
            +
                        message = build_message(method, args)
         
     | 
| 
      
 56 
     | 
    
         
            +
                        add_offense(node, location: range, message: message)
         
     | 
| 
      
 57 
     | 
    
         
            +
                      end
         
     | 
| 
      
 58 
     | 
    
         
            +
                    end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                    def autocorrect(node)
         
     | 
| 
      
 61 
     | 
    
         
            +
                      redundant_chars_call?(node) do |receiver, method, args|
         
     | 
| 
      
 62 
     | 
    
         
            +
                        range = correction_range(receiver, node)
         
     | 
| 
      
 63 
     | 
    
         
            +
                        replacement = build_good_method(method, args)
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                        lambda do |corrector|
         
     | 
| 
      
 66 
     | 
    
         
            +
                          corrector.replace(range, replacement)
         
     | 
| 
      
 67 
     | 
    
         
            +
                        end
         
     | 
| 
      
 68 
     | 
    
         
            +
                      end
         
     | 
| 
      
 69 
     | 
    
         
            +
                    end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                    private
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                    def replaceable_method?(method_name)
         
     | 
| 
      
 74 
     | 
    
         
            +
                      REPLACEABLE_METHODS.include?(method_name)
         
     | 
| 
      
 75 
     | 
    
         
            +
                    end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                    def offense_range(receiver, node)
         
     | 
| 
      
 78 
     | 
    
         
            +
                      range_between(receiver.loc.selector.begin_pos, node.loc.expression.end_pos)
         
     | 
| 
      
 79 
     | 
    
         
            +
                    end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                    def correction_range(receiver, node)
         
     | 
| 
      
 82 
     | 
    
         
            +
                      range_between(receiver.loc.dot.begin_pos, node.loc.expression.end_pos)
         
     | 
| 
      
 83 
     | 
    
         
            +
                    end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                    def build_message(method, args)
         
     | 
| 
      
 86 
     | 
    
         
            +
                      good_method = build_good_method(method, args)
         
     | 
| 
      
 87 
     | 
    
         
            +
                      bad_method = build_bad_method(method, args)
         
     | 
| 
      
 88 
     | 
    
         
            +
                      format(MSG, good_method: good_method, bad_method: bad_method)
         
     | 
| 
      
 89 
     | 
    
         
            +
                    end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                    # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
         
     | 
| 
      
 92 
     | 
    
         
            +
                    def build_good_method(method, args)
         
     | 
| 
      
 93 
     | 
    
         
            +
                      case method
         
     | 
| 
      
 94 
     | 
    
         
            +
                      when :[], :slice
         
     | 
| 
      
 95 
     | 
    
         
            +
                        "[#{build_call_args(args)}].chars"
         
     | 
| 
      
 96 
     | 
    
         
            +
                      when :first
         
     | 
| 
      
 97 
     | 
    
         
            +
                        if args.any?
         
     | 
| 
      
 98 
     | 
    
         
            +
                          "[0...#{args.first.source}].chars"
         
     | 
| 
      
 99 
     | 
    
         
            +
                        else
         
     | 
| 
      
 100 
     | 
    
         
            +
                          '[0]'
         
     | 
| 
      
 101 
     | 
    
         
            +
                        end
         
     | 
| 
      
 102 
     | 
    
         
            +
                      when :last
         
     | 
| 
      
 103 
     | 
    
         
            +
                        if args.any?
         
     | 
| 
      
 104 
     | 
    
         
            +
                          "[-#{args.first.source}..-1].chars"
         
     | 
| 
      
 105 
     | 
    
         
            +
                        else
         
     | 
| 
      
 106 
     | 
    
         
            +
                          '[-1]'
         
     | 
| 
      
 107 
     | 
    
         
            +
                        end
         
     | 
| 
      
 108 
     | 
    
         
            +
                      when :take
         
     | 
| 
      
 109 
     | 
    
         
            +
                        "[0...#{args.first.source}].chars"
         
     | 
| 
      
 110 
     | 
    
         
            +
                      when :drop
         
     | 
| 
      
 111 
     | 
    
         
            +
                        "[#{args.first.source}..-1].chars"
         
     | 
| 
      
 112 
     | 
    
         
            +
                      else
         
     | 
| 
      
 113 
     | 
    
         
            +
                        ".#{method}"
         
     | 
| 
      
 114 
     | 
    
         
            +
                      end
         
     | 
| 
      
 115 
     | 
    
         
            +
                    end
         
     | 
| 
      
 116 
     | 
    
         
            +
                    # rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                    def build_bad_method(method, args)
         
     | 
| 
      
 119 
     | 
    
         
            +
                      case method
         
     | 
| 
      
 120 
     | 
    
         
            +
                      when :[]
         
     | 
| 
      
 121 
     | 
    
         
            +
                        "chars[#{build_call_args(args)}]"
         
     | 
| 
      
 122 
     | 
    
         
            +
                      else
         
     | 
| 
      
 123 
     | 
    
         
            +
                        if args.any?
         
     | 
| 
      
 124 
     | 
    
         
            +
                          "chars.#{method}(#{build_call_args(args)})"
         
     | 
| 
      
 125 
     | 
    
         
            +
                        else
         
     | 
| 
      
 126 
     | 
    
         
            +
                          "chars.#{method}"
         
     | 
| 
      
 127 
     | 
    
         
            +
                        end
         
     | 
| 
      
 128 
     | 
    
         
            +
                      end
         
     | 
| 
      
 129 
     | 
    
         
            +
                    end
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                    def build_call_args(call_args_node)
         
     | 
| 
      
 132 
     | 
    
         
            +
                      call_args_node.map(&:source).join(', ')
         
     | 
| 
      
 133 
     | 
    
         
            +
                    end
         
     | 
| 
      
 134 
     | 
    
         
            +
                  end
         
     | 
| 
      
 135 
     | 
    
         
            +
                end
         
     | 
| 
      
 136 
     | 
    
         
            +
              end
         
     | 
| 
      
 137 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,78 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module RuboCop
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Cop
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Performance
         
     | 
| 
      
 6 
     | 
    
         
            +
                  # This cop identifies places where `reverse.first(n)` and `reverse.first`
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # can be replaced by `last(n).reverse` and `last`.
         
     | 
| 
      
 8 
     | 
    
         
            +
                  #
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # @example
         
     | 
| 
      
 10 
     | 
    
         
            +
                  #
         
     | 
| 
      
 11 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 12 
     | 
    
         
            +
                  #   array.reverse.first(5)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  #   array.reverse.first
         
     | 
| 
      
 14 
     | 
    
         
            +
                  #
         
     | 
| 
      
 15 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 16 
     | 
    
         
            +
                  #   array.last(5).reverse
         
     | 
| 
      
 17 
     | 
    
         
            +
                  #   array.last
         
     | 
| 
      
 18 
     | 
    
         
            +
                  #
         
     | 
| 
      
 19 
     | 
    
         
            +
                  class ReverseFirst < Cop
         
     | 
| 
      
 20 
     | 
    
         
            +
                    include RangeHelp
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    MSG = 'Use `%<good_method>s` instead of `%<bad_method>s`.'
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                    def_node_matcher :reverse_first_candidate?, <<~PATTERN
         
     | 
| 
      
 25 
     | 
    
         
            +
                      (send $(send _ :reverse) :first (int _)?)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    PATTERN
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                    def on_send(node)
         
     | 
| 
      
 29 
     | 
    
         
            +
                      reverse_first_candidate?(node) do |receiver|
         
     | 
| 
      
 30 
     | 
    
         
            +
                        range = correction_range(receiver, node)
         
     | 
| 
      
 31 
     | 
    
         
            +
                        message = build_message(node)
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                        add_offense(node, location: range, message: message)
         
     | 
| 
      
 34 
     | 
    
         
            +
                      end
         
     | 
| 
      
 35 
     | 
    
         
            +
                    end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                    def autocorrect(node)
         
     | 
| 
      
 38 
     | 
    
         
            +
                      reverse_first_candidate?(node) do |receiver|
         
     | 
| 
      
 39 
     | 
    
         
            +
                        range = correction_range(receiver, node)
         
     | 
| 
      
 40 
     | 
    
         
            +
                        replacement = build_good_method(node)
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                        lambda do |corrector|
         
     | 
| 
      
 43 
     | 
    
         
            +
                          corrector.replace(range, replacement)
         
     | 
| 
      
 44 
     | 
    
         
            +
                        end
         
     | 
| 
      
 45 
     | 
    
         
            +
                      end
         
     | 
| 
      
 46 
     | 
    
         
            +
                    end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                    private
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    def correction_range(receiver, node)
         
     | 
| 
      
 51 
     | 
    
         
            +
                      range_between(receiver.loc.selector.begin_pos, node.loc.expression.end_pos)
         
     | 
| 
      
 52 
     | 
    
         
            +
                    end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                    def build_message(node)
         
     | 
| 
      
 55 
     | 
    
         
            +
                      good_method = build_good_method(node)
         
     | 
| 
      
 56 
     | 
    
         
            +
                      bad_method = build_bad_method(node)
         
     | 
| 
      
 57 
     | 
    
         
            +
                      format(MSG, good_method: good_method, bad_method: bad_method)
         
     | 
| 
      
 58 
     | 
    
         
            +
                    end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                    def build_good_method(node)
         
     | 
| 
      
 61 
     | 
    
         
            +
                      if node.arguments?
         
     | 
| 
      
 62 
     | 
    
         
            +
                        "last(#{node.arguments.first.source}).reverse"
         
     | 
| 
      
 63 
     | 
    
         
            +
                      else
         
     | 
| 
      
 64 
     | 
    
         
            +
                        'last'
         
     | 
| 
      
 65 
     | 
    
         
            +
                      end
         
     | 
| 
      
 66 
     | 
    
         
            +
                    end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                    def build_bad_method(node)
         
     | 
| 
      
 69 
     | 
    
         
            +
                      if node.arguments?
         
     | 
| 
      
 70 
     | 
    
         
            +
                        "reverse.first(#{node.arguments.first.source})"
         
     | 
| 
      
 71 
     | 
    
         
            +
                      else
         
     | 
| 
      
 72 
     | 
    
         
            +
                        'reverse.first'
         
     | 
| 
      
 73 
     | 
    
         
            +
                      end
         
     | 
| 
      
 74 
     | 
    
         
            +
                    end
         
     | 
| 
      
 75 
     | 
    
         
            +
                  end
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
      
 77 
     | 
    
         
            +
              end
         
     | 
| 
      
 78 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -9,15 +9,27 @@ module RuboCop 
     | 
|
| 
       9 
9 
     | 
    
         
             
                  # @example
         
     | 
| 
       10 
10 
     | 
    
         
             
                  #   # bad
         
     | 
| 
       11 
11 
     | 
    
         
             
                  #   [1, 2, 3].count
         
     | 
| 
      
 12 
     | 
    
         
            +
                  #   (1..3).to_a.count
         
     | 
| 
      
 13 
     | 
    
         
            +
                  #   Array[*1..3].count
         
     | 
| 
      
 14 
     | 
    
         
            +
                  #   Array(1..3).count
         
     | 
| 
       12 
15 
     | 
    
         
             
                  #
         
     | 
| 
       13 
16 
     | 
    
         
             
                  #   # bad
         
     | 
| 
       14 
17 
     | 
    
         
             
                  #   {a: 1, b: 2, c: 3}.count
         
     | 
| 
      
 18 
     | 
    
         
            +
                  #   [[:foo, :bar], [1, 2]].to_h.count
         
     | 
| 
      
 19 
     | 
    
         
            +
                  #   Hash[*('a'..'z')].count
         
     | 
| 
      
 20 
     | 
    
         
            +
                  #   Hash(key: :value).count
         
     | 
| 
       15 
21 
     | 
    
         
             
                  #
         
     | 
| 
       16 
22 
     | 
    
         
             
                  #   # good
         
     | 
| 
       17 
23 
     | 
    
         
             
                  #   [1, 2, 3].size
         
     | 
| 
      
 24 
     | 
    
         
            +
                  #   (1..3).to_a.size
         
     | 
| 
      
 25 
     | 
    
         
            +
                  #   Array[*1..3].size
         
     | 
| 
      
 26 
     | 
    
         
            +
                  #   Array(1..3).size
         
     | 
| 
       18 
27 
     | 
    
         
             
                  #
         
     | 
| 
       19 
28 
     | 
    
         
             
                  #   # good
         
     | 
| 
       20 
29 
     | 
    
         
             
                  #   {a: 1, b: 2, c: 3}.size
         
     | 
| 
      
 30 
     | 
    
         
            +
                  #   [[:foo, :bar], [1, 2]].to_h.size
         
     | 
| 
      
 31 
     | 
    
         
            +
                  #   Hash[*('a'..'z')].size
         
     | 
| 
      
 32 
     | 
    
         
            +
                  #   Hash(key: :value).size
         
     | 
| 
       21 
33 
     | 
    
         
             
                  #
         
     | 
| 
       22 
34 
     | 
    
         
             
                  #   # good
         
     | 
| 
       23 
35 
     | 
    
         
             
                  #   [1, 2, 3].count { |e| e > 2 }
         
     | 
| 
         @@ -26,8 +38,30 @@ module RuboCop 
     | 
|
| 
       26 
38 
     | 
    
         
             
                  class Size < Cop
         
     | 
| 
       27 
39 
     | 
    
         
             
                    MSG = 'Use `size` instead of `count`.'
         
     | 
| 
       28 
40 
     | 
    
         | 
| 
      
 41 
     | 
    
         
            +
                    def_node_matcher :array?, <<~PATTERN
         
     | 
| 
      
 42 
     | 
    
         
            +
                      {
         
     | 
| 
      
 43 
     | 
    
         
            +
                        [!nil? array_type?]
         
     | 
| 
      
 44 
     | 
    
         
            +
                        (send _ :to_a)
         
     | 
| 
      
 45 
     | 
    
         
            +
                        (send (const nil? :Array) :[] _)
         
     | 
| 
      
 46 
     | 
    
         
            +
                        (send nil? :Array _)
         
     | 
| 
      
 47 
     | 
    
         
            +
                      }
         
     | 
| 
      
 48 
     | 
    
         
            +
                    PATTERN
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    def_node_matcher :hash?, <<~PATTERN
         
     | 
| 
      
 51 
     | 
    
         
            +
                      {
         
     | 
| 
      
 52 
     | 
    
         
            +
                        [!nil? hash_type?]
         
     | 
| 
      
 53 
     | 
    
         
            +
                        (send _ :to_h)
         
     | 
| 
      
 54 
     | 
    
         
            +
                        (send (const nil? :Hash) :[] _)
         
     | 
| 
      
 55 
     | 
    
         
            +
                        (send nil? :Hash _)
         
     | 
| 
      
 56 
     | 
    
         
            +
                      }
         
     | 
| 
      
 57 
     | 
    
         
            +
                    PATTERN
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                    def_node_matcher :count?, <<~PATTERN
         
     | 
| 
      
 60 
     | 
    
         
            +
                      (send {#array? #hash?} :count)
         
     | 
| 
      
 61 
     | 
    
         
            +
                    PATTERN
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
       29 
63 
     | 
    
         
             
                    def on_send(node)
         
     | 
| 
       30 
     | 
    
         
            -
                      return  
     | 
| 
      
 64 
     | 
    
         
            +
                      return if node.parent&.block_type? || !count?(node)
         
     | 
| 
       31 
65 
     | 
    
         | 
| 
       32 
66 
     | 
    
         
             
                      add_offense(node, location: :selector)
         
     | 
| 
       33 
67 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -35,42 +69,6 @@ module RuboCop 
     | 
|
| 
       35 
69 
     | 
    
         
             
                    def autocorrect(node)
         
     | 
| 
       36 
70 
     | 
    
         
             
                      ->(corrector) { corrector.replace(node.loc.selector, 'size') }
         
     | 
| 
       37 
71 
     | 
    
         
             
                    end
         
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
                    private
         
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
                    def eligible_node?(node)
         
     | 
| 
       42 
     | 
    
         
            -
                      return false unless node.method?(:count) && !node.arguments?
         
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
     | 
    
         
            -
                      eligible_receiver?(node.receiver) && !allowed_parent?(node.parent)
         
     | 
| 
       45 
     | 
    
         
            -
                    end
         
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
                    def eligible_receiver?(node)
         
     | 
| 
       48 
     | 
    
         
            -
                      return false unless node
         
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
       50 
     | 
    
         
            -
                      array?(node) || hash?(node)
         
     | 
| 
       51 
     | 
    
         
            -
                    end
         
     | 
| 
       52 
     | 
    
         
            -
             
     | 
| 
       53 
     | 
    
         
            -
                    def allowed_parent?(node)
         
     | 
| 
       54 
     | 
    
         
            -
                      node&.block_type?
         
     | 
| 
       55 
     | 
    
         
            -
                    end
         
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
                    def array?(node)
         
     | 
| 
       58 
     | 
    
         
            -
                      return true if node.array_type?
         
     | 
| 
       59 
     | 
    
         
            -
                      return false unless node.send_type?
         
     | 
| 
       60 
     | 
    
         
            -
             
     | 
| 
       61 
     | 
    
         
            -
                      _, constant = *node.receiver
         
     | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
       63 
     | 
    
         
            -
                      constant == :Array || node.method?(:to_a)
         
     | 
| 
       64 
     | 
    
         
            -
                    end
         
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
                    def hash?(node)
         
     | 
| 
       67 
     | 
    
         
            -
                      return true if node.hash_type?
         
     | 
| 
       68 
     | 
    
         
            -
                      return false unless node.send_type?
         
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
                      _, constant = *node.receiver
         
     | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
       72 
     | 
    
         
            -
                      constant == :Hash || node.method?(:to_h)
         
     | 
| 
       73 
     | 
    
         
            -
                    end
         
     | 
| 
       74 
72 
     | 
    
         
             
                  end
         
     | 
| 
       75 
73 
     | 
    
         
             
                end
         
     | 
| 
       76 
74 
     | 
    
         
             
              end
         
     | 
| 
         @@ -0,0 +1,54 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module RuboCop
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Cop
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Performance
         
     | 
| 
      
 6 
     | 
    
         
            +
                  # This cop identifies places where `sort { |a, b| b <=> a }`
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # can be replaced by a faster `sort.reverse`.
         
     | 
| 
      
 8 
     | 
    
         
            +
                  #
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # @example
         
     | 
| 
      
 10 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 11 
     | 
    
         
            +
                  #   array.sort { |a, b| b <=> a }
         
     | 
| 
      
 12 
     | 
    
         
            +
                  #
         
     | 
| 
      
 13 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 14 
     | 
    
         
            +
                  #   array.sort.reverse
         
     | 
| 
      
 15 
     | 
    
         
            +
                  #
         
     | 
| 
      
 16 
     | 
    
         
            +
                  class SortReverse < Cop
         
     | 
| 
      
 17 
     | 
    
         
            +
                    include SortBlock
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                    MSG = 'Use `sort.reverse` instead of `%<bad_method>s`.'
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                    def on_block(node)
         
     | 
| 
      
 22 
     | 
    
         
            +
                      sort_with_block?(node) do |send, var_a, var_b, body|
         
     | 
| 
      
 23 
     | 
    
         
            +
                        replaceable_body?(body, var_b, var_a) do
         
     | 
| 
      
 24 
     | 
    
         
            +
                          range = sort_range(send, node)
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                          add_offense(
         
     | 
| 
      
 27 
     | 
    
         
            +
                            node,
         
     | 
| 
      
 28 
     | 
    
         
            +
                            location: range,
         
     | 
| 
      
 29 
     | 
    
         
            +
                            message: message(var_a, var_b)
         
     | 
| 
      
 30 
     | 
    
         
            +
                          )
         
     | 
| 
      
 31 
     | 
    
         
            +
                        end
         
     | 
| 
      
 32 
     | 
    
         
            +
                      end
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                    def autocorrect(node)
         
     | 
| 
      
 36 
     | 
    
         
            +
                      sort_with_block?(node) do |send, _var_a, _var_b, _body|
         
     | 
| 
      
 37 
     | 
    
         
            +
                        lambda do |corrector|
         
     | 
| 
      
 38 
     | 
    
         
            +
                          range = sort_range(send, node)
         
     | 
| 
      
 39 
     | 
    
         
            +
                          replacement = 'sort.reverse'
         
     | 
| 
      
 40 
     | 
    
         
            +
                          corrector.replace(range, replacement)
         
     | 
| 
      
 41 
     | 
    
         
            +
                        end
         
     | 
| 
      
 42 
     | 
    
         
            +
                      end
         
     | 
| 
      
 43 
     | 
    
         
            +
                    end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                    private
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                    def message(var_a, var_b)
         
     | 
| 
      
 48 
     | 
    
         
            +
                      bad_method = "sort { |#{var_a}, #{var_b}| #{var_b} <=> #{var_a} }"
         
     | 
| 
      
 49 
     | 
    
         
            +
                      format(MSG, bad_method: bad_method)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    end
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
              end
         
     | 
| 
      
 54 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,70 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module RuboCop
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Cop
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Performance
         
     | 
| 
      
 6 
     | 
    
         
            +
                  # This cop identifies places where `gsub(/a+/, 'a')` and `gsub!(/a+/, 'a')`
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # can be replaced by `squeeze('a')` and `squeeze!('a')`.
         
     | 
| 
      
 8 
     | 
    
         
            +
                  #
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # The `squeeze('a')` method is faster than `gsub(/a+/, 'a')`.
         
     | 
| 
      
 10 
     | 
    
         
            +
                  #
         
     | 
| 
      
 11 
     | 
    
         
            +
                  # @example
         
     | 
| 
      
 12 
     | 
    
         
            +
                  #
         
     | 
| 
      
 13 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 14 
     | 
    
         
            +
                  #   str.gsub(/a+/, 'a')
         
     | 
| 
      
 15 
     | 
    
         
            +
                  #   str.gsub!(/a+/, 'a')
         
     | 
| 
      
 16 
     | 
    
         
            +
                  #
         
     | 
| 
      
 17 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 18 
     | 
    
         
            +
                  #   str.squeeze('a')
         
     | 
| 
      
 19 
     | 
    
         
            +
                  #   str.squeeze!('a')
         
     | 
| 
      
 20 
     | 
    
         
            +
                  #
         
     | 
| 
      
 21 
     | 
    
         
            +
                  class Squeeze < Cop
         
     | 
| 
      
 22 
     | 
    
         
            +
                    MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                    PREFERRED_METHODS = {
         
     | 
| 
      
 25 
     | 
    
         
            +
                      gsub: :squeeze,
         
     | 
| 
      
 26 
     | 
    
         
            +
                      gsub!: :squeeze!
         
     | 
| 
      
 27 
     | 
    
         
            +
                    }.freeze
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                    def_node_matcher :squeeze_candidate?, <<~PATTERN
         
     | 
| 
      
 30 
     | 
    
         
            +
                      (send
         
     | 
| 
      
 31 
     | 
    
         
            +
                        $!nil? ${:gsub :gsub!}
         
     | 
| 
      
 32 
     | 
    
         
            +
                        (regexp
         
     | 
| 
      
 33 
     | 
    
         
            +
                          (str $#repeating_literal?)
         
     | 
| 
      
 34 
     | 
    
         
            +
                          (regopt))
         
     | 
| 
      
 35 
     | 
    
         
            +
                        (str $_))
         
     | 
| 
      
 36 
     | 
    
         
            +
                    PATTERN
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                    def on_send(node)
         
     | 
| 
      
 39 
     | 
    
         
            +
                      squeeze_candidate?(node) do |_, bad_method, regexp_str, replace_str|
         
     | 
| 
      
 40 
     | 
    
         
            +
                        regexp_str = regexp_str[0..-2] # delete '+' from the end
         
     | 
| 
      
 41 
     | 
    
         
            +
                        regexp_str = interpret_string_escapes(regexp_str)
         
     | 
| 
      
 42 
     | 
    
         
            +
                        return unless replace_str == regexp_str
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                        good_method = PREFERRED_METHODS[bad_method]
         
     | 
| 
      
 45 
     | 
    
         
            +
                        message = format(MSG, current: bad_method, prefer: good_method)
         
     | 
| 
      
 46 
     | 
    
         
            +
                        add_offense(node, location: :selector, message: message)
         
     | 
| 
      
 47 
     | 
    
         
            +
                      end
         
     | 
| 
      
 48 
     | 
    
         
            +
                    end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    def autocorrect(node)
         
     | 
| 
      
 51 
     | 
    
         
            +
                      squeeze_candidate?(node) do |receiver, bad_method, _regexp_str, replace_str|
         
     | 
| 
      
 52 
     | 
    
         
            +
                        lambda do |corrector|
         
     | 
| 
      
 53 
     | 
    
         
            +
                          good_method = PREFERRED_METHODS[bad_method]
         
     | 
| 
      
 54 
     | 
    
         
            +
                          string_literal = to_string_literal(replace_str)
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                          new_code = "#{receiver.source}.#{good_method}(#{string_literal})"
         
     | 
| 
      
 57 
     | 
    
         
            +
                          corrector.replace(node.source_range, new_code)
         
     | 
| 
      
 58 
     | 
    
         
            +
                        end
         
     | 
| 
      
 59 
     | 
    
         
            +
                      end
         
     | 
| 
      
 60 
     | 
    
         
            +
                    end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                    private
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                    def repeating_literal?(regex_str)
         
     | 
| 
      
 65 
     | 
    
         
            +
                      regex_str.match?(/\A(?:#{Util::LITERAL_REGEX})\+\z/)
         
     | 
| 
      
 66 
     | 
    
         
            +
                    end
         
     | 
| 
      
 67 
     | 
    
         
            +
                  end
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
              end
         
     | 
| 
      
 70 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,57 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module RuboCop
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Cop
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Performance
         
     | 
| 
      
 6 
     | 
    
         
            +
                  # This cop identifies unnecessary use of a regex where
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # `String#include?` would suffice.
         
     | 
| 
      
 8 
     | 
    
         
            +
                  #
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # @example
         
     | 
| 
      
 10 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 11 
     | 
    
         
            +
                  #   'abc'.match?(/ab/)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  #   /ab/.match?('abc')
         
     | 
| 
      
 13 
     | 
    
         
            +
                  #   'abc' =~ /ab/
         
     | 
| 
      
 14 
     | 
    
         
            +
                  #   /ab/ =~ 'abc'
         
     | 
| 
      
 15 
     | 
    
         
            +
                  #   'abc'.match(/ab/)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  #   /ab/.match('abc')
         
     | 
| 
      
 17 
     | 
    
         
            +
                  #
         
     | 
| 
      
 18 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 19 
     | 
    
         
            +
                  #   'abc'.include?('ab')
         
     | 
| 
      
 20 
     | 
    
         
            +
                  class StringInclude < Cop
         
     | 
| 
      
 21 
     | 
    
         
            +
                    MSG = 'Use `String#include?` instead of a regex match with literal-only pattern.'
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                    def_node_matcher :redundant_regex?, <<~PATTERN
         
     | 
| 
      
 24 
     | 
    
         
            +
                      {(send $!nil? {:match :=~ :match?} (regexp (str $#literal?) (regopt)))
         
     | 
| 
      
 25 
     | 
    
         
            +
                       (send (regexp (str $#literal?) (regopt)) {:match :match?} $str)
         
     | 
| 
      
 26 
     | 
    
         
            +
                       (match-with-lvasgn (regexp (str $#literal?) (regopt)) $_)}
         
     | 
| 
      
 27 
     | 
    
         
            +
                    PATTERN
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                    def on_send(node)
         
     | 
| 
      
 30 
     | 
    
         
            +
                      return unless redundant_regex?(node)
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                      add_offense(node)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
                    alias on_match_with_lvasgn on_send
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                    def autocorrect(node)
         
     | 
| 
      
 37 
     | 
    
         
            +
                      redundant_regex?(node) do |receiver, regex_str|
         
     | 
| 
      
 38 
     | 
    
         
            +
                        receiver, regex_str = regex_str, receiver if receiver.is_a?(String)
         
     | 
| 
      
 39 
     | 
    
         
            +
                        regex_str = interpret_string_escapes(regex_str)
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                        lambda do |corrector|
         
     | 
| 
      
 42 
     | 
    
         
            +
                          new_source = receiver.source + '.include?(' +
         
     | 
| 
      
 43 
     | 
    
         
            +
                                       to_string_literal(regex_str) + ')'
         
     | 
| 
      
 44 
     | 
    
         
            +
                          corrector.replace(node.source_range, new_source)
         
     | 
| 
      
 45 
     | 
    
         
            +
                        end
         
     | 
| 
      
 46 
     | 
    
         
            +
                      end
         
     | 
| 
      
 47 
     | 
    
         
            +
                    end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                    private
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                    def literal?(regex_str)
         
     | 
| 
      
 52 
     | 
    
         
            +
                      regex_str.match?(/\A#{Util::LITERAL_REGEX}+\z/)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    end
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
              end
         
     | 
| 
      
 57 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,7 +1,10 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            require_relative 'mixin/regexp_metacharacter'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require_relative 'mixin/sort_block'
         
     | 
| 
       4 
5 
     | 
    
         | 
| 
      
 6 
     | 
    
         
            +
            require_relative 'performance/ancestors_include'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require_relative 'performance/big_decimal_with_numeric_argument'
         
     | 
| 
       5 
8 
     | 
    
         
             
            require_relative 'performance/bind_call'
         
     | 
| 
       6 
9 
     | 
    
         
             
            require_relative 'performance/caller'
         
     | 
| 
       7 
10 
     | 
    
         
             
            require_relative 'performance/case_when_splat'
         
     | 
| 
         @@ -18,13 +21,20 @@ require_relative 'performance/flat_map' 
     | 
|
| 
       18 
21 
     | 
    
         
             
            require_relative 'performance/inefficient_hash_search'
         
     | 
| 
       19 
22 
     | 
    
         
             
            require_relative 'performance/open_struct'
         
     | 
| 
       20 
23 
     | 
    
         
             
            require_relative 'performance/range_include'
         
     | 
| 
      
 24 
     | 
    
         
            +
            require_relative 'performance/io_readlines'
         
     | 
| 
       21 
25 
     | 
    
         
             
            require_relative 'performance/redundant_block_call'
         
     | 
| 
       22 
26 
     | 
    
         
             
            require_relative 'performance/redundant_match'
         
     | 
| 
       23 
27 
     | 
    
         
             
            require_relative 'performance/redundant_merge'
         
     | 
| 
      
 28 
     | 
    
         
            +
            require_relative 'performance/redundant_sort_block'
         
     | 
| 
      
 29 
     | 
    
         
            +
            require_relative 'performance/redundant_string_chars'
         
     | 
| 
       24 
30 
     | 
    
         
             
            require_relative 'performance/regexp_match'
         
     | 
| 
       25 
31 
     | 
    
         
             
            require_relative 'performance/reverse_each'
         
     | 
| 
      
 32 
     | 
    
         
            +
            require_relative 'performance/reverse_first'
         
     | 
| 
       26 
33 
     | 
    
         
             
            require_relative 'performance/size'
         
     | 
| 
      
 34 
     | 
    
         
            +
            require_relative 'performance/sort_reverse'
         
     | 
| 
      
 35 
     | 
    
         
            +
            require_relative 'performance/squeeze'
         
     | 
| 
       27 
36 
     | 
    
         
             
            require_relative 'performance/start_with'
         
     | 
| 
      
 37 
     | 
    
         
            +
            require_relative 'performance/string_include'
         
     | 
| 
       28 
38 
     | 
    
         
             
            require_relative 'performance/string_replacement'
         
     | 
| 
       29 
39 
     | 
    
         
             
            require_relative 'performance/times_map'
         
     | 
| 
       30 
40 
     | 
    
         
             
            require_relative 'performance/unfreeze_string'
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: rubocop-performance
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 1. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 1.7.0
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Bozhidar Batsov
         
     | 
| 
         @@ -10,7 +10,7 @@ authors: 
     | 
|
| 
       10 
10 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       11 
11 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       12 
12 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       13 
     | 
    
         
            -
            date: 2020- 
     | 
| 
      
 13 
     | 
    
         
            +
            date: 2020-07-07 00:00:00.000000000 Z
         
     | 
| 
       14 
14 
     | 
    
         
             
            dependencies:
         
     | 
| 
       15 
15 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       16 
16 
     | 
    
         
             
              name: rubocop
         
     | 
| 
         @@ -18,14 +18,14 @@ dependencies: 
     | 
|
| 
       18 
18 
     | 
    
         
             
                requirements:
         
     | 
| 
       19 
19 
     | 
    
         
             
                - - ">="
         
     | 
| 
       20 
20 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       21 
     | 
    
         
            -
                    version: 0. 
     | 
| 
      
 21 
     | 
    
         
            +
                    version: 0.82.0
         
     | 
| 
       22 
22 
     | 
    
         
             
              type: :runtime
         
     | 
| 
       23 
23 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       24 
24 
     | 
    
         
             
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       25 
25 
     | 
    
         
             
                requirements:
         
     | 
| 
       26 
26 
     | 
    
         
             
                - - ">="
         
     | 
| 
       27 
27 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       28 
     | 
    
         
            -
                    version: 0. 
     | 
| 
      
 28 
     | 
    
         
            +
                    version: 0.82.0
         
     | 
| 
       29 
29 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       30 
30 
     | 
    
         
             
              name: simplecov
         
     | 
| 
       31 
31 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
         @@ -55,6 +55,9 @@ files: 
     | 
|
| 
       55 
55 
     | 
    
         
             
            - config/default.yml
         
     | 
| 
       56 
56 
     | 
    
         
             
            - lib/rubocop-performance.rb
         
     | 
| 
       57 
57 
     | 
    
         
             
            - lib/rubocop/cop/mixin/regexp_metacharacter.rb
         
     | 
| 
      
 58 
     | 
    
         
            +
            - lib/rubocop/cop/mixin/sort_block.rb
         
     | 
| 
      
 59 
     | 
    
         
            +
            - lib/rubocop/cop/performance/ancestors_include.rb
         
     | 
| 
      
 60 
     | 
    
         
            +
            - lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb
         
     | 
| 
       58 
61 
     | 
    
         
             
            - lib/rubocop/cop/performance/bind_call.rb
         
     | 
| 
       59 
62 
     | 
    
         
             
            - lib/rubocop/cop/performance/caller.rb
         
     | 
| 
       60 
63 
     | 
    
         
             
            - lib/rubocop/cop/performance/case_when_splat.rb
         
     | 
| 
         @@ -70,15 +73,22 @@ files: 
     | 
|
| 
       70 
73 
     | 
    
         
             
            - lib/rubocop/cop/performance/fixed_size.rb
         
     | 
| 
       71 
74 
     | 
    
         
             
            - lib/rubocop/cop/performance/flat_map.rb
         
     | 
| 
       72 
75 
     | 
    
         
             
            - lib/rubocop/cop/performance/inefficient_hash_search.rb
         
     | 
| 
      
 76 
     | 
    
         
            +
            - lib/rubocop/cop/performance/io_readlines.rb
         
     | 
| 
       73 
77 
     | 
    
         
             
            - lib/rubocop/cop/performance/open_struct.rb
         
     | 
| 
       74 
78 
     | 
    
         
             
            - lib/rubocop/cop/performance/range_include.rb
         
     | 
| 
       75 
79 
     | 
    
         
             
            - lib/rubocop/cop/performance/redundant_block_call.rb
         
     | 
| 
       76 
80 
     | 
    
         
             
            - lib/rubocop/cop/performance/redundant_match.rb
         
     | 
| 
       77 
81 
     | 
    
         
             
            - lib/rubocop/cop/performance/redundant_merge.rb
         
     | 
| 
      
 82 
     | 
    
         
            +
            - lib/rubocop/cop/performance/redundant_sort_block.rb
         
     | 
| 
      
 83 
     | 
    
         
            +
            - lib/rubocop/cop/performance/redundant_string_chars.rb
         
     | 
| 
       78 
84 
     | 
    
         
             
            - lib/rubocop/cop/performance/regexp_match.rb
         
     | 
| 
       79 
85 
     | 
    
         
             
            - lib/rubocop/cop/performance/reverse_each.rb
         
     | 
| 
      
 86 
     | 
    
         
            +
            - lib/rubocop/cop/performance/reverse_first.rb
         
     | 
| 
       80 
87 
     | 
    
         
             
            - lib/rubocop/cop/performance/size.rb
         
     | 
| 
      
 88 
     | 
    
         
            +
            - lib/rubocop/cop/performance/sort_reverse.rb
         
     | 
| 
      
 89 
     | 
    
         
            +
            - lib/rubocop/cop/performance/squeeze.rb
         
     | 
| 
       81 
90 
     | 
    
         
             
            - lib/rubocop/cop/performance/start_with.rb
         
     | 
| 
      
 91 
     | 
    
         
            +
            - lib/rubocop/cop/performance/string_include.rb
         
     | 
| 
       82 
92 
     | 
    
         
             
            - lib/rubocop/cop/performance/string_replacement.rb
         
     | 
| 
       83 
93 
     | 
    
         
             
            - lib/rubocop/cop/performance/times_map.rb
         
     | 
| 
       84 
94 
     | 
    
         
             
            - lib/rubocop/cop/performance/unfreeze_string.rb
         
     | 
| 
         @@ -111,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       111 
121 
     | 
    
         
             
                - !ruby/object:Gem::Version
         
     | 
| 
       112 
122 
     | 
    
         
             
                  version: '0'
         
     | 
| 
       113 
123 
     | 
    
         
             
            requirements: []
         
     | 
| 
       114 
     | 
    
         
            -
            rubygems_version: 3.1. 
     | 
| 
      
 124 
     | 
    
         
            +
            rubygems_version: 3.1.4
         
     | 
| 
       115 
125 
     | 
    
         
             
            signing_key: 
         
     | 
| 
       116 
126 
     | 
    
         
             
            specification_version: 4
         
     | 
| 
       117 
127 
     | 
    
         
             
            summary: Automatic performance checking tool for Ruby code.
         
     |