# Extensible FizzBuzz in Ruby

The title says it all. This is yet another FizzBuzz implementation where you can specify the words you want to use, though it autoselects the divisors as the first n primes other than 2, rather than having you enter them.

I'm looking for tips on variable/function naming and that kind of thing; I couldn't think of good ones when I wrote this. I'd also like any performance improvements that can be put in.

def n_primes(count)
primes = []
number = 2
until primes.length == count
primes << number if primes.inject(true) { |memo, cur| memo and number % cur != 0 }
number += 1
end
primes
end

puts 'Enter the words you would like to use'
word_array = gets.chomp.split
puts 'Enter the number to count up to'
up_to = gets.chomp.to_i

words = {}
primes = n_primes(word_array.length + 1)[1..-1]
primes.each_with_index { |prime, index| words[prime] = word_array[index] }

1.upto(up_to) do |number|
to_print = words.reject { |n, _| number % n != 0 }.values
to_print = [number] if to_print.length == 0
puts to_print.join ''
end


Note: I extracted n_primes into a function because it means I don't have to use meaningless names like p or num to avoid naming conflicts. If there's a better solution, I'd like to know it.

Sample output:

Enter the words you would like to use
> Fizz Buzz Wolf Foo Bar
Enter the number to count up to
> 100
1
2
Fizz
4
Buzz
Fizz
Wolf
8
Fizz
Buzz
Foo
Fizz
Bar
Wolf
FizzBuzz
16
17
Fizz
19
Buzz
FizzWolf
Foo
23
Fizz
Buzz
Bar
Fizz
Wolf
29
FizzBuzz
31
32
FizzFoo
34
BuzzWolf
Fizz
37
38
FizzBar
Buzz
41
FizzWolf
43
Foo
FizzBuzz
46
47
Fizz
Wolf
Buzz
Fizz
Bar
53
Fizz
BuzzFoo
Wolf
Fizz
58
59
FizzBuzz
61
62
FizzWolf
64
BuzzBar
FizzFoo
67
68
Fizz
BuzzWolf
71
Fizz
73
74
FizzBuzz
76
WolfFoo
FizzBar
79
Buzz
Fizz
82
83
FizzWolf
Buzz
86
Fizz
Foo
89
FizzBuzz
WolfBar
92
Fizz
94
Buzz
Fizz
97
Wolf
FizzFoo
Buzz


(The user input is prefixed with >, though it doesn't show up when you actually run the code)

• #n_primes

Ruby has the Prime class as part of its stdlib, so you don't need to roll your own prime number generator.

• n_primes(word_array.length + 1)[1..-1]

A more Rubyesque version might use drop(1) instead of the [1..-1] slice.

• words = {} + primes.each_with_index

Instead of creating an empty Hash and then adding elements to it, you can use Array#zip to create an array of word/number pairs. You can turn that into a hash with Hash[], if you'd like.

• words.reject

Purely from a semantic standpoint, I think select would be more natural to use. I think of it as "finding the words to print" rather than "discarding the words that shouldn't be printed" which sounds like a double negative.

You could also consider using #inject or #each_with_object to collect matches instead of #reject + #values

• to_print.length == 0

Use Array#empty? instead.

• to_print.join ''

You don't need the argument for Array#join.

I'd do this:

require "prime"

puts "Enter the words you would like to use (separated by spaces)"
words = gets.strip.split

puts "Enter the number to count up to"
count = gets.strip.to_i

pairs = Prime.first(words.count + 1).drop(1).zip(words)

1.upto(count) do |n|
line = pairs.each_with_object([]) do |(prime, word), memo|
memo << word if (n % prime).zero?
end
puts line.empty? ? n : line.join
end


Or, more in line with yours, the last part could be:

1.upto(count) do |n|
line = pairs.select { |prime, _| (n % prime).zero? }.map(&:last)
puts line.empty? ? n : line.join
end

• I updated the doc link in your answer from 1.9.3 (IIRC) to 2.2.2, if you wanna accept the suggestion ;)
– Nic
Jun 6, 2015 at 20:14
• @QPaysTaxes Approved - I actually wanted to link to a newer one, but there was something weird going on with ruby-docs, and some of the 2.x doc pages kept saying "You've entered the forbidden area!"... with little in the way of explanation :) Jun 6, 2015 at 20:17
• @QPaysTaxes I just meant "a newer version than the 1.9 one I ended up posting" - not that the Prime class has changed very much in terms of API over the years, so it's not a huge deal either way. And oddly, the answer appears as accepted here, and I got some rep too (thanks!) Jun 6, 2015 at 20:20
• Oh, that makes sense. The API doc bit, at least. Still showing as not accepted here, and I've refreshed at least twice... Eh, I don't mind, so long as you get the rep
– Nic
Jun 6, 2015 at 20:21
• It's showing now... Odd. Still, unplugging the internet seems fun. BRB!
– Nic
Jun 6, 2015 at 20:25