class RubbyCop::Cop::Performance::CaseWhenSplat
Place `when` conditions that use splat at the end of the list of `when` branches.
Ruby has to allocate memory for the splat expansion every time that the `case` `when` statement is run. Since Ruby does not support fall through inside of `case` `when`, like some other languages do, the order of the `when` branches does not matter. By placing any splat expansions at the end of the list of `when` branches we will reduce the number of times that memory has to be allocated for the expansion.
This is not a guaranteed performance improvement. If the data being processed by the `case` condition is normalized in a manner that favors hitting a condition in the splat expansion, it is possible that moving the splat condition to the end will use more memory, and run slightly slower.
@example
# bad case foo when *condition bar when baz foobar end case foo when *[1, 2, 3, 4] bar when 5 baz end # good case foo when baz foobar when *condition bar end case foo when 1, 2, 3, 4 bar when 5 baz end
Constants
- ARRAY_MSG
- MSG
- PERCENT_CAPITAL_I
- PERCENT_CAPITAL_W
- PERCENT_I
- PERCENT_W
Public Instance Methods
# File lib/rubbycop/cop/performance/case_when_splat.rb, line 64 def on_case(case_node) when_conditions = case_node.when_branches.flat_map(&:conditions) splat_offenses(when_conditions).reverse_each do |condition| range = condition.parent.loc.keyword.join(condition.source_range) variable, = *condition message = variable.array_type? ? ARRAY_MSG : MSG add_offense(condition.parent, range, message) end end
Private Instance Methods
# File lib/rubbycop/cop/performance/case_when_splat.rb, line 77 def autocorrect(when_node) lambda do |corrector| if needs_reorder?(when_node) reorder_condition(corrector, when_node) else inline_fix_branch(corrector, when_node) end end end
# File lib/rubbycop/cop/performance/case_when_splat.rb, line 138 def indent_for(node) ' ' * node.loc.column end
# File lib/rubbycop/cop/performance/case_when_splat.rb, line 92 def inline_fix_branch(corrector, when_node) conditions = when_node.conditions range = range_between(conditions[0].loc.expression.begin_pos, conditions[-1].loc.expression.end_pos) corrector.replace(range, replacement(conditions)) end
# File lib/rubbycop/cop/performance/case_when_splat.rb, line 163 def needs_reorder?(when_node) following_branches = when_node.parent.when_branches[(when_node.branch_index + 1)..-1] following_branches.any? do |when_branch| when_branch.conditions.any? do |condition| non_splat?(condition) end end end
# File lib/rubbycop/cop/performance/case_when_splat.rb, line 133 def new_branch_without_then(node, new_condition) "\n#{indent_for(node)}when #{new_condition}" \ "\n#{indent_for(node.body)}#{node.body.source}" end
# File lib/rubbycop/cop/performance/case_when_splat.rb, line 128 def new_condition_with_then(node, new_condition) "\n#{indent_for(node)}when " \ "#{new_condition} then #{node.body.source}" end
# File lib/rubbycop/cop/performance/case_when_splat.rb, line 156 def non_splat?(condition) variable, = *condition (condition.splat_type? && variable.array_type?) || !condition.splat_type? end
# File lib/rubbycop/cop/performance/case_when_splat.rb, line 100 def reorder_condition(corrector, when_node) when_branches = when_node.parent.when_branches return if when_branches.one? corrector.remove(when_branch_range(when_node)) corrector.insert_after(when_branches.last.source_range, reordering_correction(when_node)) end
# File lib/rubbycop/cop/performance/case_when_splat.rb, line 110 def reordering_correction(when_node) new_condition = replacement(when_node.conditions) if same_line?(when_node, when_node.body) new_condition_with_then(when_node, new_condition) else new_branch_without_then(when_node, new_condition) end end
# File lib/rubbycop/cop/performance/case_when_splat.rb, line 87 def replacement(conditions) reordered = conditions.partition(&:splat_type?).reverse reordered.flatten.map(&:source).join(', ') end
# File lib/rubbycop/cop/performance/case_when_splat.rb, line 142 def splat_offenses(when_conditions) found_non_splat = false offenses = when_conditions.reverse.map do |condition| found_non_splat ||= non_splat?(condition) next if non_splat?(condition) condition if found_non_splat end offenses.compact end
# File lib/rubbycop/cop/performance/case_when_splat.rb, line 120 def when_branch_range(when_node) next_branch = when_node.parent.when_branches[when_node.branch_index + 1] range_between(when_node.source_range.begin_pos, next_branch.source_range.begin_pos) end