class RuboCop::Cop::Style::ConditionalAssignment
Check for `if` and `case` statements where each branch is used for assignment to the same variable when using the return of the condition can be used instead.
@example
EnforcedStyle: assign_to_condition # bad if foo bar = 1 else bar = 2 end case foo when 'a' bar += 1 else bar += 2 end if foo some_method bar = 1 else some_other_method bar = 2 end # good bar = if foo 1 else 2 end bar += case foo when 'a' 1 else 2 end bar << if foo some_method 1 else some_other_method 2 end EnforcedStyle: assign_inside_condition # bad bar = if foo 1 else 2 end bar += case foo when 'a' 1 else 2 end bar << if foo some_method 1 else some_other_method 2 end # good if foo bar = 1 else bar = 2 end case foo when 'a' bar += 1 else bar += 2 end if foo some_method bar = 1 else some_other_method bar = 2 end
Constants
- ASSIGNMENT_TYPES
- ASSIGN_TO_CONDITION_MSG
- CONDITION_TYPES
- ENABLED
- IF
- INDENTATION_WIDTH
- LINE_LENGTH
- MAX
- METHODS
- MSG
- SINGLE_LINE_CONDITIONS_ONLY
- UNLESS
- VARIABLE_ASSIGNMENT_TYPES
- WIDTH
Public Instance Methods
autocorrect(node)
click to toggle source
# File lib/rubocop/cop/style/conditional_assignment.rb, line 266 def autocorrect(node) if assignment_type?(node) move_assignment_inside_condition(node) else move_assignment_outside_condition(node) end end
check_assignment_to_condition(node)
click to toggle source
# File lib/rubocop/cop/style/conditional_assignment.rb, line 224 def check_assignment_to_condition(node) return unless style == :assign_inside_condition ignore_node(node) *_variable, assignment = *node if assignment.respond_to?(:type) if assignment.begin_type? && assignment.children.size == 1 assignment, = *assignment end return unless CONDITION_TYPES.include?(assignment.type) end _condition, *branches, else_branch = *assignment return unless else_branch # empty else return if single_line_conditions_only? && [*branches, else_branch].any?(&:begin_type?) add_offense(node, :expression, ASSIGN_TO_CONDITION_MSG) end
on_case(node)
click to toggle source
# File lib/rubocop/cop/style/conditional_assignment.rb, line 255 def on_case(node) return unless style == :assign_to_condition _condition, *when_branches, else_branch = *node return unless else_branch # empty else when_branches = expand_when_branches(when_branches) branches = [*when_branches, else_branch] check_node(node, branches) end
on_if(node)
click to toggle source
# File lib/rubocop/cop/style/conditional_assignment.rb, line 242 def on_if(node) return unless style == :assign_to_condition return if elsif?(node) _condition, if_branch, else_branch = *node elsif_branches, else_branch = expand_elses(else_branch) return unless else_branch # empty else branches = [if_branch, *elsif_branches, else_branch] check_node(node, branches) end
on_send(node)
click to toggle source
# File lib/rubocop/cop/style/conditional_assignment.rb, line 219 def on_send(node) return unless assignment_type?(node) check_assignment_to_condition(node) end
Private Instance Methods
assignment_type?(branch)
click to toggle source
The shovel operator `<<` does not have its own type. It is a `send` type.
# File lib/rubocop/cop/style/conditional_assignment.rb, line 312 def assignment_type?(branch) return true if ASSIGNMENT_TYPES.include?(branch.type) if branch.send_type? _receiver, method, = *branch return true if METHODS.include?(method) return true if method.to_s.end_with?(EQUAL) end false end
assignment_types_match?(*nodes)
click to toggle source
# File lib/rubocop/cop/style/conditional_assignment.rb, line 304 def assignment_types_match?(*nodes) return unless assignment_type?(nodes.first) first_type = nodes.first.type nodes.all? { |node| node.type == first_type } end
check_node(node, branches)
click to toggle source
# File lib/rubocop/cop/style/conditional_assignment.rb, line 324 def check_node(node, branches) return unless branches.all? last_statements = branches.map { |branch| tail(branch) } return unless lhs_all_match?(last_statements) return if last_statements.any?(&:masgn_type?) return unless assignment_types_match?(*last_statements) return if single_line_conditions_only? && branches.any?(&:begin_type?) return if correction_exceeds_line_limit?(node, branches) add_offense(node, :expression) end
correction_exceeds_line_limit?(node, branches)
click to toggle source
If `Metrics/LineLength` is enabled, we do not want to introduce an offense by auto-correcting this cop. Find the max configured line length. Find the longest line of condition. Remove the assignment from lines that contain the offending assignment because after correcting, this will not be on the line anymore. Check if the length of the longest line + the length of the corrected assignment is greater than the max configured line length
# File lib/rubocop/cop/style/conditional_assignment.rb, line 344 def correction_exceeds_line_limit?(node, branches) return false unless config.for_cop(LINE_LENGTH)[ENABLED] assignment = lhs(tail(branches[0])) max_line_length = config.for_cop(LINE_LENGTH)[MAX] indentation_width = config.for_cop(INDENTATION_WIDTH)[WIDTH] || 2 return true if longest_rhs(branches) + indentation_width + assignment.length > max_line_length longest_line(node, assignment).length > max_line_length end
lhs_all_match?(branches)
click to toggle source
# File lib/rubocop/cop/style/conditional_assignment.rb, line 299 def lhs_all_match?(branches) first_lhs = lhs(branches.first) branches.all? { |branch| lhs(branch) == first_lhs } end
lines_with_numbers(node)
click to toggle source
# File lib/rubocop/cop/style/conditional_assignment.rb, line 368 def lines_with_numbers(node) line_nos = node.loc.line..node.loc.last_line node.source.lines.zip(line_nos) end
longest_line(node, assignment)
click to toggle source
# File lib/rubocop/cop/style/conditional_assignment.rb, line 355 def longest_line(node, assignment) assignment_regex = /#{Regexp.escape(assignment).gsub(' ', '\s*')}/ lines = node.source.lines.map do |line| line.chomp.sub(assignment_regex, '') end longest_line = lines.max_by(&:length) longest_line + assignment end
longest_rhs(branches)
click to toggle source
# File lib/rubocop/cop/style/conditional_assignment.rb, line 364 def longest_rhs(branches) branches.map { |branch| branch.children.last.source.length }.max end
move_assignment_inside_condition(node)
click to toggle source
# File lib/rubocop/cop/style/conditional_assignment.rb, line 288 def move_assignment_inside_condition(node) *_assignment, condition = *node if ternary?(condition) || ternary?(condition.children[0]) 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
move_assignment_outside_condition(node)
click to toggle source
# File lib/rubocop/cop/style/conditional_assignment.rb, line 276 def move_assignment_outside_condition(node) if ternary?(node) TernaryCorrector.correct(node) elsif node.loc.keyword.is?(IF) IfCorrector.correct(self, node) elsif node.loc.keyword.is?(UNLESS) UnlessCorrector.correct(self, node) else CaseCorrector.correct(self, node) end end
single_line_conditions_only?()
click to toggle source
# File lib/rubocop/cop/style/conditional_assignment.rb, line 373 def single_line_conditions_only? cop_config[SINGLE_LINE_CONDITIONS_ONLY] end