rubocop 0.87.1 → 0.88.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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/bin/rubocop-profile +31 -0
  4. data/config/default.yml +57 -6
  5. data/lib/rubocop.rb +6 -0
  6. data/lib/rubocop/cli.rb +2 -2
  7. data/lib/rubocop/cli/command/auto_genenerate_config.rb +2 -2
  8. data/lib/rubocop/config_loader.rb +20 -7
  9. data/lib/rubocop/config_store.rb +4 -0
  10. data/lib/rubocop/cop/autocorrect_logic.rb +1 -1
  11. data/lib/rubocop/cop/badge.rb +1 -1
  12. data/lib/rubocop/cop/base.rb +12 -4
  13. data/lib/rubocop/cop/cop.rb +1 -1
  14. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +26 -0
  15. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +6 -1
  16. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
  17. data/lib/rubocop/cop/layout/end_alignment.rb +3 -2
  18. data/lib/rubocop/cop/layout/multiline_block_layout.rb +16 -5
  19. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +3 -2
  20. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +27 -68
  21. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +3 -2
  22. data/lib/rubocop/cop/lint/disjunctive_assignment_in_constructor.rb +8 -2
  23. data/lib/rubocop/cop/lint/duplicate_elsif_condition.rb +39 -0
  24. data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -2
  25. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +3 -2
  26. data/lib/rubocop/cop/lint/literal_as_condition.rb +11 -1
  27. data/lib/rubocop/cop/lint/nested_method_definition.rb +13 -19
  28. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +67 -0
  29. data/lib/rubocop/cop/mixin/statement_modifier.rb +3 -3
  30. data/lib/rubocop/cop/style/accessor_grouping.rb +8 -1
  31. data/lib/rubocop/cop/style/array_coercion.rb +63 -0
  32. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +3 -2
  33. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +5 -4
  34. data/lib/rubocop/cop/style/case_like_if.rb +217 -0
  35. data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
  36. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
  37. data/lib/rubocop/cop/style/exponential_notation.rb +6 -8
  38. data/lib/rubocop/cop/style/float_division.rb +7 -10
  39. data/lib/rubocop/cop/style/format_string_token.rb +5 -5
  40. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +62 -0
  41. data/lib/rubocop/cop/style/hash_like_case.rb +76 -0
  42. data/lib/rubocop/cop/style/if_unless_modifier.rb +11 -11
  43. data/lib/rubocop/cop/style/missing_else.rb +1 -11
  44. data/lib/rubocop/cop/style/numeric_predicate.rb +3 -4
  45. data/lib/rubocop/cop/style/parallel_assignment.rb +3 -3
  46. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  47. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +50 -0
  48. data/lib/rubocop/cop/style/redundant_sort.rb +3 -2
  49. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +3 -2
  50. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +9 -32
  51. data/lib/rubocop/cop/variable_force/variable.rb +5 -3
  52. data/lib/rubocop/file_finder.rb +12 -12
  53. data/lib/rubocop/path_util.rb +2 -17
  54. data/lib/rubocop/result_cache.rb +12 -8
  55. data/lib/rubocop/rspec/expect_offense.rb +31 -5
  56. data/lib/rubocop/rspec/shared_contexts.rb +12 -9
  57. data/lib/rubocop/runner.rb +5 -6
  58. data/lib/rubocop/target_finder.rb +2 -2
  59. data/lib/rubocop/version.rb +1 -1
  60. metadata +9 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 766878b5fd031a287c24a96e8545398cf26adca7b6ea1a3f6b0a3bd15ee07dda
4
- data.tar.gz: 8e33f8a7e7a15ada40bdfbba85c9568e8910c71871af11677f74499241d20c87
3
+ metadata.gz: f95eb2bcf68a27cd9069d1e7cf4fa1b9f4eb499649ccb8c60dcc7327b8bad6b1
4
+ data.tar.gz: 693a6483669b3c11ba0c181b5c1d502c937f34ea73b44710062f9a2a58b34c09
5
5
  SHA512:
6
- metadata.gz: dd87ec99764bc87637c84d50443a60611c87dabb23af42f5339b8911b60898b527e94bed74a1fb925d0ebe91d059041a1214dc7bb53a6d9c4e15a0bafab4c465
7
- data.tar.gz: d747fdfd2254f1b13a332d145aef2fb205afe4aae67c9fddc41d0bdbd6eff13c6f72af18426497ac98ae68a492abcc297892a41e0f2e766ac428029b69e3b9b4
6
+ metadata.gz: a49ca9e1823323f4478552d8217eb924d42e451b909169893e74ce3164c4438a6fce3d2222b1cfc08dc8f88131eae488dee6a98865887e561a8f298a3456dc07
7
+ data.tar.gz: 516d28b2f1d612e9e5a0abfd364ecab6940ef68ec0c2e755b170c43e1961621041b6346478fb59f044494e9d5c9300bfa1307bd580968468586b755b40fc161e
data/README.md CHANGED
@@ -49,7 +49,7 @@ haven't reached version 1.0 yet). To prevent an unwanted RuboCop update you
49
49
  might want to use a conservative version lock in your `Gemfile`:
50
50
 
51
51
  ```rb
52
- gem 'rubocop', '~> 0.87.1', require: false
52
+ gem 'rubocop', '~> 0.88.0', require: false
53
53
  ```
54
54
 
55
55
  ## Quickstart
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ if ARGV.include?('-h') || ARGV.include?('--help')
5
+ puts "Usage: same as main `rubocop` command but gathers profiling info"
6
+ puts "Additional option: `--memory` to print memory usage"
7
+ exit(0)
8
+ end
9
+ with_mem = ARGV.delete('--memory')
10
+
11
+ require 'stackprof'
12
+ if with_mem
13
+ require 'memory_profiler'
14
+ MemoryProfiler.start
15
+ end
16
+ StackProf.start
17
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
18
+ begin
19
+ load "#{__dir__}/../exe/rubocop"
20
+ ensure
21
+ delta = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
22
+ puts "Finished in #{delta.round(1)} seconds"
23
+ StackProf.stop
24
+ if with_mem
25
+ puts "Building memory report..."
26
+ report = MemoryProfiler.stop
27
+ end
28
+ Dir.mkdir('tmp') unless File.exist?('tmp')
29
+ StackProf.results('tmp/stackprof.dump')
30
+ report&.pretty_print(scale_bytes: true)
31
+ end
@@ -1397,12 +1397,18 @@ Lint/DisjunctiveAssignmentInConstructor:
1397
1397
  Enabled: true
1398
1398
  Safe: false
1399
1399
  VersionAdded: '0.62'
1400
+ VersionChanged: '0.88'
1400
1401
 
1401
1402
  Lint/DuplicateCaseCondition:
1402
1403
  Description: 'Do not repeat values in case conditionals.'
1403
1404
  Enabled: true
1404
1405
  VersionAdded: '0.45'
1405
1406
 
1407
+ Lint/DuplicateElsifCondition:
1408
+ Description: 'Do not repeat conditions used in if `elsif`.'
1409
+ Enabled: 'pending'
1410
+ VersionAdded: '0.88'
1411
+
1406
1412
  Lint/DuplicateHashKey:
1407
1413
  Description: 'Check for duplicate keys in hash literals.'
1408
1414
  Enabled: true
@@ -2179,17 +2185,18 @@ Naming/MethodParameterName:
2179
2185
  AllowNamesEndingInNumbers: true
2180
2186
  # Allowed names that will not register an offense
2181
2187
  AllowedNames:
2182
- - io
2183
- - id
2184
- - to
2188
+ - at
2185
2189
  - by
2186
- - 'on'
2190
+ - db
2191
+ - id
2187
2192
  - in
2188
- - at
2193
+ - io
2189
2194
  - ip
2190
- - db
2195
+ - of
2196
+ - 'on'
2191
2197
  - os
2192
2198
  - pp
2199
+ - to
2193
2200
  # Forbidden names that will register an offense
2194
2201
  ForbiddenNames: []
2195
2202
 
@@ -2340,6 +2347,14 @@ Style/AndOr:
2340
2347
  - always
2341
2348
  - conditionals
2342
2349
 
2350
+ Style/ArrayCoercion:
2351
+ Description: >-
2352
+ Use Array() instead of explicit Array check or [*var], when dealing
2353
+ with a variable you want to treat as an Array, but you're not certain it's an array.
2354
+ StyleGuide: '#array-coercion'
2355
+ Enabled: 'pending'
2356
+ VersionAdded: '0.88'
2357
+
2343
2358
  Style/ArrayJoin:
2344
2359
  Description: 'Use Array#join instead of Array#*.'
2345
2360
  StyleGuide: '#array-join'
@@ -2522,6 +2537,12 @@ Style/CaseEquality:
2522
2537
  # String === "string"
2523
2538
  AllowOnConstant: false
2524
2539
 
2540
+ Style/CaseLikeIf:
2541
+ Description: 'This cop identifies places where `if-elsif` constructions can be replaced with `case-when`.'
2542
+ StyleGuide: '#case-vs-if-else'
2543
+ Enabled: 'pending'
2544
+ VersionAdded: '0.88'
2545
+
2525
2546
  Style/CharacterLiteral:
2526
2547
  Description: 'Checks for uses of character literals.'
2527
2548
  StyleGuide: '#no-character-literals'
@@ -2961,6 +2982,18 @@ Style/GuardClause:
2961
2982
  # needs to have to trigger this cop
2962
2983
  MinBodyLength: 1
2963
2984
 
2985
+ Style/HashAsLastArrayItem:
2986
+ Description: >-
2987
+ Checks for presence or absence of braces around hash literal as a last
2988
+ array item depending on configuration.
2989
+ StyleGuide: '#hash-literal-as-last-array-item'
2990
+ Enabled: 'pending'
2991
+ VersionAdded: '0.88'
2992
+ EnforcedStyle: braces
2993
+ SupportedStyles:
2994
+ - braces
2995
+ - no_braces
2996
+
2964
2997
  Style/HashEachMethods:
2965
2998
  Description: 'Use Hash#each_key and Hash#each_value.'
2966
2999
  StyleGuide: '#hash-each'
@@ -2968,6 +3001,16 @@ Style/HashEachMethods:
2968
3001
  VersionAdded: '0.80'
2969
3002
  Safe: false
2970
3003
 
3004
+ Style/HashLikeCase:
3005
+ Description: >-
3006
+ Checks for places where `case-when` represents a simple 1:1
3007
+ mapping and can be replaced with a hash lookup.
3008
+ Enabled: 'pending'
3009
+ VersionAdded: '0.88'
3010
+ # `MinBranchesCount` defines the number of branches `case` needs to have
3011
+ # to trigger this cop
3012
+ MinBranchesCount: 3
3013
+
2971
3014
  Style/HashSyntax:
2972
3015
  Description: >-
2973
3016
  Prefer Ruby 1.9 hash syntax { a: 1, b: 2 } over 1.8 syntax
@@ -3665,6 +3708,14 @@ Style/RedundantFetchBlock:
3665
3708
  SafeForConstants: false
3666
3709
  VersionAdded: '0.86'
3667
3710
 
3711
+ Style/RedundantFileExtensionInRequire:
3712
+ Description: >-
3713
+ Checks for the presence of superfluous `.rb` extension in
3714
+ the filename provided to `require` and `require_relative`.
3715
+ StyleGuide: '#no-explicit-rb-to-require'
3716
+ Enabled: 'pending'
3717
+ VersionAdded: '0.88'
3718
+
3668
3719
  Style/RedundantFreeze:
3669
3720
  Description: "Checks usages of Object#freeze on immutable objects."
3670
3721
  Enabled: true
@@ -251,6 +251,7 @@ require_relative 'rubocop/cop/lint/deprecated_class_methods'
251
251
  require_relative 'rubocop/cop/lint/deprecated_open_ssl_constant'
252
252
  require_relative 'rubocop/cop/lint/disjunctive_assignment_in_constructor'
253
253
  require_relative 'rubocop/cop/lint/duplicate_case_condition'
254
+ require_relative 'rubocop/cop/lint/duplicate_elsif_condition'
254
255
  require_relative 'rubocop/cop/lint/duplicate_hash_key'
255
256
  require_relative 'rubocop/cop/lint/duplicate_methods'
256
257
  require_relative 'rubocop/cop/lint/each_with_object_argument'
@@ -360,6 +361,7 @@ require_relative 'rubocop/cop/style/access_modifier_declarations'
360
361
  require_relative 'rubocop/cop/style/accessor_grouping'
361
362
  require_relative 'rubocop/cop/style/alias'
362
363
  require_relative 'rubocop/cop/style/and_or'
364
+ require_relative 'rubocop/cop/style/array_coercion'
363
365
  require_relative 'rubocop/cop/style/array_join'
364
366
  require_relative 'rubocop/cop/style/ascii_comments'
365
367
  require_relative 'rubocop/cop/style/attr'
@@ -370,6 +372,7 @@ require_relative 'rubocop/cop/style/bisected_attr_accessor'
370
372
  require_relative 'rubocop/cop/style/block_comments'
371
373
  require_relative 'rubocop/cop/style/block_delimiters'
372
374
  require_relative 'rubocop/cop/style/case_equality'
375
+ require_relative 'rubocop/cop/style/case_like_if'
373
376
  require_relative 'rubocop/cop/style/character_literal'
374
377
  require_relative 'rubocop/cop/style/class_and_module_children'
375
378
  require_relative 'rubocop/cop/style/class_check'
@@ -413,7 +416,9 @@ require_relative 'rubocop/cop/style/format_string_token'
413
416
  require_relative 'rubocop/cop/style/frozen_string_literal_comment'
414
417
  require_relative 'rubocop/cop/style/global_vars'
415
418
  require_relative 'rubocop/cop/style/guard_clause'
419
+ require_relative 'rubocop/cop/style/hash_as_last_array_item'
416
420
  require_relative 'rubocop/cop/style/hash_each_methods'
421
+ require_relative 'rubocop/cop/style/hash_like_case'
417
422
  require_relative 'rubocop/cop/style/hash_syntax'
418
423
  require_relative 'rubocop/cop/style/hash_transform_keys'
419
424
  require_relative 'rubocop/cop/style/hash_transform_values'
@@ -434,6 +439,7 @@ require_relative 'rubocop/cop/style/method_call_without_args_parentheses'
434
439
  require_relative 'rubocop/cop/style/method_call_with_args_parentheses'
435
440
  require_relative 'rubocop/cop/style/redundant_assignment'
436
441
  require_relative 'rubocop/cop/style/redundant_fetch_block'
442
+ require_relative 'rubocop/cop/style/redundant_file_extension_in_require'
437
443
  require_relative 'rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses'
438
444
  require_relative 'rubocop/cop/style/method_call_with_args_parentheses/require_parentheses'
439
445
  require_relative 'rubocop/cop/style/method_called_on_do_end_block'
@@ -75,7 +75,7 @@ module RuboCop
75
75
 
76
76
  def validate_options_vs_config
77
77
  if @options[:parallel] &&
78
- !@config_store.for_dir(Dir.pwd).for_all_cops['UseCache']
78
+ !@config_store.for_pwd.for_all_cops['UseCache']
79
79
  raise OptionArgumentError, '-P/--parallel uses caching to speed up ' \
80
80
  'execution, so combining with AllCops: ' \
81
81
  'UseCache: false is not allowed.'
@@ -121,7 +121,7 @@ module RuboCop
121
121
  if @options[:auto_gen_config]
122
122
  formatter = 'autogenconf'
123
123
  else
124
- cfg = @config_store.for_dir(Dir.pwd).for_all_cops
124
+ cfg = @config_store.for_pwd.for_all_cops
125
125
  formatter = cfg['DefaultFormatter'] || 'progress'
126
126
  end
127
127
  [[formatter, @options[:output_path]]]
@@ -27,10 +27,10 @@ module RuboCop
27
27
  private
28
28
 
29
29
  def maybe_run_line_length_cop
30
- if !line_length_enabled?(@config_store.for_dir(Dir.pwd))
30
+ if !line_length_enabled?(@config_store.for_pwd)
31
31
  skip_line_length_cop(PHASE_1_DISABLED)
32
32
  elsif !same_max_line_length?(
33
- @config_store.for_dir(Dir.pwd), ConfigLoader.default_configuration
33
+ @config_store.for_pwd, ConfigLoader.default_configuration
34
34
  )
35
35
  skip_line_length_cop(PHASE_1_OVERRIDDEN)
36
36
  else
@@ -24,7 +24,7 @@ module RuboCop
24
24
 
25
25
  attr_accessor :debug, :ignore_parent_exclusion,
26
26
  :disable_pending_cops, :enable_pending_cops
27
- attr_writer :default_configuration
27
+ attr_writer :default_configuration, :project_root
28
28
 
29
29
  alias debug? debug
30
30
  alias ignore_parent_exclusion? ignore_parent_exclusion
@@ -118,14 +118,13 @@ module RuboCop
118
118
  end
119
119
 
120
120
  def add_excludes_from_files(config, config_file)
121
- found_files = find_files_upwards(DOTFILE, config_file)
121
+ exclusion_file = find_last_file_upwards(DOTFILE, config_file, project_root)
122
122
 
123
- return if found_files.empty?
124
- return if PathUtil.relative_path(found_files.last) ==
125
- PathUtil.relative_path(config_file)
123
+ return unless exclusion_file
124
+ return if PathUtil.relative_path(exclusion_file) == PathUtil.relative_path(config_file)
126
125
 
127
126
  print 'AllCops/Exclude ' if debug?
128
- config.add_excludes_from_higher_level(load_file(found_files.last))
127
+ config.add_excludes_from_higher_level(load_file(exclusion_file))
129
128
  end
130
129
 
131
130
  def default_configuration
@@ -135,6 +134,12 @@ module RuboCop
135
134
  end
136
135
  end
137
136
 
137
+ # Returns the path rubocop inferred as the root of the project. No file
138
+ # searches will go past this directory.
139
+ def project_root
140
+ @project_root ||= find_project_root
141
+ end
142
+
138
143
  def warn_on_pending_cops(pending_cops)
139
144
  return if pending_cops.empty?
140
145
 
@@ -159,7 +164,15 @@ module RuboCop
159
164
  private
160
165
 
161
166
  def find_project_dotfile(target_dir)
162
- find_file_upwards(DOTFILE, target_dir)
167
+ find_file_upwards(DOTFILE, target_dir, project_root)
168
+ end
169
+
170
+ def find_project_root
171
+ pwd = Dir.pwd
172
+ gems_file = find_last_file_upwards('Gemfile', pwd) || find_last_file_upwards('gems.rb', pwd)
173
+ return unless gems_file
174
+
175
+ File.dirname(gems_file)
163
176
  end
164
177
 
165
178
  def find_user_dotfile
@@ -33,6 +33,10 @@ module RuboCop
33
33
  for_dir(File.dirname(file))
34
34
  end
35
35
 
36
+ def for_pwd
37
+ for_dir(Dir.pwd)
38
+ end
39
+
36
40
  # If type (file/dir) is known beforehand,
37
41
  # prefer using #for_file or #for_dir for improved performance
38
42
  def for(file_or_dir)
@@ -73,7 +73,7 @@ module RuboCop
73
73
  end
74
74
 
75
75
  def max_line_length
76
- config.for_cop('Layout/LineLength')['Max'] || 80
76
+ config.for_cop('Layout/LineLength')['Max'] || 120
77
77
  end
78
78
 
79
79
  def disable_offense_at_end_of_line(range, eol_comment)
@@ -58,7 +58,7 @@ module RuboCop
58
58
  end
59
59
 
60
60
  def to_s
61
- qualified? ? "#{department}/#{cop_name}" : cop_name
61
+ @to_s ||= qualified? ? "#{department}/#{cop_name}" : cop_name
62
62
  end
63
63
 
64
64
  def qualified?
@@ -105,7 +105,7 @@ module RuboCop
105
105
  # If message is not specified, the method `message` will be called.
106
106
  def add_offense(node_or_range, message: nil, severity: nil, &block)
107
107
  range = range_from_node_or_range(node_or_range)
108
- return unless @current_offense_locations.add?(range)
108
+ return unless current_offense_locations.add?(range)
109
109
 
110
110
  range_to_pass = callback_argument(range)
111
111
 
@@ -271,11 +271,19 @@ module RuboCop
271
271
 
272
272
  ### Reserved for Commissioner:
273
273
 
274
+ def current_offense_locations
275
+ @current_offense_locations ||= Set.new
276
+ end
277
+
278
+ def currently_disabled_lines
279
+ @currently_disabled_lines ||= Set.new
280
+ end
281
+
274
282
  # Called before any investigation
275
283
  def begin_investigation(processed_source)
276
284
  @current_offenses = []
277
- @current_offense_locations = Set[]
278
- @currently_disabled_lines = Set[]
285
+ @current_offense_locations = nil
286
+ @currently_disabled_lines = nil
279
287
  @processed_source = processed_source
280
288
  @current_corrector = Corrector.new(@processed_source) if @processed_source.valid_syntax?
281
289
  end
@@ -327,7 +335,7 @@ module RuboCop
327
335
 
328
336
  def disable_uncorrectable(range)
329
337
  line = range.line
330
- return unless @currently_disabled_lines.add?(line)
338
+ return unless currently_disabled_lines.add?(line)
331
339
 
332
340
  disable_offense(range)
333
341
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'uri'
4
- require_relative 'legacy/corrections_proxy.rb'
4
+ require_relative 'legacy/corrections_proxy'
5
5
 
6
6
  module RuboCop
7
7
  module Cop
@@ -42,8 +42,34 @@ module RuboCop
42
42
 
43
43
  corrector.insert_before(
44
44
  last_element_range_with_trailing_comma(node).end,
45
+ content_if_comment_present(corrector, node)
46
+ )
47
+ end
48
+
49
+ def content_if_comment_present(corrector, node)
50
+ range = range_with_surrounding_space(
51
+ range: children(node).last.source_range,
52
+ side: :right
53
+ ).end.resize(1)
54
+ if range.source == '#'
55
+ select_content_to_be_inserted_after_last_element(corrector, node)
56
+ else
45
57
  node.loc.end.source
58
+ end
59
+ end
60
+
61
+ def select_content_to_be_inserted_after_last_element(corrector, node)
62
+ range = range_between(
63
+ node.loc.end.begin_pos,
64
+ range_by_whole_lines(node.loc.expression).end.end_pos
46
65
  )
66
+
67
+ remove_trailing_content_of_comment(corrector, range)
68
+ range.source
69
+ end
70
+
71
+ def remove_trailing_content_of_comment(corrector, range)
72
+ corrector.remove(range)
47
73
  end
48
74
 
49
75
  def last_element_range_with_trailing_comma(node)
@@ -35,6 +35,11 @@ module RuboCop
35
35
  # Gem::Specification.new do |spec|
36
36
  # spec.required_ruby_version = ['>= 2.5.0', '< 2.7.0']
37
37
  # end
38
+ #
39
+ # # good
40
+ # Gem::Specification.new do |spec|
41
+ # spec.required_ruby_version = '~> 2.5'
42
+ # end
38
43
  class RequiredRubyVersion < Cop
39
44
  MSG = '`required_ruby_version` (%<required_ruby_version>s, ' \
40
45
  'declared in %<gemspec_filename>s) and `TargetRubyVersion` ' \
@@ -68,7 +73,7 @@ module RuboCop
68
73
  end
69
74
  end
70
75
 
71
- required_ruby_version.str_content.match(/(\d\.\d)/)[1]
76
+ required_ruby_version.str_content.scan(/\d/).first(2).join('.')
72
77
  end
73
78
 
74
79
  def message(required_ruby_version, target_ruby_version)
@@ -109,6 +109,7 @@ module RuboCop
109
109
 
110
110
  def allowed_only_before_style?(node)
111
111
  if node.special_modifier?
112
+ return true if processed_source[node.last_line] == 'end'
112
113
  return false if next_line_empty?(node.last_line)
113
114
  end
114
115