views:

89

answers:

4

I have two succeeding function with the same condition and I wonder what is the best way to write this? I know the one way to do this is using if (condition) ... end, but I'm wondering if I can do it in one-line similar to bash, '[$n == $value] echo "$n" && break'.

n = 0
loop do
  puts n if n == value # puts and break is having the same condition, but
  break if n == value # can we do it in one line?
  n += 1
end
+1  A: 

One easy way is to just parenthesize the statements:

ruby-1.9.1-p378 > 0.upto(5) do |n|
ruby-1.9.1-p378 >     (puts n; break;) if n == 3
ruby-1.9.1-p378 ?>    puts ">>#{n}<<"
ruby-1.9.1-p378 ?>  end
>>0<<
>>1<<
>>2<<
3

If it's a bit much to put in parentheses, a begin-end will do the trick:

0.upto(5) do |n|
  begin
      puts "I found a matching n!"
      puts n
      puts "And if you multiply it by 10, it is #{10*n}"
      break;
  end if n == 3
  puts "((#{n}))"
end

Output:

((0))
((1))
((2))
I found a matching n!
3
And if you multiply it by 10, it is 30
Mark Rushakoff
That's amazing, thank you for your insightful answer!
+3  A: 

Because n is truthy, you can use the 'and' joiner. It reads really nicely:

n = 0
loop do
  puts n and break if n == value
  n += 1
end

--edit--

As pointed out in comments, that won't actually work because puts returns nil, which isn't truthy. My bad. You can use 'or' instead, but that doesn't read nicely. So I'd say just group the statements with parenthesis.

n = 0
loop do
  (puts n; break) if n == value
  n += 1
end

You could also change the puts method to return the value it prints, and that would work with 'and', but that's probably not the smartest idea :)

I'm guessing your actual code is different to what you've pasted, so if the first method in your chain returns something, you can use 'and'.

zaius
I tried it, and it continually loops and the break statement doesn't get executed.
Jakub Hampl
Oh, my bad. puts returns nil, hence you can't use 'and'. Have to use 'or', which doesn't read anywhere near as well.
zaius
zaius
A: 

proc { puts n; break; }.() if n == 3

banister
A: 

One of the golden rules of Ruby is that if you are writing a loop, you are probably doing it wrong. In this particular case, all that your loop is doing is to find an element in a collection. In Ruby, there already is a method for finding an element in a collection: Enumerable#find. There is no need to write your own.

So, the code gets simplified to:

puts (0...1.0/0).find {|n| n == value }

Now that we have a nice declarative formulation of the problem, it is easy to see that (assuming sane equality semantics and sane semantics of value.to_s), this is exactly the same as:

puts value

So, the whole loop was completely unnecessary to begin with.

Jörg W Mittag