rubocop 1.13.0 → 1.17.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/README.md +3 -1
- data/config/default.yml +68 -8
- data/lib/rubocop.rb +9 -0
- data/lib/rubocop/cop/bundler/gem_comment.rb +1 -3
- data/lib/rubocop/cop/bundler/gem_version.rb +99 -0
- data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
- data/lib/rubocop/cop/layout/argument_alignment.rb +29 -11
- data/lib/rubocop/cop/layout/case_indentation.rb +57 -9
- data/lib/rubocop/cop/layout/dot_position.rb +7 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +13 -15
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +12 -0
- data/lib/rubocop/cop/layout/hash_alignment.rb +34 -9
- data/lib/rubocop/cop/layout/indentation_width.rb +13 -2
- data/lib/rubocop/cop/layout/redundant_line_break.rb +24 -10
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +53 -0
- data/lib/rubocop/cop/layout/space_around_keyword.rb +28 -0
- data/lib/rubocop/cop/layout/space_around_operators.rb +6 -0
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +83 -39
- data/lib/rubocop/cop/lint/empty_block.rb +18 -2
- data/lib/rubocop/cop/lint/empty_in_pattern.rb +62 -0
- data/lib/rubocop/cop/lint/literal_as_condition.rb +13 -1
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +32 -17
- data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +105 -74
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +5 -0
- data/lib/rubocop/cop/lint/symbol_conversion.rb +2 -12
- data/lib/rubocop/cop/lint/unreachable_loop.rb +12 -2
- data/lib/rubocop/cop/lint/unused_block_argument.rb +7 -1
- data/lib/rubocop/cop/lint/void.rb +1 -1
- data/lib/rubocop/cop/migration/department_name.rb +3 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +19 -3
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +6 -0
- data/lib/rubocop/cop/mixin/gem_declaration.rb +13 -0
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +14 -3
- data/lib/rubocop/cop/mixin/string_literals_help.rb +3 -5
- data/lib/rubocop/cop/mixin/symbol_help.rb +13 -0
- data/lib/rubocop/cop/style/class_and_module_children.rb +17 -5
- data/lib/rubocop/cop/style/empty_literal.rb +8 -1
- data/lib/rubocop/cop/style/hash_each_methods.rb +18 -1
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +58 -8
- data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -4
- data/lib/rubocop/cop/style/in_pattern_then.rb +56 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -1
- data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +62 -0
- data/lib/rubocop/cop/style/multiline_when_then.rb +2 -11
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +17 -9
- data/lib/rubocop/cop/style/nil_lambda.rb +29 -12
- data/lib/rubocop/cop/style/quoted_symbols.rb +110 -0
- data/lib/rubocop/cop/style/raise_args.rb +2 -0
- data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
- data/lib/rubocop/cop/style/redundant_self.rb +24 -2
- data/lib/rubocop/cop/style/regexp_literal.rb +9 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +8 -3
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +14 -5
- data/lib/rubocop/cop/style/string_literals.rb +1 -0
- data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +1 -0
- data/lib/rubocop/cop/style/top_level_method_definition.rb +83 -0
- data/lib/rubocop/cop/style/trivial_accessors.rb +65 -0
- data/lib/rubocop/cop/style/when_then.rb +6 -2
- data/lib/rubocop/cop/variable_force/branch.rb +15 -0
- data/lib/rubocop/directive_comment.rb +58 -6
- data/lib/rubocop/formatter/junit_formatter.rb +21 -6
- data/lib/rubocop/options.rb +14 -20
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/remote_config.rb +10 -2
- data/lib/rubocop/rspec/shared_contexts.rb +4 -0
- data/lib/rubocop/target_finder.rb +9 -2
- data/lib/rubocop/target_ruby.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- metadata +18 -9
@@ -35,6 +35,12 @@ module RuboCop
|
|
35
35
|
leading_comment_lines.any? { |line| MagicComment.parse(line).frozen_string_literal? }
|
36
36
|
end
|
37
37
|
|
38
|
+
def frozen_string_literals_disabled?
|
39
|
+
leading_comment_lines.any? do |line|
|
40
|
+
MagicComment.parse(line).frozen_string_literal == false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
38
44
|
def frozen_string_literal_specified?
|
39
45
|
leading_comment_lines.any? do |line|
|
40
46
|
MagicComment.parse(line).frozen_string_literal_specified?
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# Common functionality for checking gem declarations.
|
6
|
+
module GemDeclaration
|
7
|
+
extend NodePattern::Macros
|
8
|
+
|
9
|
+
# @!method gem_declaration?(node)
|
10
|
+
def_node_matcher :gem_declaration?, '(send nil? :gem str ...)'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -43,7 +43,7 @@ module RuboCop
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def value_delta(pair)
|
46
|
-
return 0 if pair.
|
46
|
+
return 0 if pair.value_on_new_line?
|
47
47
|
|
48
48
|
correct_value_column = pair.loc.operator.end.column + 1
|
49
49
|
actual_value_column = pair.value.loc.column
|
@@ -108,8 +108,6 @@ module RuboCop
|
|
108
108
|
end
|
109
109
|
|
110
110
|
def value_delta(first_pair, current_pair)
|
111
|
-
return 0 if current_pair.kwsplat_type?
|
112
|
-
|
113
111
|
correct_value_column = first_pair.key.loc.column +
|
114
112
|
current_pair.delimiter(true).length +
|
115
113
|
max_key_width
|
@@ -139,6 +137,19 @@ module RuboCop
|
|
139
137
|
first_pair.value_delta(current_pair)
|
140
138
|
end
|
141
139
|
end
|
140
|
+
|
141
|
+
# Handles calculation of deltas for `kwsplat` nodes.
|
142
|
+
# This is a special case that just ensures the kwsplat is aligned with the rest of the hash
|
143
|
+
# since a `kwsplat` does not have a key, separator or value.
|
144
|
+
class KeywordSplatAlignment
|
145
|
+
def deltas(first_pair, current_pair)
|
146
|
+
if Util.begins_its_line?(current_pair.source_range)
|
147
|
+
{ key: first_pair.key_delta(current_pair) }
|
148
|
+
else
|
149
|
+
{}
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
142
153
|
end
|
143
154
|
end
|
144
155
|
end
|
@@ -4,18 +4,16 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
# Common functionality for cops checking single/double quotes.
|
6
6
|
module StringLiteralsHelp
|
7
|
-
include StringHelp
|
8
|
-
|
9
7
|
private
|
10
8
|
|
11
|
-
def wrong_quotes?(
|
12
|
-
src =
|
9
|
+
def wrong_quotes?(src_or_node)
|
10
|
+
src = src_or_node.is_a?(RuboCop::AST::Node) ? src_or_node.source : src_or_node
|
13
11
|
return false if src.start_with?('%', '?')
|
14
12
|
|
15
13
|
if style == :single_quotes
|
16
14
|
!double_quotes_required?(src)
|
17
15
|
else
|
18
|
-
!/" | \\[^'] | \#
|
16
|
+
!/" | \\[^'\\] | \#[@{$]/x.match?(src)
|
19
17
|
end
|
20
18
|
end
|
21
19
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# Classes that include this module just implement functions for working
|
6
|
+
# with symbol nodes.
|
7
|
+
module SymbolHelp
|
8
|
+
def hash_key?(node)
|
9
|
+
node.parent&.pair_type? && node == node.parent.child_nodes.first
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -87,9 +87,18 @@ module RuboCop
|
|
87
87
|
end
|
88
88
|
|
89
89
|
def compact_node(corrector, node)
|
90
|
-
replacement = "#{node.body.type} #{compact_identifier_name(node)}"
|
91
90
|
range = range_between(node.loc.keyword.begin_pos, node.body.loc.name.end_pos)
|
92
|
-
corrector.replace(range,
|
91
|
+
corrector.replace(range, compact_replacement(node))
|
92
|
+
end
|
93
|
+
|
94
|
+
def compact_replacement(node)
|
95
|
+
replacement = "#{node.body.type} #{compact_identifier_name(node)}"
|
96
|
+
|
97
|
+
body_comments = processed_source.ast_with_comments[node.body]
|
98
|
+
unless body_comments.empty?
|
99
|
+
replacement = body_comments.map(&:text).push(replacement).join("\n")
|
100
|
+
end
|
101
|
+
replacement
|
93
102
|
end
|
94
103
|
|
95
104
|
def compact_identifier_name(node)
|
@@ -132,7 +141,10 @@ module RuboCop
|
|
132
141
|
end
|
133
142
|
|
134
143
|
def check_compact_style(node, body)
|
135
|
-
|
144
|
+
parent = node.parent
|
145
|
+
return if parent&.class_type? || parent&.module_type?
|
146
|
+
|
147
|
+
return unless needs_compacting?(body)
|
136
148
|
|
137
149
|
add_offense(node.loc.name, message: COMPACT_MSG) do |corrector|
|
138
150
|
autocorrect(corrector, node)
|
@@ -145,12 +157,12 @@ module RuboCop
|
|
145
157
|
nest_or_compact(corrector, node)
|
146
158
|
end
|
147
159
|
|
148
|
-
def
|
160
|
+
def needs_compacting?(body)
|
149
161
|
body && %i[module class].include?(body.type)
|
150
162
|
end
|
151
163
|
|
152
164
|
def compact_node_name?(node)
|
153
|
-
/::/.match?(node.
|
165
|
+
/::/.match?(node.identifier.source)
|
154
166
|
end
|
155
167
|
end
|
156
168
|
end
|
@@ -62,7 +62,7 @@ module RuboCop
|
|
62
62
|
ARR_MSG
|
63
63
|
elsif offense_hash_node?(node)
|
64
64
|
HASH_MSG
|
65
|
-
elsif str_node(node) && !
|
65
|
+
elsif str_node(node) && !frozen_strings?
|
66
66
|
format(STR_MSG, prefer: preferred_string_literal)
|
67
67
|
end
|
68
68
|
end
|
@@ -125,6 +125,13 @@ module RuboCop
|
|
125
125
|
end
|
126
126
|
end
|
127
127
|
end
|
128
|
+
|
129
|
+
def frozen_strings?
|
130
|
+
return true if frozen_string_literals_enabled?
|
131
|
+
|
132
|
+
frozen_string_cop_enabled = config.for_cop('Style/FrozenStringLiteral')['Enabled']
|
133
|
+
frozen_string_cop_enabled && !frozen_string_literals_disabled?
|
134
|
+
end
|
128
135
|
end
|
129
136
|
end
|
130
137
|
end
|
@@ -17,6 +17,11 @@ module RuboCop
|
|
17
17
|
# # good
|
18
18
|
# hash.each_key { |k| p k }
|
19
19
|
# hash.each_value { |v| p v }
|
20
|
+
#
|
21
|
+
# @example AllowedReceivers: ['execute']
|
22
|
+
# # good
|
23
|
+
# execute(sql).keys.each { |v| p v }
|
24
|
+
# execute(sql).values.each { |v| p v }
|
20
25
|
class HashEachMethods < Base
|
21
26
|
include Lint::UnusedArgument
|
22
27
|
extend AutoCorrector
|
@@ -36,7 +41,9 @@ module RuboCop
|
|
36
41
|
|
37
42
|
def register_kv_offense(node)
|
38
43
|
kv_each(node) do |target, method|
|
39
|
-
|
44
|
+
parent_receiver = target.receiver.receiver
|
45
|
+
return unless parent_receiver
|
46
|
+
return if allowed_receiver?(parent_receiver)
|
40
47
|
|
41
48
|
msg = format(message, prefer: "each_#{method[0..-2]}", current: "#{method}.each")
|
42
49
|
|
@@ -80,6 +87,16 @@ module RuboCop
|
|
80
87
|
def kv_range(outer_node)
|
81
88
|
outer_node.receiver.loc.selector.join(outer_node.loc.selector)
|
82
89
|
end
|
90
|
+
|
91
|
+
def allowed_receiver?(receiver)
|
92
|
+
receiver_name = receiver.send_type? ? receiver.method_name.to_s : receiver.source
|
93
|
+
|
94
|
+
allowed_receivers.include?(receiver_name)
|
95
|
+
end
|
96
|
+
|
97
|
+
def allowed_receivers
|
98
|
+
cop_config.fetch('AllowedReceivers', [])
|
99
|
+
end
|
83
100
|
end
|
84
101
|
end
|
85
102
|
end
|
@@ -67,40 +67,90 @@ module RuboCop
|
|
67
67
|
# do_x
|
68
68
|
# do_z
|
69
69
|
# end
|
70
|
+
#
|
71
|
+
# # bad
|
72
|
+
# case foo
|
73
|
+
# in 1
|
74
|
+
# do_x
|
75
|
+
# in 2
|
76
|
+
# do_x
|
77
|
+
# else
|
78
|
+
# do_x
|
79
|
+
# end
|
80
|
+
#
|
81
|
+
# # good
|
82
|
+
# case foo
|
83
|
+
# in 1
|
84
|
+
# do_x
|
85
|
+
# do_y
|
86
|
+
# in 2
|
87
|
+
# # nothing
|
88
|
+
# else
|
89
|
+
# do_x
|
90
|
+
# do_z
|
91
|
+
# end
|
70
92
|
class IdenticalConditionalBranches < Base
|
93
|
+
include RangeHelp
|
94
|
+
extend AutoCorrector
|
95
|
+
|
71
96
|
MSG = 'Move `%<source>s` out of the conditional.'
|
72
97
|
|
73
98
|
def on_if(node)
|
74
99
|
return if node.elsif?
|
75
100
|
|
76
101
|
branches = expand_elses(node.else_branch).unshift(node.if_branch)
|
77
|
-
check_branches(branches)
|
102
|
+
check_branches(node, branches)
|
78
103
|
end
|
79
104
|
|
80
105
|
def on_case(node)
|
81
106
|
return unless node.else? && node.else_branch
|
82
107
|
|
83
108
|
branches = node.when_branches.map(&:body).push(node.else_branch)
|
84
|
-
check_branches(branches)
|
109
|
+
check_branches(node, branches)
|
110
|
+
end
|
111
|
+
|
112
|
+
def on_case_match(node)
|
113
|
+
return unless node.else? && node.else_branch
|
114
|
+
|
115
|
+
branches = node.in_pattern_branches.map(&:body).push(node.else_branch)
|
116
|
+
check_branches(node, branches)
|
85
117
|
end
|
86
118
|
|
87
119
|
private
|
88
120
|
|
89
|
-
def check_branches(branches)
|
121
|
+
def check_branches(node, branches)
|
90
122
|
# return if any branch is empty. An empty branch can be an `if`
|
91
123
|
# without an `else` or a branch that contains only comments.
|
92
124
|
return if branches.any?(&:nil?)
|
93
125
|
|
94
126
|
tails = branches.map { |branch| tail(branch) }
|
95
|
-
check_expressions(tails) if
|
127
|
+
check_expressions(node, tails, :after_condition) if duplicated_expressions?(tails)
|
128
|
+
|
96
129
|
heads = branches.map { |branch| head(branch) }
|
97
|
-
check_expressions(heads) if
|
130
|
+
check_expressions(node, heads, :before_condition) if duplicated_expressions?(heads)
|
98
131
|
end
|
99
132
|
|
100
|
-
def
|
101
|
-
|
133
|
+
def duplicated_expressions?(expressions)
|
134
|
+
expressions.size > 1 && expressions.uniq.one?
|
135
|
+
end
|
102
136
|
|
103
|
-
|
137
|
+
def check_expressions(node, expressions, insert_position)
|
138
|
+
inserted_expression = false
|
139
|
+
|
140
|
+
expressions.each do |expression|
|
141
|
+
add_offense(expression) do |corrector|
|
142
|
+
range = range_by_whole_lines(expression.source_range, include_final_newline: true)
|
143
|
+
corrector.remove(range)
|
144
|
+
next if inserted_expression
|
145
|
+
|
146
|
+
if insert_position == :after_condition
|
147
|
+
corrector.insert_after(node, "\n#{expression.source}")
|
148
|
+
else
|
149
|
+
corrector.insert_before(node, "#{expression.source}\n")
|
150
|
+
end
|
151
|
+
inserted_expression = true
|
152
|
+
end
|
153
|
+
end
|
104
154
|
end
|
105
155
|
|
106
156
|
def message(node)
|
@@ -67,15 +67,14 @@ module RuboCop
|
|
67
67
|
|
68
68
|
def autocorrect(corrector, node)
|
69
69
|
replacement = if node.modifier_form?
|
70
|
-
|
71
|
-
last_argument = node.if_branch.last_argument
|
70
|
+
last_argument = node.if_branch.last_argument if node.if_branch.send_type?
|
72
71
|
|
73
72
|
if last_argument.respond_to?(:heredoc?) && last_argument.heredoc?
|
74
73
|
heredoc = extract_heredoc_from(last_argument)
|
75
74
|
remove_heredoc(corrector, heredoc)
|
76
|
-
to_normal_form_with_heredoc(node,
|
75
|
+
to_normal_form_with_heredoc(node, indent(node), heredoc)
|
77
76
|
else
|
78
|
-
to_normal_form(node,
|
77
|
+
to_normal_form(node, indent(node))
|
79
78
|
end
|
80
79
|
else
|
81
80
|
to_modifier_form(node)
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop checks for `in;` uses in `case` expressions.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# case expression
|
11
|
+
# in pattern_a; foo
|
12
|
+
# in pattern_b; bar
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# case expression
|
17
|
+
# in pattern_a then foo
|
18
|
+
# in pattern_b then bar
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
class InPatternThen < Base
|
22
|
+
extend AutoCorrector
|
23
|
+
extend TargetRubyVersion
|
24
|
+
|
25
|
+
minimum_target_ruby_version 2.7
|
26
|
+
|
27
|
+
MSG = 'Do not use `in %<pattern>s;`. Use `in %<pattern>s then` instead.'
|
28
|
+
|
29
|
+
def on_in_pattern(node)
|
30
|
+
return if node.multiline? || node.then? || !node.body
|
31
|
+
|
32
|
+
pattern = node.pattern
|
33
|
+
pattern_source = if pattern.match_alt_type?
|
34
|
+
alternative_pattern_source(pattern)
|
35
|
+
else
|
36
|
+
pattern.source
|
37
|
+
end
|
38
|
+
|
39
|
+
add_offense(node.loc.begin, message: format(MSG, pattern: pattern_source)) do |corrector|
|
40
|
+
corrector.replace(node.loc.begin, ' then')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def alternative_pattern_source(pattern)
|
47
|
+
return pattern.children.map(&:source) unless pattern.children.first.match_alt_type?
|
48
|
+
|
49
|
+
pattern_sources = alternative_pattern_source(pattern.children.first)
|
50
|
+
|
51
|
+
(pattern_sources << pattern.children[1].source).join(' | ')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -116,7 +116,8 @@ module RuboCop
|
|
116
116
|
end
|
117
117
|
|
118
118
|
def call_with_braced_block?(node)
|
119
|
-
(node.send_type? || node.super_type?) &&
|
119
|
+
(node.send_type? || node.super_type?) &&
|
120
|
+
((node.parent&.block_type? || node.parent&.numblock_type?) && node.parent&.braces?)
|
120
121
|
end
|
121
122
|
|
122
123
|
def call_as_argument_or_chain?(node)
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop checks uses of the `then` keyword in multi-line `in` statement.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# case expression
|
11
|
+
# in pattern then
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# case expression
|
16
|
+
# in pattern
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# case expression
|
21
|
+
# in pattern then do_something
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# # good
|
25
|
+
# case expression
|
26
|
+
# in pattern then do_something(arg1,
|
27
|
+
# arg2)
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
class MultilineInPatternThen < Base
|
31
|
+
include RangeHelp
|
32
|
+
extend AutoCorrector
|
33
|
+
extend TargetRubyVersion
|
34
|
+
|
35
|
+
minimum_target_ruby_version 2.7
|
36
|
+
|
37
|
+
MSG = 'Do not use `then` for multiline `in` statement.'
|
38
|
+
|
39
|
+
def on_in_pattern(node)
|
40
|
+
return if !node.then? || require_then?(node)
|
41
|
+
|
42
|
+
range = node.loc.begin
|
43
|
+
add_offense(range) do |corrector|
|
44
|
+
corrector.remove(
|
45
|
+
range_with_surrounding_space(range: range, side: :left, newlines: false)
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
# Requires `then` for write `in` and its body on the same line.
|
53
|
+
def require_then?(in_pattern_node)
|
54
|
+
return true if in_pattern_node.pattern.first_line != in_pattern_node.pattern.last_line
|
55
|
+
return false unless in_pattern_node.body
|
56
|
+
|
57
|
+
in_pattern_node.loc.line == in_pattern_node.body.loc.line
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|