I'd prefer to see counting loops written as `1.upto(100) do … end`. Ruby `case` blocks are expressions. The `puts` can be factored out: 1.upto(100) do |n| i_3 = (n % 3 == 0) i_5 = (n % 5 == 0) puts case when i_3 && i_5 'fizzbuzz' when i_3 'fizz' when i_5 'buzz' else n end end Personally, I'd go further: instead of treating `i_3` and `i_5` as booleans, assign them a noise. 1.upto(100) do |n| fizz = (n % 3 == 0) ? 'Fizz' : nil buzz = (n % 5 == 0) ? 'Buzz' : nil puts case when fizz || buzz "#{fizz}#{buzz}" else n end end Or, replace `case` with a ternary expression: 1.upto(100) do |n| fizz = (n % 3 == 0) ? 'Fizz' : nil buzz = (n % 5 == 0) ? 'Buzz' : nil puts (fizz || buzz) ? "#{fizz}#{buzz}" : n end To enhance code reusability, I suggest putting the code into a function, and `yield`ing the results instead of printing them directly. def fizzbuzz(max=100) 1.upto(max) do |n| fizz = (n % 3 == 0) ? 'Fizz' : nil buzz = (n % 5 == 0) ? 'Buzz' : nil yield (fizz || buzz) ? "#{fizz}#{buzz}" : n end end fizzbuzz { |fb| puts fb } Note the Ruby whitespace conventions: two spaces of indentation (you used four), and some space on each side of binary operators (you used none).