I don't use Ruby on a regular basis, but I felt inspired to write an extensible, object-oriented version of FizzBuzz to sharpen my skills. I welcome all feedback.
The main class:
class FizzBuzzer
def initialize(*tests)
@tests = tests
end
def run(values)
result = []
values.each do |value|
str = ''
@tests.each do |test|
str << test.word if test.satisfied_by? value
end
str = value.to_s if str.empty?
result << "#{str}\n"
end
result.join
end
end
Sample test operation classes:
class ModuloTester
attr_accessor :word
def initialize(modulo, word)
@modulo = modulo.to_i
@word = word
end
def satisfied_by?(number)
(number % @modulo).zero?
end
end
class SquareRootTester
attr_accessor :word
def initialize(word)
@word = word
end
def satisfied_by?(number)
(Math.sqrt(number) % 1).zero?
end
end
In use:
fizz_buzzer = FizzBuzzer.new ModuloTester.new(3, 'Fizz'), ModuloTester.new(5, 'Buzz')
puts fizz_buzzer.run 1..100
puts
fizz_buzzer = FizzBuzzer.new SquareRootTester.new('(PerfectSquare)')
puts fizz_buzzer.run 1..10
puts fizz_buzzer.run 20..30
puts fizz_buzzer.run 45..55
Which produces the expected output. Is this idiomatic Ruby? Is the naming scheme acceptable? What can be improved?
Enumerable
methods likeselect
andmap
for therun
method. \$\endgroup\$Enumerable
in 200_success' answer). Duck-typing is basically what you'd use an interface or protocol for in other OOP languages, and inheritance is regular inheritance (e.g.Car
inheriting fromVehicle
). In your code, there isn't much to inherit though, so duck-typing is a good solution. Just think of duck-typing as you implementing an interface, and inheritance as regular inheritance. \$\endgroup\$