4

I'm looking for a statement that skips the execution of the when block, similiar to break for loops. Is this possible?

What I want to avoid is a construct like:

case n
  when 1
    if valid
      foo.bar
    end
  when 2
    if valid
      foo.foo
  end

The more desirable code block would look like:

case n
  when 1
    break unless valid
    foo.bar
  when 2
    break unless valid
    foo.foo
  end

Obviously, break does not work.

nTraum
  • 1,426
  • 11
  • 14
  • 2
    I think your design is faulty. You shouldn't even have such big `case` statements in your code. Maybe you can use a dictionary to map the value of `n` to a function to call or something. We could be of more help if you gave use a more specific example that shows your real issue. It might well be a case for codereview.SE, though – Niklas B. Nov 03 '12 at 15:03
  • I'm trying to parse a log file. The various `when` statements represent the regexs, I want to check the line against. The catch is that I may have to ignore some lines, depending on certain conditions (`valid` in the previous example). – nTraum Nov 03 '12 at 15:09
  • 1
    I don't understand what makes the version using break more desirable in your example. – sepp2k Nov 03 '12 at 15:10
  • @seep2k: Then you are obviously neither a Perl, nor a Ruby developer :) We hate nesting. – Niklas B. Nov 03 '12 at 15:11
  • @sepp2k much more nicer to read in my opinion. – nTraum Nov 03 '12 at 15:12
  • 1
    @nTraum: Why not only match only the valid ones with your regex? Also, what I said applies: You can use a list of regexes together with their validation function and action, then iterate over the list and find the first match. – Niklas B. Nov 03 '12 at 15:12

4 Answers4

7

Equivalent but more succinct:

case n
  when 1
    foo.bar if valid
  when 2
    foo.foo if valid
  end
end

of if the condition really applies to all cases, you can check it beforehand:

if valid
  case n
    when 1
      foo.bar
    when 2
      foo.foo
    end
  end
end

If neither works for you, then short answer: No, there's no break equivalent in a case statement in ruby.

Thilo
  • 17,565
  • 5
  • 68
  • 84
  • The condition does not apply on all cases unfortunately, I also have to execute more than one statement. I may have to consider grouping them together to a method I guess. – nTraum Nov 03 '12 at 15:11
  • 2
    I think you mean `foo.bar if valid`, etc. – Mark Thomas Nov 03 '12 at 16:14
2

I'm always a fan of adding conditionals to the end of ruby statements. It makes for easier and more readable code. Which is what ruby is known for. My answer to your question would look something like this:

case n
when 1
    foo.bar
when 2
    bar.foo
end unless !valid
jebentier
  • 151
  • 6
  • 3
    +1 but to me it would make more sense to say `case n ... end if valid` instead of `unless !valid`. – maerics Nov 03 '12 at 23:19
0

What I did in one case, which might be applicable to your case is encapsulating in a loop;

loop do
  case variable
  when conditionalA
    block1
    next if anotherconditional
    blockX
  when conditionalB
    block2
    next if anotherconditional
    blockY
  end
end

Though not sure if this is "fine art".

Sascha
  • 149
  • 1
  • 10
  • Your loop can have a condition `while condition` and you can set that condition to `false` to stop the loop. You can also use `break` to stop the entire loop as if `while condition` hit `false`. – Sascha Dec 01 '19 at 13:20
0

You can accomplish this functionality using closures. Closures are possible in ruby using the lambda syntax (-> can be replaced with the lambda keyword). This is because lambdas act as their own standalone function and return will exit the lambda/function without exiting the parent block/scope:

def valid(q)
  q == 2
end

def test_break(myvar)
  -> (n) {
    case n
      when 1
        return unless valid(n)
        puts 'I am not valid'
      when 2
        return unless valid(n)
        puts 'I am valid'
      end
  }.(myvar)

  puts 'I am run every time'
end

test_break(1)
test_break(2)

# Output:
# I am run every time
# I am valid
# I am run every time

Lambda syntax:

def valid(q)
  q == 2
end

def test_break(myvar)
  lambda do |n|
    case n
        when 1
          return unless valid(n)
          puts 'I am not valid'
        when 2
          return unless valid(n)
          puts 'I am valid'
        end
  end.call(myvar)

  puts 'I am run every time'
end

test_break(1)
test_break(2)

# Output:
# I am run every time
# I am valid
# I am run every time

More info on closures here:

What is the difference between a 'closure' and a 'lambda'?