Question

Is there a way to make this function into one statement?

def test
  err = _invalid_permission
  return err if err # this statement
  # do something else
end

I tried:

def test
  return (err = _invalid_permission) if err
  # do something else
end

but this is different, err after if is always nil

Or this one:

def test
  return err if (err = _invalid_permission)
  # do something else
end

but this one causes undefined local variable or method 'err'.

explanation for what i trying to do is to shorten these kind of method:

def test
  err = _invalid_permission
  return err if err
  err = _check_another_error
  return err if err
  err = _and_another_one
  return err if err
  # and lots more
  # do something else when not error
  return nil
end

the _invalid_permission, _check_another_error, and _and_another_one would return non-empty string or array or hash containing the error message.

another story, after seeing answers below, i think it could combined into:

def test
  err = _invalid_permission ||
    _check_another_error ||
    _and_another_one
  # and lots more
  return err if err
  # do something else when not error
  return nil
end
Was it helpful?

Solution

def test
  (err = _invalid_permission) && return err

  #do something else
end

OTHER TIPS

Are you sure you've asked the right question? You've focused on one way to reduce the lines of code you have to write. Instead, you need to DRY out your code. Here's one way:

module Checks
  def _invalid_permission() nil end
  def _check_another_error() "oops!" end
  def _and_another_one() nil end
end

class Doit
  @@checks = Checks.instance_methods(false)
  include Checks

  def doit
    @@checks.each { |m| rv = send(m); return rv if rv }

    "test"
  end
end

p Doit.new.doit # => "oops!"

If you change

def _check_another_error() "oops!" end

to

def _check_another_error() nil end

then

p Doit.new.doit # => "test"

This approach also allows you to add, remove or rename a check method without having to remember to change references to it elsewhere.

This works, but you would sacrifice clarity

def test
  (err = _invalid_permission) ? (return err) : nil
  #do something
end
def test
  (err = _invalid_permission) or begin
   # do something else
  end
end

This doesn't go into combining statements, but if what you're trying to do is check a bunch of error conditions like you show, it can be done more readably with something like this:

def test
  err ||= _invalid_permission
  err ||= _check_another_error
  err ||= _and_another_one
  return err if err
  #do a bunch of other stuff
end

Or, if you do this in a lot of places, it sounds like an exception might make sense. Something like:

class MyValidationError < Exception
  attr_accessor :err
  def initialize(err)
    @err = err
  end
end

def check(err_or_nil)
  raise MyValidationError.new(err) if err_or_nil
end

def test
  check _invalid_permission
  check _check_another_error
  check _and_another_one
  #do a bunch of other stuff
rescue MyValidationError
  $!.err
end

But I think the first is quite readable, personally.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top