class RuboCop::Cop::Style::ConditionalAssignment
end
bar = 2
some_other_method
else
bar = 1
some_method
if foo
end
bar += 2
else
bar += 1
when ‘a’
case foo
end
bar = 2
else
bar = 1
if foo
# good
end
2
some_other_method
else
1
some_method
bar << if foo
end
2
else
1
when ‘a’
bar += case foo
end
2
else
1
bar = if foo
# bad
@example EnforcedStyle: assign_inside_condition
end
2
some_other_method
else
1
some_method
bar << if foo
end
2
else
1
when ‘a’
bar += case foo
end
2
else
1
bar = if foo
# good
end
bar = 2
some_other_method
else
bar = 1
some_method
if foo
end
bar += 2
else
bar += 1
when ‘a’
case foo
end
bar = 2
else
bar = 1
if foo
# bad
@example EnforcedStyle: assign_to_condition (default)
condition can be used instead.
assignment to the same variable when using the return of the
Check for ‘if` and `case` statements where each branch is used for
def allowed_single_line?(branches)
def allowed_single_line?(branches) single_line_conditions_only? && branches.any?(&:begin_type?) end
def allowed_statements?(branches)
def allowed_statements?(branches) return false unless branches.all? statements = branches.map { |branch| tail(branch) }.compact lhs_all_match?(statements) && statements.none?(&:masgn_type?) && assignment_types_match?(*statements) end
def allowed_ternary?(assignment)
def allowed_ternary?(assignment) assignment.if_type? && assignment.ternary? && !include_ternary? end
def assignment_node(node)
def assignment_node(node) *_variable, assignment = *node # ignore pseudo-assignments without rhs in for nodes return if node.parent&.for_type? if assignment.begin_type? && assignment.children.one? assignment, = *assignment end assignment end
def assignment_types_match?(*nodes)
def assignment_types_match?(*nodes) return unless assignment_type?(nodes.first) nodes.map(&:type).uniq.one? end
def autocorrect(node)
def autocorrect(node) if assignment_type?(node) move_assignment_inside_condition(node) else move_assignment_outside_condition(node) end end
def candidate_node?(node)
def candidate_node?(node) style == :assign_inside_condition && assignment_rhs_exist?(node) end
def check_assignment_to_condition(node)
def check_assignment_to_condition(node) return unless candidate_node?(node) ignore_node(node) assignment = assignment_node(node) return unless candidate_condition?(assignment) _condition, *branches, else_branch = *assignment return unless else_branch return if allowed_single_line?([*branches, else_branch]) add_offense(node, message: ASSIGN_TO_CONDITION_MSG) end
def check_node(node, branches)
def check_node(node, branches) return if allowed_ternary?(node) return unless allowed_statements?(branches) return if allowed_single_line?(branches) return if correction_exceeds_line_limit?(node, branches) add_offense(node) end
def correction_exceeds_line_limit?(node, branches)
of the longest line + the length of the corrected assignment is
correcting, this will not be on the line anymore. Check if the length
from lines that contain the offending assignment because after
length. Find the longest line of condition. Remove the assignment
offense by auto-correcting this cop. Find the max configured line
If `Metrics/LineLength` is enabled, we do not want to introduce an
def correction_exceeds_line_limit?(node, branches) return false unless line_length_cop_enabled? assignment = lhs(tail(branches[0])) longest_line_exceeds_line_limit?(node, assignment) end
def include_ternary?
def include_ternary? cop_config['IncludeTernaryExpressions'] end
def indentation_width
def indentation_width config.for_cop(INDENTATION_WIDTH)[WIDTH] || 2 end
def lhs_all_match?(branches)
def lhs_all_match?(branches) return true if branches.empty? first_lhs = lhs(branches.first) branches.all? { |branch| lhs(branch) == first_lhs } end
def line_length_cop_enabled?
def line_length_cop_enabled? config.for_cop(LINE_LENGTH)[ENABLED] end
def longest_line(node, assignment)
def longest_line(node, assignment) assignment_regex = /\s*#{Regexp.escape(assignment).gsub('\ ', '\s*')}/ lines = node.source.lines.map do |line| line.chomp.sub(assignment_regex, '') end longest_line = lines.max_by(&:length) assignment + longest_line end
def longest_line_exceeds_line_limit?(node, assignment)
def longest_line_exceeds_line_limit?(node, assignment) longest_line(node, assignment).length > max_line_length end
def max_line_length
def max_line_length config.for_cop(LINE_LENGTH)[MAX] end
def move_assignment_inside_condition(node)
def move_assignment_inside_condition(node) *_assignment, condition = *node if ternary_condition?(condition) TernaryCorrector.move_assignment_inside_condition(node) elsif condition.case_type? CaseCorrector.move_assignment_inside_condition(node) elsif condition.if_type? IfCorrector.move_assignment_inside_condition(node) end end
def move_assignment_outside_condition(node)
def move_assignment_outside_condition(node) if node.case_type? CaseCorrector.correct(self, node) elsif node.ternary? TernaryCorrector.correct(node) elsif node.if? || node.unless? IfCorrector.correct(self, node) end end
def on_case(node)
def on_case(node) return unless style == :assign_to_condition return unless node.else_branch when_branches = expand_when_branches(node.when_branches) branches = [*when_branches, node.else_branch] check_node(node, branches) end
def on_if(node)
def on_if(node) return unless style == :assign_to_condition return if node.elsif? else_branch = node.else_branch elsif_branches, else_branch = expand_elses(else_branch) return unless else_branch branches = [node.if_branch, *elsif_branches, else_branch] check_node(node, branches) end
def on_send(node)
def on_send(node) return unless assignment_type?(node) check_assignment_to_condition(node) end
def single_line_conditions_only?
def single_line_conditions_only? cop_config[SINGLE_LINE_CONDITIONS_ONLY] end
def ternary_condition?(node)
def ternary_condition?(node) [node, node.children.first].any? { |n| n.if_type? && n.ternary? } end