class RuboCop::Cop::Style::Next
Use ‘next` to skip iteration instead of a condition at the end.
@example EnforcedStyle: skip_modifier_ifs (default)
# bad [1, 2].each do |a| if a == 1 puts a end end # good [1, 2].each do |a| next unless a == 1 puts a end # good [1, 2].each do |a| puts a if a == 1 end
@example EnforcedStyle: always
# With `always` all conditions at the end of an iteration needs to be # replaced by next - with `skip_modifier_ifs` the modifier if like # this one are ignored: `[1, 2].each { |a| puts a if a == 1 }` # bad [1, 2].each do |a| puts a if a == 1 end # bad [1, 2].each do |a| if a == 1 puts a end end # good [1, 2].each do |a| next unless a == 1 puts a end
Constants
- EXIT_TYPES
- MSG
Public Class Methods
autocorrect_incompatible_with()
click to toggle source
# File lib/rubocop/cop/style/next.rb, line 58 def self.autocorrect_incompatible_with [Style::SafeNavigation] end
Public Instance Methods
on_block(node)
click to toggle source
# File lib/rubocop/cop/style/next.rb, line 68 def on_block(node) return unless node.send_node.call_type? && node.send_node.enumerator_method? check(node) end
Also aliased as: on_numblock
on_new_investigation()
click to toggle source
# File lib/rubocop/cop/style/next.rb, line 62 def on_new_investigation # When correcting nested offenses, we need to keep track of how much # we have adjusted the indentation of each line @reindented_lines = Hash.new(0) end
Private Instance Methods
actual_indent(lines, buffer)
click to toggle source
# File lib/rubocop/cop/style/next.rb, line 213 def actual_indent(lines, buffer) lines.map { |lineno| buffer.source_line(lineno) =~ /\S/ }.min end
allowed_modifier_if?(node)
click to toggle source
# File lib/rubocop/cop/style/next.rb, line 112 def allowed_modifier_if?(node) if node.modifier_form? style == :skip_modifier_ifs else !min_body_length?(node) end end
autocorrect_block(corrector, node)
click to toggle source
# File lib/rubocop/cop/style/next.rb, line 155 def autocorrect_block(corrector, node) next_code = "next #{node.inverse_keyword} #{node.condition.source}" corrector.insert_before(node, next_code) corrector.remove(cond_range(node, node.condition)) corrector.remove(end_range(node)) lines = reindentable_lines(node) return if lines.empty? reindent(lines, node.condition, corrector) end
autocorrect_modifier(corrector, node)
click to toggle source
# File lib/rubocop/cop/style/next.rb, line 145 def autocorrect_modifier(corrector, node) body = node.if_branch || node.else_branch replacement = "next #{node.inverse_keyword} #{node.condition.source}\n" \ "#{' ' * node.source_range.column}#{body.source}" corrector.replace(node, replacement) end
check(node)
click to toggle source
# File lib/rubocop/cop/style/next.rb, line 84 def check(node) return unless node.body && ends_with_condition?(node.body) offending_node = offense_node(node.body) add_offense(offense_location(offending_node)) do |corrector| if offending_node.modifier_form? autocorrect_modifier(corrector, offending_node) else autocorrect_block(corrector, offending_node) end end end
cond_range(node, cond)
click to toggle source
# File lib/rubocop/cop/style/next.rb, line 170 def cond_range(node, cond) end_pos = if node.loc.begin node.loc.begin.end_pos # after "then" else cond.source_range.end_pos end range_between(node.source_range.begin_pos, end_pos) end
end_followed_by_whitespace_only?(source_buffer, end_pos)
click to toggle source
# File lib/rubocop/cop/style/next.rb, line 189 def end_followed_by_whitespace_only?(source_buffer, end_pos) /\A\s*$/.match?(source_buffer.source[end_pos..]) end
end_range(node)
click to toggle source
# File lib/rubocop/cop/style/next.rb, line 180 def end_range(node) source_buffer = node.source_range.source_buffer end_pos = node.loc.end.end_pos begin_pos = node.loc.end.begin_pos - node.loc.end.column begin_pos -= 1 if end_followed_by_whitespace_only?(source_buffer, end_pos) range_between(begin_pos, end_pos) end
ends_with_condition?(body)
click to toggle source
# File lib/rubocop/cop/style/next.rb, line 98 def ends_with_condition?(body) return true if simple_if_without_break?(body) body.begin_type? && simple_if_without_break?(body.children.last) end
exit_body_type?(node)
click to toggle source
# File lib/rubocop/cop/style/next.rb, line 128 def exit_body_type?(node) return false unless node.if_branch EXIT_TYPES.include?(node.if_branch.type) end
heredoc_lines(node)
click to toggle source
# File lib/rubocop/cop/style/next.rb, line 217 def heredoc_lines(node) node.each_node(:dstr) .select(&:heredoc?) .map { |n| n.loc.heredoc_body } .flat_map { |b| (b.line...b.last_line).to_a } end
if_else_children?(node)
click to toggle source
# File lib/rubocop/cop/style/next.rb, line 120 def if_else_children?(node) node.each_child_node(:if).any?(&:else?) end
if_without_else?(node)
click to toggle source
# File lib/rubocop/cop/style/next.rb, line 124 def if_without_else?(node) node&.if_type? && !node.ternary? && !node.else? end
offense_location(offense_node)
click to toggle source
# File lib/rubocop/cop/style/next.rb, line 140 def offense_location(offense_node) offense_begin_pos = offense_node.source_range.begin offense_begin_pos.join(offense_node.condition.source_range) end
offense_node(body)
click to toggle source
# File lib/rubocop/cop/style/next.rb, line 134 def offense_node(body) *_, condition = *body condition&.if_type? ? condition : body end
reindent(lines, node, corrector)
click to toggle source
Adjust indentation of ‘lines` to match `node`
# File lib/rubocop/cop/style/next.rb, line 204 def reindent(lines, node, corrector) range = node.source_range buffer = range.source_buffer target_indent = range.source_line =~ /\S/ delta = actual_indent(lines, buffer) - target_indent lines.each { |lineno| reindent_line(corrector, lineno, delta, buffer) } end
reindent_line(corrector, lineno, delta, buffer)
click to toggle source
# File lib/rubocop/cop/style/next.rb, line 224 def reindent_line(corrector, lineno, delta, buffer) adjustment = delta + @reindented_lines[lineno] @reindented_lines[lineno] = adjustment corrector.remove_leading(buffer.line_range(lineno), adjustment) if adjustment.positive? end
reindentable_lines(node)
click to toggle source
# File lib/rubocop/cop/style/next.rb, line 193 def reindentable_lines(node) buffer = node.source_range.source_buffer # end_range starts with the final newline of the if body lines = (node.source_range.line + 1)...node.loc.end.line lines = lines.to_a - heredoc_lines(node) # Skip blank lines lines.reject { |lineno| /\A\s*\z/.match?(buffer.source_line(lineno)) } end
simple_if_without_break?(node)
click to toggle source
# File lib/rubocop/cop/style/next.rb, line 104 def simple_if_without_break?(node) return false unless if_without_else?(node) return false if if_else_children?(node) return false if allowed_modifier_if?(node) !exit_body_type?(node) end