Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write a guard clause with multiple conditions in Ruby?

After running Rubocop against this code I am getting

Use a guard clause instead of wrapping the code inside a conditional expression.

So from what I have read a "Guard Clause" will bail out of the method if the condition is not met, so we don't have to waste time going through extra conditionals, please correct me if my understanding is not correct.

My question is though how would i use a guard statement with multiple conditions

def auth_creds
  if %w(test1 qa demo ci).include? ENV['ENV']
    { key: 'key1', secret: 'secret1' }
  elsif ENV['ENV'] == 'live'
    { key: 'key2', secret: 'secret2' }
  else
    fail 'Unable to set key/secret'
  end
end

Thanks

like image 899
Richlewis Avatar asked Oct 17 '25 08:10

Richlewis


2 Answers

Your snippet is not a valid example for "guard clauses". There's nothing to guard against. It's just selecting data. It'd look better as case/when but if chain is fine too.

def auth_creds
  case ENV['ENV']
  when 'test1', 'qa', 'demo', 'ci'
    { key: 'key1', secret: 'secret1' }
  when 'live'
    { key: 'key2', secret: 'secret2' }
  else
    fail 'Unable to set key/secret'
  end
end

Guard clause (or as I call them, early returns) are used when the whole body of the method is wrapped in a conditional.

def process_project
  if project
    # do stuff
  end
end

The method won't do anything unless there's a project. So it makes for more readable code if we reduce the nesting here.

def process_project
  return unless project

  # do stuff with project
end

Again, not every if in your code can/should be transformed to this form. Only where it's appropriate.

like image 74
Sergio Tulentsev Avatar answered Oct 19 '25 23:10

Sergio Tulentsev


It all depends on your actual code, but with the given snippet, you could use a guard clause to ensure a valid ENV['ENV'] value:

VALID_ENVS = %w(test1 qa demo ci live)

def auth_creds
  fail 'invalid environment' unless VALID_ENVS.include? ENV['ENV']

  if ENV['ENV'] == 'live'
    { key: 'key2', secret: 'secret2' }
  else
    { key: 'key1', secret: 'secret1' }
  end
end

As noted by Sergio Tulentsev, storing your credentials in ENV (instead of the env's name) would probably be better:

def auth_creds
  { key: ENV.fetch('KEY'), secret: ENV.fetch('SECRET') }
end

fetch will raise a KeyError if the given key is not found in ENV.

like image 34
Stefan Avatar answered Oct 19 '25 23:10

Stefan