rubocop 1.15.0 → 1.18.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +104 -31
  4. data/lib/rubocop.rb +7 -0
  5. data/lib/rubocop/cli/command/suggest_extensions.rb +3 -3
  6. data/lib/rubocop/config_loader.rb +1 -1
  7. data/lib/rubocop/config_validator.rb +5 -5
  8. data/lib/rubocop/cop/base.rb +2 -2
  9. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
  10. data/lib/rubocop/cop/bundler/gem_version.rb +38 -4
  11. data/lib/rubocop/cop/corrector.rb +4 -4
  12. data/lib/rubocop/cop/generator.rb +1 -1
  13. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  14. data/lib/rubocop/cop/layout/argument_alignment.rb +4 -3
  15. data/lib/rubocop/cop/layout/array_alignment.rb +2 -2
  16. data/lib/rubocop/cop/layout/block_alignment.rb +1 -1
  17. data/lib/rubocop/cop/layout/case_indentation.rb +57 -9
  18. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +7 -1
  19. data/lib/rubocop/cop/layout/comment_indentation.rb +1 -1
  20. data/lib/rubocop/cop/layout/dot_position.rb +7 -1
  21. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +13 -15
  22. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -2
  23. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -2
  24. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  25. data/lib/rubocop/cop/layout/hash_alignment.rb +26 -8
  26. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
  27. data/lib/rubocop/cop/layout/indentation_width.rb +8 -0
  28. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +122 -0
  29. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +6 -6
  30. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +2 -2
  31. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +6 -6
  32. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +6 -6
  33. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +6 -6
  34. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +3 -3
  35. data/lib/rubocop/cop/layout/parameter_alignment.rb +2 -2
  36. data/lib/rubocop/cop/layout/redundant_line_break.rb +11 -9
  37. data/lib/rubocop/cop/layout/space_around_keyword.rb +28 -0
  38. data/lib/rubocop/cop/layout/space_around_operators.rb +7 -1
  39. data/lib/rubocop/cop/lint/empty_in_pattern.rb +62 -0
  40. data/lib/rubocop/cop/lint/literal_as_condition.rb +13 -1
  41. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +32 -17
  42. data/lib/rubocop/cop/lint/nested_percent_literal.rb +1 -1
  43. data/lib/rubocop/cop/lint/percent_string_array.rb +1 -1
  44. data/lib/rubocop/cop/lint/percent_symbol_array.rb +1 -1
  45. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +105 -74
  46. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +5 -0
  47. data/lib/rubocop/cop/lint/symbol_conversion.rb +3 -13
  48. data/lib/rubocop/cop/lint/unused_block_argument.rb +1 -1
  49. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
  50. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  51. data/lib/rubocop/cop/migration/department_name.rb +3 -1
  52. data/lib/rubocop/cop/mixin/check_line_breakable.rb +10 -1
  53. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +14 -3
  54. data/lib/rubocop/cop/mixin/string_literals_help.rb +2 -4
  55. data/lib/rubocop/cop/mixin/symbol_help.rb +13 -0
  56. data/lib/rubocop/cop/naming/inclusive_language.rb +249 -0
  57. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +2 -2
  58. data/lib/rubocop/cop/style/class_and_module_children.rb +14 -0
  59. data/lib/rubocop/cop/style/hash_each_methods.rb +18 -1
  60. data/lib/rubocop/cop/style/identical_conditional_branches.rb +58 -8
  61. data/lib/rubocop/cop/style/in_pattern_then.rb +56 -0
  62. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -1
  63. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +62 -0
  64. data/lib/rubocop/cop/style/multiline_when_then.rb +2 -11
  65. data/lib/rubocop/cop/style/multiple_comparison.rb +1 -1
  66. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  67. data/lib/rubocop/cop/style/quoted_symbols.rb +110 -0
  68. data/lib/rubocop/cop/style/raise_args.rb +2 -0
  69. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
  70. data/lib/rubocop/cop/style/redundant_self.rb +24 -2
  71. data/lib/rubocop/cop/style/regexp_literal.rb +10 -1
  72. data/lib/rubocop/cop/style/special_global_vars.rb +3 -3
  73. data/lib/rubocop/cop/style/string_concatenation.rb +32 -5
  74. data/lib/rubocop/cop/style/string_literals.rb +3 -2
  75. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +1 -0
  76. data/lib/rubocop/cop/style/swap_values.rb +1 -1
  77. data/lib/rubocop/cop/style/top_level_method_definition.rb +10 -2
  78. data/lib/rubocop/cop/style/unpack_first.rb +1 -1
  79. data/lib/rubocop/cop/style/when_then.rb +6 -2
  80. data/lib/rubocop/cop/variable_force/variable_table.rb +1 -1
  81. data/lib/rubocop/directive_comment.rb +58 -6
  82. data/lib/rubocop/options.rb +4 -4
  83. data/lib/rubocop/rake_task.rb +1 -1
  84. data/lib/rubocop/remote_config.rb +10 -2
  85. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  86. data/lib/rubocop/rspec/expect_offense.rb +1 -1
  87. data/lib/rubocop/version.rb +1 -1
  88. metadata +12 -5
@@ -39,7 +39,7 @@ module RuboCop
39
39
  include RangeHelp
40
40
 
41
41
  MSG = 'Gem `%<gem_name>s` requirements already given on line '\
42
- '%<line_of_first_occurrence>d of the Gemfile.'
42
+ '%<line_of_first_occurrence>d of the Gemfile.'
43
43
 
44
44
  def on_new_investigation
45
45
  return if processed_source.blank?
@@ -3,8 +3,8 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Bundler
6
- # Enforce that Gem version specifications are either required
7
- # or forbidden.
6
+ # Enforce that Gem version specifications or a commit reference (branch,
7
+ # ref, or tag) are either required or forbidden.
8
8
  #
9
9
  # @example EnforcedStyle: required (default)
10
10
  # # bad
@@ -19,6 +19,15 @@ module RuboCop
19
19
  # # good
20
20
  # gem 'rubocop', '>= 1.5.0', '< 1.10.0'
21
21
  #
22
+ # # good
23
+ # gem 'rubocop', branch: 'feature-branch'
24
+ #
25
+ # # good
26
+ # gem 'rubocop', ref: '74b5bfbb2c4b6fd6cdbbc7254bd7084b36e0c85b'
27
+ #
28
+ # # good
29
+ # gem 'rubocop', tag: 'v1.17.0'
30
+ #
22
31
  # @example EnforcedStyle: forbidden
23
32
  # # good
24
33
  # gem 'rubocop'
@@ -32,6 +41,15 @@ module RuboCop
32
41
  # # bad
33
42
  # gem 'rubocop', '>= 1.5.0', '< 1.10.0'
34
43
  #
44
+ # # bad
45
+ # gem 'rubocop', branch: 'feature-branch'
46
+ #
47
+ # # bad
48
+ # gem 'rubocop', ref: '74b5bfbb2c4b6fd6cdbbc7254bd7084b36e0c85b'
49
+ #
50
+ # # bad
51
+ # gem 'rubocop', tag: 'v1.17.0'
52
+ #
35
53
  class GemVersion < Base
36
54
  include ConfigurableEnforcedStyle
37
55
  include GemDeclaration
@@ -45,6 +63,11 @@ module RuboCop
45
63
  (send nil? :gem <(str #version_specification?) ...>)
46
64
  PATTERN
47
65
 
66
+ # @!method includes_commit_reference?(node)
67
+ def_node_matcher :includes_commit_reference?, <<~PATTERN
68
+ (send nil? :gem <(hash <(pair (sym {:branch :ref :tag}) (str _)) ...>) ...>)
69
+ PATTERN
70
+
48
71
  def on_send(node)
49
72
  return unless gem_declaration?(node)
50
73
  return if allowed_gem?(node)
@@ -78,8 +101,19 @@ module RuboCop
78
101
  end
79
102
 
80
103
  def offense?(node)
81
- (required_style? && !includes_version_specification?(node)) ||
82
- (forbidden_style? && includes_version_specification?(node))
104
+ required_offense?(node) || forbidden_offense?(node)
105
+ end
106
+
107
+ def required_offense?(node)
108
+ return unless required_style?
109
+
110
+ !includes_version_specification?(node) && !includes_commit_reference?(node)
111
+ end
112
+
113
+ def forbidden_offense?(node)
114
+ return unless forbidden_style?
115
+
116
+ includes_version_specification?(node) || includes_commit_reference?(node)
83
117
  end
84
118
 
85
119
  def forbidden_style?
@@ -32,7 +32,7 @@ module RuboCop
32
32
 
33
33
  # Removes `size` characters prior to the source range.
34
34
  #
35
- # @param [Parser::Source::Range, Rubocop::AST::Node] range or node
35
+ # @param [Parser::Source::Range, RuboCop::AST::Node] range or node
36
36
  # @param [Integer] size
37
37
  def remove_preceding(node_or_range, size)
38
38
  range = to_range(node_or_range)
@@ -44,7 +44,7 @@ module RuboCop
44
44
  # If `size` is greater than the size of `range`, the removed region can
45
45
  # overrun the end of `range`.
46
46
  #
47
- # @param [Parser::Source::Range, Rubocop::AST::Node] range or node
47
+ # @param [Parser::Source::Range, RuboCop::AST::Node] range or node
48
48
  # @param [Integer] size
49
49
  def remove_leading(node_or_range, size)
50
50
  range = to_range(node_or_range)
@@ -56,7 +56,7 @@ module RuboCop
56
56
  # If `size` is greater than the size of `range`, the removed region can
57
57
  # overrun the beginning of `range`.
58
58
  #
59
- # @param [Parser::Source::Range, Rubocop::AST::Node] range or node
59
+ # @param [Parser::Source::Range, RuboCop::AST::Node] range or node
60
60
  # @param [Integer] size
61
61
  def remove_trailing(node_or_range, size)
62
62
  range = to_range(node_or_range)
@@ -90,7 +90,7 @@ module RuboCop
90
90
  else
91
91
  raise TypeError,
92
92
  'Expected a Parser::Source::Range, Comment or ' \
93
- "Rubocop::AST::Node, got #{node_or_range.class}"
93
+ "RuboCop::AST::Node, got #{node_or_range.class}"
94
94
  end
95
95
  validate_buffer(range.source_buffer)
96
96
  range
@@ -104,7 +104,7 @@ module RuboCop
104
104
 
105
105
  CONFIGURATION_ADDED_MESSAGE =
106
106
  '[modify] A configuration for the cop is added into ' \
107
- '%<configuration_file_path>s.'
107
+ '%<configuration_file_path>s.'
108
108
 
109
109
  def initialize(name, github_user, output: $stdout)
110
110
  @badge = Badge.parse(name)
@@ -25,7 +25,7 @@ module RuboCop
25
25
 
26
26
  MSG = 'Preceed `%<method>s` with a `@!method` YARD directive.'
27
27
  MSG_WRONG_NAME = '`@!method` YARD directive has invalid method name, ' \
28
- 'use `%<expected>s` instead of `%<actual>s`.'
28
+ 'use `%<expected>s` instead of `%<actual>s`.'
29
29
  MSG_TOO_MANY = 'Multiple `@!method` YARD directives found for this matcher.'
30
30
 
31
31
  RESTRICT_ON_SEND = %i[def_node_matcher def_node_search].to_set.freeze
@@ -50,14 +50,15 @@ module RuboCop
50
50
  ALIGN_PARAMS_MSG = 'Align the arguments of a method call if they span more than one line.'
51
51
 
52
52
  FIXED_INDENT_MSG = 'Use one level of indentation for arguments ' \
53
- 'following the first line of a multi-line method call.'
53
+ 'following the first line of a multi-line method call.'
54
54
 
55
55
  def on_send(node)
56
56
  first_arg = node.first_argument
57
57
  return if !multiple_arguments?(node, first_arg) || node.send_type? && node.method?(:[]=)
58
58
 
59
- if first_arg.hash_type?
60
- check_alignment(first_arg.pairs, base_column(node, first_arg.pairs.first))
59
+ if first_arg.hash_type? && !first_arg.braces?
60
+ pairs = first_arg.pairs
61
+ check_alignment(pairs, base_column(node, pairs.first))
61
62
  else
62
63
  check_alignment(node.arguments, base_column(node, first_arg))
63
64
  end
@@ -38,10 +38,10 @@ module RuboCop
38
38
  extend AutoCorrector
39
39
 
40
40
  ALIGN_ELEMENTS_MSG = 'Align the elements of an array literal ' \
41
- 'if they span more than one line.'
41
+ 'if they span more than one line.'
42
42
 
43
43
  FIXED_INDENT_MSG = 'Use one level of indentation for elements ' \
44
- 'following the first line of a multi-line array.'
44
+ 'following the first line of a multi-line array.'
45
45
 
46
46
  def on_array(node)
47
47
  return if node.children.size < 2
@@ -210,7 +210,7 @@ module RuboCop
210
210
 
211
211
  def format_source_line_column(source_line_column)
212
212
  "`#{source_line_column[:source]}` at #{source_line_column[:line]}, " \
213
- "#{source_line_column[:column]}"
213
+ "#{source_line_column[:column]}"
214
214
  end
215
215
 
216
216
  def compute_start_col(ancestor_node, node)
@@ -3,10 +3,10 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Layout
6
- # This cop checks how the ``when``s of a `case` expression
6
+ # This cop checks how the `when` and `in`s of a `case` expression
7
7
  # are indented in relation to its `case` or `end` keyword.
8
8
  #
9
- # It will register a separate offense for each misaligned `when`.
9
+ # It will register a separate offense for each misaligned `when` and `in`.
10
10
  #
11
11
  # @example
12
12
  # # If Layout/EndAlignment is set to keyword style (default)
@@ -22,6 +22,13 @@ module RuboCop
22
22
  # y / 3
23
23
  # end
24
24
  #
25
+ # case n
26
+ # in pattern
27
+ # x * 2
28
+ # else
29
+ # y / 3
30
+ # end
31
+ #
25
32
  # # good for all styles
26
33
  # case n
27
34
  # when 0
@@ -30,6 +37,13 @@ module RuboCop
30
37
  # y / 3
31
38
  # end
32
39
  #
40
+ # case n
41
+ # in pattern
42
+ # x * 2
43
+ # else
44
+ # y / 3
45
+ # end
46
+ #
33
47
  # @example EnforcedStyle: case (default)
34
48
  # # if EndAlignment is set to other style such as
35
49
  # # start_of_line (as shown below), then *when* alignment
@@ -43,6 +57,13 @@ module RuboCop
43
57
  # y / 3
44
58
  # end
45
59
  #
60
+ # a = case n
61
+ # in pattern
62
+ # x * 2
63
+ # else
64
+ # y / 3
65
+ # end
66
+ #
46
67
  # # good
47
68
  # a = case n
48
69
  # when 0
@@ -51,6 +72,13 @@ module RuboCop
51
72
  # y / 3
52
73
  # end
53
74
  #
75
+ # a = case n
76
+ # in pattern
77
+ # x * 2
78
+ # else
79
+ # y / 3
80
+ # end
81
+ #
54
82
  # @example EnforcedStyle: end
55
83
  # # bad
56
84
  # a = case n
@@ -60,6 +88,13 @@ module RuboCop
60
88
  # y / 3
61
89
  # end
62
90
  #
91
+ # a = case n
92
+ # in pattern
93
+ # x * 2
94
+ # else
95
+ # y / 3
96
+ # end
97
+ #
63
98
  # # good
64
99
  # a = case n
65
100
  # when 0
@@ -67,30 +102,43 @@ module RuboCop
67
102
  # else
68
103
  # y / 3
69
104
  # end
105
+ #
106
+ # a = case n
107
+ # in pattern
108
+ # x * 2
109
+ # else
110
+ # y / 3
111
+ # end
70
112
  class CaseIndentation < Base
71
113
  include Alignment
72
114
  include ConfigurableEnforcedStyle
73
115
  include RangeHelp
74
116
  extend AutoCorrector
75
117
 
76
- MSG = 'Indent `when` %<depth>s `%<base>s`.'
118
+ MSG = 'Indent `%<branch_type>s` %<depth>s `%<base>s`.'
77
119
 
78
120
  def on_case(case_node)
79
121
  return if case_node.single_line?
80
122
 
81
- case_node.each_when { |when_node| check_when(when_node) }
123
+ case_node.each_when { |when_node| check_when(when_node, 'when') }
124
+ end
125
+
126
+ def on_case_match(case_match_node)
127
+ return if case_match_node.single_line?
128
+
129
+ case_match_node.each_in_pattern { |in_pattern_node| check_when(in_pattern_node, 'in') }
82
130
  end
83
131
 
84
132
  private
85
133
 
86
- def check_when(when_node)
134
+ def check_when(when_node, branch_type)
87
135
  when_column = when_node.loc.keyword.column
88
136
  base_column = base_column(when_node.parent, style)
89
137
 
90
138
  if when_column == base_column + indentation_width
91
139
  correct_style_detected
92
140
  else
93
- incorrect_style(when_node)
141
+ incorrect_style(when_node, branch_type)
94
142
  end
95
143
  end
96
144
 
@@ -102,9 +150,9 @@ module RuboCop
102
150
  indent_one_step? ? configured_indentation_width : 0
103
151
  end
104
152
 
105
- def incorrect_style(when_node)
153
+ def incorrect_style(when_node, branch_type)
106
154
  depth = indent_one_step? ? 'one step more than' : 'as deep as'
107
- message = format(MSG, depth: depth, base: style)
155
+ message = format(MSG, branch_type: branch_type, depth: depth, base: style)
108
156
 
109
157
  add_offense(when_node.loc.keyword, message: message) do |corrector|
110
158
  detect_incorrect_style(when_node)
@@ -141,7 +189,7 @@ module RuboCop
141
189
  end
142
190
 
143
191
  def replacement(node)
144
- case_node = node.each_ancestor(:case).first
192
+ case_node = node.each_ancestor(:case, :case_match).first
145
193
  base_type = cop_config[style_parameter_name] == 'end' ? :end : :case
146
194
 
147
195
  column = base_column(case_node, base_type)
@@ -155,7 +155,13 @@ module RuboCop
155
155
  end
156
156
 
157
157
  def all_elements_aligned?(elements)
158
- elements.map { |e| e.loc.column }.uniq.count == 1
158
+ elements.flat_map do |e|
159
+ if e.hash_type?
160
+ e.each_pair.map { |pair| pair.loc.column }
161
+ else
162
+ e.loc.column
163
+ end
164
+ end.uniq.count == 1
159
165
  end
160
166
 
161
167
  def first_argument_line(elements)
@@ -37,7 +37,7 @@ module RuboCop
37
37
  extend AutoCorrector
38
38
 
39
39
  MSG = 'Incorrect indentation detected (column %<column>d ' \
40
- 'instead of %<correct_comment_indentation>d).'
40
+ 'instead of %<correct_comment_indentation>d).'
41
41
 
42
42
  def on_new_investigation
43
43
  processed_source.comments.each { |comment| check(comment) }
@@ -24,6 +24,7 @@ module RuboCop
24
24
  # method
25
25
  class DotPosition < Base
26
26
  include ConfigurableEnforcedStyle
27
+ include RangeHelp
27
28
  extend AutoCorrector
28
29
 
29
30
  def on_send(node)
@@ -42,7 +43,12 @@ module RuboCop
42
43
  private
43
44
 
44
45
  def autocorrect(corrector, dot, node)
45
- corrector.remove(dot)
46
+ dot_range = if processed_source[dot.line - 1].strip == '.'
47
+ range_by_whole_lines(dot, include_final_newline: true)
48
+ else
49
+ dot
50
+ end
51
+ corrector.remove(dot_range)
46
52
  case style
47
53
  when :leading
48
54
  corrector.insert_before(selector_range(node), dot.source)
@@ -45,8 +45,7 @@ module RuboCop
45
45
  def on_if(node)
46
46
  return if correct_style?(node)
47
47
 
48
- if node.modifier_form? && last_argument_is_heredoc?(node)
49
- heredoc_node = last_heredoc_argument(node)
48
+ if node.modifier_form? && (heredoc_node = last_heredoc_argument(node))
50
49
  return if next_line_empty_or_enable_directive_comment?(heredoc_line(node, heredoc_node))
51
50
 
52
51
  add_offense(heredoc_node.loc.heredoc_end) do |corrector|
@@ -62,7 +61,7 @@ module RuboCop
62
61
  private
63
62
 
64
63
  def autocorrect(corrector, node)
65
- node_range = if node.respond_to?(:heredoc?) && node.heredoc?
64
+ node_range = if heredoc?(node)
66
65
  range_by_whole_lines(node.loc.heredoc_body)
67
66
  else
68
67
  range_by_whole_lines(node.source_range)
@@ -125,19 +124,8 @@ module RuboCop
125
124
  next_sibling.if_type? && contains_guard_clause?(next_sibling)
126
125
  end
127
126
 
128
- def last_argument_is_heredoc?(node)
129
- last_children = node.if_branch
130
- return false unless last_children&.send_type?
131
-
132
- heredoc?(last_heredoc_argument(node))
133
- end
134
-
135
127
  def last_heredoc_argument(node)
136
- n = if node.respond_to?(:if_branch)
137
- node.if_branch.children.last
138
- else
139
- node
140
- end
128
+ n = last_heredoc_argument_node(node)
141
129
 
142
130
  return n if heredoc?(n)
143
131
  return unless n.respond_to?(:arguments)
@@ -150,6 +138,16 @@ module RuboCop
150
138
  return last_heredoc_argument(n.receiver) if n.respond_to?(:receiver)
151
139
  end
152
140
 
141
+ def last_heredoc_argument_node(node)
142
+ return node unless node.respond_to?(:if_branch)
143
+
144
+ if node.if_branch.and_type?
145
+ node.if_branch.children.first
146
+ else
147
+ node.if_branch.children.last
148
+ end
149
+ end
150
+
153
151
  def heredoc_line(node, heredoc_node)
154
152
  heredoc_body = heredoc_node.loc.heredoc_body
155
153
  num_of_heredoc_lines = heredoc_body.last_line - heredoc_body.first_line
@@ -161,10 +161,10 @@ module RuboCop
161
161
  'Indent the right bracket the same as the left bracket.'
162
162
  elsif style == :special_inside_parentheses && left_parenthesis
163
163
  'Indent the right bracket the same as the first position ' \
164
- 'after the preceding left parenthesis.'
164
+ 'after the preceding left parenthesis.'
165
165
  else
166
166
  'Indent the right bracket the same as the start of the line' \
167
- ' where the left bracket is.'
167
+ ' where the left bracket is.'
168
168
  end
169
169
  end
170
170
  end