# Case of Cyclomatic Complexity

I'm trying to recreate the method inject (Works like Reduce) from ruby Enumerable Module. Using Rubocop (A Linter) I got the error:

Cyclomatic complexity for my_inject is too high. [7/6]



The code is:

module Enumerable
def my_inject(*args)
list = to_a if Range
reduce = args[0] if args[0].is_a?(Integer)
operator = args[0].is_a?(Symbol) ? args[0] : args[1]

if operator
list.each { |item| reduce = reduce ? reduce.send(operator, item) : item }
return reduce
end
list.each { |item| reduce = reduce ? yield(reduce, item) : item }
reduce
end
end


I already did my best to reduce the Cyclomatic complexity, but still have 1 above (7/6), now I stuck, any directions will be appreciate.

The code can be run on reply: https://repl.it/@ThiagoMiranda2/INJECT

• Does my_inject() as presented work as specified? – greybeard Apr 2 at 8:28
• Yes, works almost like the original, same behavior as describe on documentation, but some edge cases are not cover, like when we have an empty block . – Sevila Apr 2 at 14:29
• Please can you add a description on what the code achieves, currently all I've learnt from reading your question is that it's got bad cyclomatic complexity. To be able to help people need to know what it is you're doing. – Peilonrayz Apr 6 at 20:49
• This method works like Reduce function of any main stream language, for example if you have an array [1,2,3] and let's say you want to reduce with sum operator, so you have = 1 + 2 +3 = 6. In this case we have the array as input [1,2,3] an the return is the number 6. – Sevila Apr 7 at 15:07

list = to_a if Range


is incorrect. Range is a constant and if Range is always true. You probably means if is_a?(Range) which would mean list was undefined in most cases.

As a first attempt at solving this I would take the case where an operator is provided and have the method call itself with a block something like below.

module Enumerable
def my_inject(*args)
unless block_given?
operator = args.delete_at(-1)
initial  = args.first
return my_inject(initial) { |accumulator, i| accumulator.send(operator, i) }
end

list = is_a?(Range) ? to_a : self

accumulator = args.first
list.each { |item| accumulator = accumulator ? yield(accumulator, item) : item
accumulator
end

end



Note: I didn't test this or check its complexity.

This code is also incorrect. There is actually a difference between an initial value that is not provided and one of nil. It is also possible for the block to to return nil which would cause the yield block not to be called for that iteration. The real solution is to check args.length not just args.first but that would increase your complexity.

To do this properly and still pass Rubocop's checks for complexity (as well as its other checks) you will need to break this method up into a few smaller methods.

• Your code doesn't have problem with complexity, and now I have new paths to try. Thanks for the advice about Range, was missing that. – Sevila Apr 2 at 18:24