How does "Assignment Branch Condition size for index is too high" work?

pangpang picture pangpang · Jan 9, 2016 · Viewed 8.5k times · Source

Rubocop is always report the error:

app/controllers/account_controller.rb:5:3: C: Assignment Branch Condition size for index is too high. [30.95/24]

if params[:role]
  @users = @search.result.where(:role => params[:role])
elsif params[:q] && params[:q][:s].include?('count')
  @users = @search.result.order(params[:q][:s])
else
  @users = @search.result
end

How to fix it? Anyone has good idea?

Answer

New Alexandria picture New Alexandria · Jan 9, 2016

The ABC size [1][2] is

computed by counting the number of assignments, branches and conditions for a section of code. The counting rules in the original C++ Report article were specifically for the C, C++ and Java languages.

The previous links details what counts for A, B, and C. ABC size is a scalar magnitude, reminiscent of a triangulated relationship:

|ABC| = sqrt((A*A)+(B*B)+(C*C))

Actually, a quick google on the error shows that the first indexed page is the Rubocop docs for the method that renders that message.

Your repo or analysis tool will define a threshold amount when the warning is triggered.

Calculating, if you like self-inflicting....

Your code calcs as

(1+1+1)^2  + 
(1+1+1+1+1+1+1+1+1+1+1+1+1)^2   + 
(1+1+1+1)^2 
=> 194 

That's a 'blind' calculation with values I've made up (1s). However, you can see that the error states numbers that probably now make sense as your ABC and the threshold:

 [30.95/24]

So cop threshold is 24 and your ABC size is 30.95. This tells us that the rubocop engine assign different numbers for A, B, and C. As well, different kinds or Assignments (or B or C) could have different values, too. E.G. a 'normal' assignment x = y is perhaps scored lower than a chained assignment x = y = z = r.

tl;dr answer

At this point, you probably have a fairly clear idea of how to reduce your ABC size. If not:

  1. a simple way it to take the conditional used for your elsif and place it in a helper method.
  2. since you are assigning an @ variable, and largely calling from one as well, your code uses no encapsulation of memory. Thus, you can move both if and elsif block actions into each their own load_search_users_by_role and load_search_users_by_order methods.