class RubbyCop::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
- ENABLED
- INDENTATION_WIDTH
- LINE_LENGTH
- MAX
- MSG
- SINGLE_LINE_CONDITIONS_ONLY
- VARIABLE_ASSIGNMENT_TYPES
- WIDTH
Public Instance Methods
on_case(node)
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 257 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
on_if(node)
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 243 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
on_send(node)
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 237 def on_send(node) return unless assignment_type?(node) check_assignment_to_condition(node) end
Private Instance Methods
allowed_single_line?(branches)
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 289 def allowed_single_line?(branches) single_line_conditions_only? && branches.any?(&:begin_type?) end
allowed_statements?(branches)
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 359 def allowed_statements?(branches) return false unless branches.all? statements = branches.map { |branch| tail(branch) } lhs_all_match?(statements) && statements.none?(&:masgn_type?) && assignment_types_match?(*statements) end
allowed_ternary?(assignment)
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 285 def allowed_ternary?(assignment) assignment.if_type? && assignment.ternary? && !include_ternary? end
assignment_node(node)
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 301 def assignment_node(node) *_variable, assignment = *node if assignment.begin_type? && assignment.children.one? assignment, = *assignment end assignment end
assignment_types_match?(*nodes)
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 344 def assignment_types_match?(*nodes) return unless assignment_type?(nodes.first) nodes.map(&:type).uniq.one? end
autocorrect(node)
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 293 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/rubbycop/cop/style/conditional_assignment.rb, line 269 def check_assignment_to_condition(node) return unless style == :assign_inside_condition return unless assignment_rhs_exist?(node) ignore_node(node) assignment = assignment_node(node) return unless condition?(assignment) return if allowed_ternary?(assignment) _condition, *branches, else_branch = *assignment return unless else_branch # empty else return if allowed_single_line?([*branches, else_branch]) add_offense(node, :expression, ASSIGN_TO_CONDITION_MSG) end
check_node(node, branches)
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 350 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, :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/rubbycop/cop/style/conditional_assignment.rb, line 375 def correction_exceeds_line_limit?(node, branches) return false unless line_length_cop_enabled? assignment = lhs(tail(branches[0])) longest_rhs_exceeds_line_limit?(branches, assignment) || longest_line_exceeds_line_limit?(node, assignment) end
include_ternary?()
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 428 def include_ternary? cop_config['IncludeTernaryExpressions'] end
indentation_width()
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 420 def indentation_width config.for_cop(INDENTATION_WIDTH)[WIDTH] || 2 end
lhs_all_match?(branches)
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 339 def lhs_all_match?(branches) first_lhs = lhs(branches.first) branches.all? { |branch| lhs(branch) == first_lhs } end
line_length_cop_enabled?()
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 412 def line_length_cop_enabled? config.for_cop(LINE_LENGTH)[ENABLED] end
longest_line(node, assignment)
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 396 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_line_exceeds_line_limit?(node, assignment)
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 388 def longest_line_exceeds_line_limit?(node, assignment) longest_line(node, assignment).length > max_line_length end
longest_rhs(branches)
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 405 def longest_rhs(branches) line_lengths = branches.flat_map do |branch| branch.children.last.source.split("\n").map(&:length) end line_lengths.max end
longest_rhs_exceeds_line_limit?(branches, assignment)
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 384 def longest_rhs_exceeds_line_limit?(branches, assignment) longest_rhs_full_length(branches, assignment) > max_line_length end
longest_rhs_full_length(branches, assignment)
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 392 def longest_rhs_full_length(branches, assignment) longest_rhs(branches) + indentation_width + assignment.length end
max_line_length()
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 416 def max_line_length config.for_cop(LINE_LENGTH)[MAX] end
move_assignment_inside_condition(node)
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 323 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
move_assignment_outside_condition(node)
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 311 def move_assignment_outside_condition(node) if node.case_type? CaseCorrector.correct(self, node) elsif node.ternary? TernaryCorrector.correct(node) elsif node.if? IfCorrector.correct(self, node) elsif node.unless? UnlessCorrector.correct(self, node) end end
single_line_conditions_only?()
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 424 def single_line_conditions_only? cop_config[SINGLE_LINE_CONDITIONS_ONLY] end
ternary_condition?(node)
click to toggle source
# File lib/rubbycop/cop/style/conditional_assignment.rb, line 335 def ternary_condition?(node) [node, node.children.first].any? { |n| n.if_type? && n.ternary? } end