rubocop 1.22.1 → 1.23.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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +43 -7
  4. data/lib/rubocop/cop/bundler/gem_comment.rb +3 -3
  5. data/lib/rubocop/cop/gemspec/date_assignment.rb +2 -10
  6. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +1 -10
  7. data/lib/rubocop/cop/gemspec/require_mfa.rb +146 -0
  8. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +30 -23
  9. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -10
  10. data/lib/rubocop/cop/generator.rb +1 -1
  11. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +60 -0
  12. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  13. data/lib/rubocop/cop/layout/assignment_indentation.rb +1 -1
  14. data/lib/rubocop/cop/layout/block_alignment.rb +3 -3
  15. data/lib/rubocop/cop/layout/dot_position.rb +9 -7
  16. data/lib/rubocop/cop/layout/empty_comment.rb +1 -1
  17. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +22 -1
  18. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +7 -4
  19. data/lib/rubocop/cop/layout/end_alignment.rb +1 -2
  20. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +1 -1
  21. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -1
  22. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  23. data/lib/rubocop/cop/layout/hash_alignment.rb +1 -1
  24. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
  25. data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
  26. data/lib/rubocop/cop/layout/line_length.rb +1 -1
  27. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
  28. data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -2
  29. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +1 -1
  30. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
  31. data/lib/rubocop/cop/layout/space_before_comment.rb +1 -1
  32. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +11 -5
  33. data/lib/rubocop/cop/layout/space_inside_parens.rb +0 -4
  34. data/lib/rubocop/cop/lint/ambiguous_range.rb +3 -3
  35. data/lib/rubocop/cop/lint/deprecated_constants.rb +3 -2
  36. data/lib/rubocop/cop/lint/else_layout.rb +1 -1
  37. data/lib/rubocop/cop/lint/number_conversion.rb +5 -2
  38. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +117 -0
  39. data/lib/rubocop/cop/metrics/parameter_lists.rb +5 -2
  40. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -2
  41. data/lib/rubocop/cop/mixin/gemspec_help.rb +30 -0
  42. data/lib/rubocop/cop/mixin/hash_transform_method.rb +3 -3
  43. data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +1 -1
  44. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
  45. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  46. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  47. data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
  48. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -5
  49. data/lib/rubocop/cop/mixin/trailing_body.rb +1 -1
  50. data/lib/rubocop/cop/naming/file_name.rb +37 -4
  51. data/lib/rubocop/cop/security/json_load.rb +1 -1
  52. data/lib/rubocop/cop/style/commented_keyword.rb +5 -3
  53. data/lib/rubocop/cop/style/documentation.rb +1 -1
  54. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  55. data/lib/rubocop/cop/style/format_string_token.rb +2 -1
  56. data/lib/rubocop/cop/style/line_end_concatenation.rb +1 -1
  57. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +1 -1
  58. data/lib/rubocop/cop/style/multiline_when_then.rb +1 -1
  59. data/lib/rubocop/cop/style/open_struct_use.rb +69 -0
  60. data/lib/rubocop/cop/style/parentheses_around_condition.rb +12 -2
  61. data/lib/rubocop/cop/style/quoted_symbols.rb +11 -1
  62. data/lib/rubocop/cop/style/select_by_regexp.rb +9 -3
  63. data/lib/rubocop/cop/util.rb +11 -1
  64. data/lib/rubocop/formatter/html_formatter.rb +5 -2
  65. data/lib/rubocop/formatter/json_formatter.rb +4 -1
  66. data/lib/rubocop/remote_config.rb +1 -1
  67. data/lib/rubocop/rspec/parallel_formatter.rb +90 -0
  68. data/lib/rubocop/rspec/support.rb +1 -0
  69. data/lib/rubocop/target_finder.rb +1 -1
  70. data/lib/rubocop/version.rb +1 -1
  71. data/lib/rubocop/yaml_duplication_checker.rb +1 -1
  72. data/lib/rubocop.rb +4 -0
  73. metadata +14 -7
@@ -65,21 +65,24 @@ module RuboCop
65
65
  MSG = 'Extra empty line detected %<location>s the `%<keyword>s`.'
66
66
 
67
67
  def on_def(node)
68
- check_body(node.body)
68
+ check_body(node.body, node.loc.line)
69
69
  end
70
70
  alias on_defs on_def
71
71
 
72
72
  def on_kwbegin(node)
73
73
  body, = *node
74
- check_body(body)
74
+ check_body(body, node.loc.line)
75
75
  end
76
76
 
77
77
  private
78
78
 
79
- def check_body(node)
80
- locations = keyword_locations(node)
79
+ def check_body(body, line_of_def_or_kwbegin)
80
+ locations = keyword_locations(body)
81
+
81
82
  locations.each do |loc|
82
83
  line = loc.line
84
+ next if line == line_of_def_or_kwbegin
85
+
83
86
  keyword = loc.source
84
87
  # below the keyword
85
88
  check_line(style, line, message('after', keyword), &:empty?)
@@ -165,8 +165,7 @@ module RuboCop
165
165
  end
166
166
 
167
167
  def alignment_node_for_variable_style(node)
168
- return node.parent if node.case_type? && node.argument? &&
169
- node.loc.line == node.parent.loc.line
168
+ return node.parent if node.case_type? && node.argument? && same_line?(node, node.parent)
170
169
 
171
170
  assignment = assignment_or_operator_method(node)
172
171
 
@@ -115,7 +115,7 @@ module RuboCop
115
115
  left_bracket = array_node.loc.begin
116
116
  first_elem = array_node.values.first
117
117
  if first_elem
118
- return if first_elem.source_range.line == left_bracket.line
118
+ return if same_line?(first_elem, left_bracket)
119
119
 
120
120
  check_first(first_elem, left_bracket, left_parenthesis, 0)
121
121
  end
@@ -116,7 +116,7 @@ module RuboCop
116
116
  first_pair = hash_node.pairs.first
117
117
 
118
118
  if first_pair
119
- return if first_pair.first_line == left_brace.line
119
+ return if same_line?(first_pair, left_brace)
120
120
 
121
121
  if separator_style?(first_pair)
122
122
  check_based_on_longest_key(hash_node, left_brace, left_parenthesis)
@@ -74,7 +74,7 @@ module RuboCop
74
74
  left_parenthesis = def_node.arguments.loc.begin
75
75
  first_elem = def_node.arguments.first
76
76
  return unless first_elem
77
- return if first_elem.source_range.line == left_parenthesis.line
77
+ return if same_line?(first_elem, left_parenthesis)
78
78
 
79
79
  check_first(first_elem, left_parenthesis, nil, 0)
80
80
  end
@@ -224,7 +224,7 @@ module RuboCop
224
224
 
225
225
  parent_loc = node.parent.loc
226
226
  selector = parent_loc.selector || parent_loc.expression
227
- selector.line == node.pairs.first.loc.line
227
+ same_line?(selector, node.pairs.first)
228
228
  end
229
229
 
230
230
  def reset!
@@ -167,7 +167,7 @@ module RuboCop
167
167
 
168
168
  end_of_outer_send = outermost_send.loc.end
169
169
 
170
- end_of_outer_send.line == end_of_last_arg_of_outer_send.line &&
170
+ same_line?(end_of_outer_send, end_of_last_arg_of_outer_send) &&
171
171
  end_of_outer_send.column == end_of_last_arg_of_outer_send.column + 1
172
172
  end
173
173
 
@@ -341,7 +341,7 @@ module RuboCop
341
341
  return true unless body_node
342
342
 
343
343
  # Don't check if expression is on same line as "then" keyword, etc.
344
- return true if body_node.loc.line == base_loc.line
344
+ return true if same_line?(body_node, base_loc)
345
345
 
346
346
  return true if starts_with_access_modifier?(body_node)
347
347
 
@@ -137,7 +137,7 @@ module RuboCop
137
137
  range = semicolon_token.pos
138
138
  end_pos = range.end_pos
139
139
  next_range = range_between(end_pos, end_pos + 1)
140
- return nil unless next_range.line == range.line
140
+ return nil unless same_line?(next_range, range)
141
141
 
142
142
  next_char = next_range.source
143
143
  return nil if /[\r\n]/.match?(next_char)
@@ -88,7 +88,7 @@ module RuboCop
88
88
  end
89
89
 
90
90
  def check_new_line_offense(node, rhs)
91
- return unless node.loc.operator.line == rhs.first_line
91
+ return unless same_line?(node.loc.operator, rhs)
92
92
 
93
93
  add_offense(node, message: NEW_LINE_OFFENSE) do |corrector|
94
94
  corrector.insert_after(node.loc.operator, "\n")
@@ -63,7 +63,7 @@ module RuboCop
63
63
  add_offense_for_expression(node, node.arguments, ARG_MSG)
64
64
  end
65
65
 
66
- return unless node.body && node.loc.begin.line == node.body.first_line
66
+ return unless node.body && same_line?(node.loc.begin, node.body)
67
67
 
68
68
  add_offense_for_expression(node, node.body, MSG)
69
69
  end
@@ -110,7 +110,7 @@ module RuboCop
110
110
 
111
111
  expr_before_body ||= node.loc.begin
112
112
 
113
- return unless expr_before_body.line == node.body.first_line
113
+ return unless same_line?(expr_before_body, node.body)
114
114
 
115
115
  autocorrect_body(corrector, node, node.body)
116
116
  end
@@ -75,7 +75,7 @@ module RuboCop
75
75
  def right_hand_side(send_node)
76
76
  dot = send_node.loc.dot
77
77
  selector = send_node.loc.selector
78
- if send_node.dot? && selector && dot.line == selector.line
78
+ if send_node.dot? && selector && same_line?(dot, selector)
79
79
  dot.join(selector)
80
80
  elsif selector
81
81
  selector
@@ -61,7 +61,7 @@ module RuboCop
61
61
  alignment_loc = alignment_location(alignment_node)
62
62
  kw_loc = node.loc.keyword
63
63
 
64
- return if alignment_loc.column == kw_loc.column || alignment_loc.line == kw_loc.line
64
+ return if alignment_loc.column == kw_loc.column || same_line?(alignment_loc, kw_loc)
65
65
 
66
66
  add_offense(
67
67
  kw_loc, message: format_message(alignment_node, alignment_loc, kw_loc)
@@ -20,7 +20,7 @@ module RuboCop
20
20
  def on_new_investigation
21
21
  processed_source.sorted_tokens.each_cons(2) do |token1, token2|
22
22
  next unless token2.comment?
23
- next unless token1.line == token2.line
23
+ next unless same_line?(token1, token2)
24
24
  next unless token1.pos.end == token2.pos.begin
25
25
 
26
26
  range = token2.pos
@@ -30,15 +30,17 @@ module RuboCop
30
30
  def on_send(node)
31
31
  return unless arrow_lambda_with_args?(node)
32
32
 
33
- lambda_node = range_of_offense(node)
34
-
35
33
  if style == :require_space && !space_after_arrow?(node)
34
+ lambda_node = range_of_offense(node)
35
+
36
36
  add_offense(lambda_node, message: MSG_REQUIRE_SPACE) do |corrector|
37
- corrector.insert_before(node.parent.children[1], ' ')
37
+ corrector.insert_before(lambda_arguments(node), ' ')
38
38
  end
39
39
  elsif style == :require_no_space && space_after_arrow?(node)
40
- add_offense(lambda_node, message: MSG_REQUIRE_NO_SPACE) do |corrector|
41
- corrector.remove(space_after_arrow(node))
40
+ space = space_after_arrow(node)
41
+
42
+ add_offense(space, message: MSG_REQUIRE_NO_SPACE) do |corrector|
43
+ corrector.remove(space)
42
44
  end
43
45
  end
44
46
  end
@@ -66,6 +68,10 @@ module RuboCop
66
68
  node.parent.arguments.loc.expression.end_pos
67
69
  )
68
70
  end
71
+
72
+ def lambda_arguments(node)
73
+ node.parent.children[1]
74
+ end
69
75
  end
70
76
  end
71
77
  end
@@ -146,10 +146,6 @@ module RuboCop
146
146
  end
147
147
  end
148
148
 
149
- def same_line?(token1, token2)
150
- token1.line == token2.line
151
- end
152
-
153
149
  def parens?(token1, token2)
154
150
  token1.left_parens? || token2.right_parens?
155
151
  end
@@ -8,7 +8,7 @@ module RuboCop
8
8
  # Ranges have quite low precedence, which leads to unexpected behaviour when
9
9
  # using a range with other operators. This cop avoids that by making ranges
10
10
  # explicit by requiring parenthesis around complex range boundaries (anything
11
- # that is not a basic literal: numerics, strings, symbols, etc.).
11
+ # that is not a literal: numerics, strings, symbols, etc.).
12
12
  #
13
13
  # This cop can be configured with `RequireParenthesesForMethodChains` in order to
14
14
  # specify whether method chains (including `self.foo`) should be wrapped in parens
@@ -81,8 +81,8 @@ module RuboCop
81
81
 
82
82
  def acceptable?(node)
83
83
  node.begin_type? ||
84
- node.basic_literal? ||
85
- node.variable? || node.const_type? ||
84
+ node.literal? ||
85
+ node.variable? || node.const_type? || node.self_type? ||
86
86
  (node.call_type? && acceptable_call?(node))
87
87
  end
88
88
 
@@ -42,11 +42,12 @@ module RuboCop
42
42
  # Maybe further investigation of RuboCop AST will lead to an essential solution.
43
43
  return unless node.loc
44
44
 
45
- constant = node.absolute? ? constant_name(node, node.short_name.to_s) : node.source
45
+ constant = node.absolute? ? constant_name(node, node.short_name) : node.source
46
46
  return unless (deprecated_constant = deprecated_constants[constant])
47
47
 
48
48
  alternative = deprecated_constant['Alternative']
49
49
  version = deprecated_constant['DeprecatedVersion']
50
+ return if target_ruby_version < version.to_f
50
51
 
51
52
  add_offense(node, message: message(alternative, node.source, version)) do |corrector|
52
53
  corrector.replace(node, alternative)
@@ -56,7 +57,7 @@ module RuboCop
56
57
  private
57
58
 
58
59
  def constant_name(node, nested_constant_name)
59
- return nested_constant_name unless node.namespace.const_type?
60
+ return nested_constant_name.to_s unless node.namespace.const_type?
60
61
 
61
62
  constant_name(node.namespace, "#{node.namespace.short_name}::#{nested_constant_name}")
62
63
  end
@@ -72,7 +72,7 @@ module RuboCop
72
72
  first_else = else_branch.begin_type? ? else_branch.children.first : else_branch
73
73
 
74
74
  return unless first_else
75
- return unless first_else.source_range.line == node.loc.else.line
75
+ return unless same_line?(first_else, node.loc.else)
76
76
 
77
77
  add_offense(first_else) { |corrector| autocorrect(corrector, node, first_else) }
78
78
  end
@@ -30,6 +30,7 @@ module RuboCop
30
30
  # '10'.to_i
31
31
  # '10.2'.to_f
32
32
  # '10'.to_c
33
+ # '1/3'.to_r
33
34
  # ['1', '2', '3'].map(&:to_i)
34
35
  # foo.try(:to_f)
35
36
  # bar.send(:to_c)
@@ -39,6 +40,7 @@ module RuboCop
39
40
  # Integer('10', 10)
40
41
  # Float('10.2')
41
42
  # Complex('10')
43
+ # Rational('1/3')
42
44
  # ['1', '2', '3'].map { |i| Integer(i, 10) }
43
45
  # foo.try { |i| Float(i) }
44
46
  # bar.send { |i| Complex(i) }
@@ -59,13 +61,14 @@ module RuboCop
59
61
  CONVERSION_METHOD_CLASS_MAPPING = {
60
62
  to_i: "#{Integer.name}(%<number_object>s, 10)",
61
63
  to_f: "#{Float.name}(%<number_object>s)",
62
- to_c: "#{Complex.name}(%<number_object>s)"
64
+ to_c: "#{Complex.name}(%<number_object>s)",
65
+ to_r: "#{Rational.name}(%<number_object>s)"
63
66
  }.freeze
64
67
  MSG = 'Replace unsafe number conversion with number '\
65
68
  'class parsing, instead of using '\
66
69
  '`%<current>s`, use stricter '\
67
70
  '`%<corrected_method>s`.'
68
- CONVERSION_METHODS = %i[Integer Float Complex to_i to_f to_c].freeze
71
+ CONVERSION_METHODS = %i[Integer Float Complex Rational to_i to_f to_c to_r].freeze
69
72
  METHODS = CONVERSION_METHOD_CLASS_MAPPING.keys.map(&:inspect).join(' ')
70
73
 
71
74
  # @!method to_method(node)
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop looks for `ruby2_keywords` calls for methods that do not need it.
7
+ #
8
+ # `ruby2_keywords` should only be called on methods that accept an argument splat
9
+ # (`*args`) but do not explicit keyword arguments (`k:` or `k: true`) or
10
+ # a keyword splat (`**kwargs`).
11
+ #
12
+ # @example
13
+ # # good (splat argument without keyword arguments)
14
+ # ruby2_keywords def foo(*args); end
15
+ #
16
+ # # bad (no arguments)
17
+ # ruby2_keywords def foo; end
18
+ #
19
+ # # good
20
+ # def foo; end
21
+ #
22
+ # # bad (positional argument)
23
+ # ruby2_keywords def foo(arg); end
24
+ #
25
+ # # good
26
+ # def foo(arg); end
27
+ #
28
+ # # bad (double splatted argument)
29
+ # ruby2_keywords def foo(**args); end
30
+ #
31
+ # # good
32
+ # def foo(**args); end
33
+ #
34
+ # # bad (keyword arguments)
35
+ # ruby2_keywords def foo(i:, j:); end
36
+ #
37
+ # # good
38
+ # def foo(i:, j:); end
39
+ #
40
+ # # bad (splat argument with keyword arguments)
41
+ # ruby2_keywords def foo(*args, i:, j:); end
42
+ #
43
+ # # good
44
+ # def foo(*args, i:, j:); end
45
+ #
46
+ # # bad (splat argument with double splat)
47
+ # ruby2_keywords def foo(*args, **kwargs); end
48
+ #
49
+ # # good
50
+ # def foo(*args, **kwargs); end
51
+ #
52
+ # # bad (ruby2_keywords given a symbol)
53
+ # def foo; end
54
+ # ruby2_keywords :foo
55
+ #
56
+ # # good
57
+ # def foo; end
58
+ #
59
+ # # bad (ruby2_keywords with dynamic method)
60
+ # define_method(:foo) { |arg| }
61
+ # ruby2_keywords :foo
62
+ #
63
+ # # good
64
+ # define_method(:foo) { |arg| }
65
+ #
66
+ class UselessRuby2Keywords < Base
67
+ MSG = '`ruby2_keywords` is unnecessary for method `%<method_name>s`.'
68
+ RESTRICT_ON_SEND = %i[ruby2_keywords].freeze
69
+
70
+ # Looks for statically or dynamically defined methods with a given name
71
+ # @!method method_definition(node, method_name)
72
+ def_node_matcher :method_definition, <<~PATTERN
73
+ {
74
+ (def %1 ...)
75
+ ({block numblock} (send _ :define_method (sym %1)) ...)
76
+ }
77
+ PATTERN
78
+
79
+ def on_send(node)
80
+ if node.first_argument.def_type?
81
+ inspect_def(node, node.first_argument)
82
+ elsif node.first_argument.sym_type?
83
+ inspect_sym(node, node.first_argument)
84
+ end
85
+ end
86
+
87
+ private
88
+
89
+ def inspect_def(node, def_node)
90
+ return if allowed_arguments(def_node.arguments)
91
+
92
+ add_offense(node.loc.selector, message: format(MSG, method_name: def_node.method_name))
93
+ end
94
+
95
+ def inspect_sym(node, sym_node)
96
+ return unless node.parent
97
+
98
+ method_name = sym_node.value
99
+ definition = node.parent.each_child_node.detect { |n| method_definition(n, method_name) }
100
+
101
+ return unless definition
102
+ return if allowed_arguments(definition.arguments)
103
+
104
+ add_offense(node, message: format(MSG, method_name: method_name))
105
+ end
106
+
107
+ # `ruby2_keywords` is only allowed if there's a `restarg` and no keyword arguments
108
+ def allowed_arguments(arguments)
109
+ return false if arguments.empty?
110
+
111
+ arguments.each_child_node(:restarg).any? &&
112
+ arguments.each_child_node(:kwarg, :kwoptarg, :kwrestarg).none?
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -9,6 +9,9 @@ module RuboCop
9
9
  # Keyword arguments can optionally be excluded from the total count,
10
10
  # as they add less complexity than positional or optional parameters.
11
11
  #
12
+ # NOTE: Explicit block argument `&block` is not counted to prevent
13
+ # erroneous change that is avoided by making block argument implicit.
14
+ #
12
15
  # @example Max: 3
13
16
  # # good
14
17
  # def foo(a, b, c = 1)
@@ -94,9 +97,9 @@ module RuboCop
94
97
 
95
98
  def args_count(node)
96
99
  if count_keyword_args?
97
- node.children.size
100
+ node.children.count { |a| !a.blockarg_type? }
98
101
  else
99
- node.children.count { |a| !NAMED_KEYWORD_TYPES.include?(a.type) }
102
+ node.children.count { |a| !NAMED_KEYWORD_TYPES.include?(a.type) && !a.blockarg_type? }
100
103
  end
101
104
  end
102
105
 
@@ -34,8 +34,7 @@ module RuboCop
34
34
 
35
35
  def matching_ranges(end_loc, align_ranges)
36
36
  align_ranges.select do |_, range|
37
- range.line == end_loc.line ||
38
- column_offset_between(range, end_loc).zero?
37
+ same_line?(range, end_loc) || column_offset_between(range, end_loc).zero?
39
38
  end
40
39
  end
41
40
 
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # Common functionality for checking gem declarations.
6
+ module GemspecHelp
7
+ extend NodePattern::Macros
8
+
9
+ # @!method gem_specification?(node)
10
+ def_node_matcher :gem_specification?, <<~PATTERN
11
+ (block
12
+ (send
13
+ (const
14
+ (const {cbase nil?} :Gem) :Specification) :new)
15
+ (args
16
+ (arg $_)) ...)
17
+ PATTERN
18
+
19
+ # @!method gem_specification(node)
20
+ def_node_search :gem_specification, <<~PATTERN
21
+ (block
22
+ (send
23
+ (const
24
+ (const {cbase nil?} :Gem) :Specification) :new)
25
+ (args
26
+ (arg $_)) ...)
27
+ PATTERN
28
+ end
29
+ end
30
+ end
@@ -139,9 +139,9 @@ module RuboCop
139
139
  end
140
140
 
141
141
  def self.from_map_to_h(node, match)
142
- strip_trailing_chars = 0
143
-
144
- unless node.parent&.block_type?
142
+ if node.parent&.block_type? && node.parent.send_node == node
143
+ strip_trailing_chars = 0
144
+ else
145
145
  map_range = node.children.first.source_range
146
146
  node_range = node.source_range
147
147
  strip_trailing_chars = node_range.end_pos - map_range.end_pos
@@ -15,7 +15,7 @@ module RuboCop
15
15
  node.arguments.each do |arg|
16
16
  on_node(type, arg, :send) do |type_node|
17
17
  left_brace = type_node.loc.begin
18
- if left_brace && left_brace.line == left_parenthesis.line
18
+ if left_brace && same_line?(left_brace, left_parenthesis)
19
19
  yield type_node, left_parenthesis
20
20
  ignore_node(type_node)
21
21
  end
@@ -90,7 +90,7 @@ module RuboCop
90
90
  # This method depends on the fact that we have guarded
91
91
  # against implicit and empty literals.
92
92
  def opening_brace_on_same_line?(node)
93
- node.loc.begin.line == children(node).first.first_line
93
+ same_line?(node.loc.begin, children(node).first)
94
94
  end
95
95
 
96
96
  # This method depends on the fact that we have guarded
@@ -28,7 +28,7 @@ module RuboCop
28
28
  end
29
29
 
30
30
  def space_missing?(token1, token2)
31
- token1.line == token2.line && token2.column == token1.column + offset
31
+ same_line?(token1, token2) && token2.column == token1.column + offset
32
32
  end
33
33
 
34
34
  def space_required_before?(token)
@@ -32,7 +32,7 @@ module RuboCop
32
32
  end
33
33
 
34
34
  def space_missing?(token1, token2)
35
- token1.line == token2.line && token2.begin_pos > token1.end_pos
35
+ same_line?(token1, token2) && token2.begin_pos > token1.end_pos
36
36
  end
37
37
 
38
38
  def space_required_after?(token)
@@ -54,7 +54,7 @@ module RuboCop
54
54
  end
55
55
 
56
56
  def first_line_comment(node)
57
- comment = processed_source.find_comment { |c| c.loc.line == node.loc.line }
57
+ comment = processed_source.find_comment { |c| same_line?(c, node) }
58
58
  return unless comment
59
59
 
60
60
  comment_source = comment.loc.expression.source
@@ -13,11 +13,7 @@ module RuboCop
13
13
  if style == :single_quotes
14
14
  !double_quotes_required?(src)
15
15
  else
16
- # The string needs single quotes if:
17
- # 1. It contains a double quote
18
- # 2. It contains text that would become an escape sequence with double quotes
19
- # 3. It contains text that would become an interpolation with double quotes
20
- !/" | (?<!\\)\\[abcefMnrtuUx0-7] | \#[@{$]/x.match?(src)
16
+ !/" | \\[^'\\] | \#[@{$]/x.match?(src)
21
17
  end
22
18
  end
23
19
  end
@@ -10,7 +10,7 @@ module RuboCop
10
10
  end
11
11
 
12
12
  def body_on_first_line?(node, body)
13
- node.source_range.first_line == body.source_range.first_line
13
+ same_line?(node, body)
14
14
  end
15
15
 
16
16
  def first_part_of(body)