2

I've run into a problem with the Cyclomatic complexity being too high for this ruby method:

def find_value(a, b, lookup_value)
  return find_x1(a, b) if lookup_value == 'x1'
  return find_x2(a, b) if lookup_value == 'x2'
  return find_x3(a, b) if lookup_value == 'x3'
  return find_x4(a, b) if lookup_value == 'x4'
  return find_x5(a, b) if lookup_value == 'x5'
  return find_x6(lookup_value) if lookup_value.include? 'test'
end

Is there any way of writing this without having to use eval?

QCFia
  • 39
  • 4

2 Answers2

4

Try this:

def find_value(a, b, lookup_value)
  return find_x6(lookup_value) if lookup_value.include? 'test'
  send(:"find_#{lookup_value}", a, b)
end

send() allows you to call a method by name using strings or symbols. The first parameter is the name of the method; following parameters are just passed on to the method being called.

eiko
  • 5,110
  • 6
  • 17
  • 35
2

There's nothing wrong with looking up method or class names if you need some flexibility:

LOOKUP_BY_A_B = {
  'x1' => :find_x1,
  'x2' => :find_x2,
  'x3' => :find_x3,
  'x4' => :find_x4,
  'x5' => :find_x5,
}.freeze

def find_value(a, b, lookup_value)
  method = LOOKUP_BY_A_B[lookup_value]
  return self.send(method, a, b) if method
  find_x6(lookup_value) if lookup_value.include? 'test'
end

You can also lookup Procs, something like

MY_PROCS = {
  1 => proc { |a:, b:| "#{a}.#{b}" },
  2 => proc { |a:, b:| "#{a}..#{b}" },
  3 => proc { |a:, b:| "#{a}...#{b}" }
}.freeze

def thing(a, b, x)
  MY_PROCS[x].call(a: a, b: b)
end
David Aldridge
  • 51,479
  • 8
  • 68
  • 96