I would do it like this:
enum = [:upcase, :downcase].cycle
#<Enumerator: [:upcase, :downcase]:cycle>
5.times.with_object([]) do |_,words|
puts "Please enter a word:"
words << gets.chomp.send(enum.next)
end
If "dog\n"
, "cat\n"
, "pig\n"
, "cow\n"
and "owl\n"
were entered, this would return:
["DOG", "cat", "PIG", "cow", "OWL"]
As you are new to Ruby, I would be surprised if you understand what I've done on first reading. If you break it down, however, it's not so bad. If you work on this until you understand it, I guarantee you will make a big jump in your understanding of the language.
If you examine the docs for Array#cycle (which returns an instance of the class Enumerator
) and Enumerator#next you will find:
enum.next #=> :upcase
enum.next #=> :downcase
enum.next #=> :upcase
enum.next #=> :downcase
...
The dispatching of methods to receivers is the job of Object#send.Whenever you invoke a method (say [1,2] << 3
) Ruby sends the method (name) and its arguments to the receiver ([1,2].send(:<<, 3
).
So you see, the method name :upcase
is sent to all
even-numbered words and:downcase
is sent to all odd-numbered words.
The method Enumerator#with_object is a more Ruby-like way of producing the result:
words = []
5.times do
puts "Please enter a word:"
words << gets.chomp.send(enum.next)
end
words
Notice that with_object
saves two steps, but it also has the advantage of restricting the scope of the array words
to the block.
A related method, Enumerable#each_with_object could be used in place of each_object
's (because the class Enumerator
include
's the Enumerable
module) and must be used when the receiver is not an enumerator (when the receiver is an array or hash, for example).
Lastly, you could write the block variables as |i,words|
, where i
is the index (produced by Integer#times) that ranges from 0
to 4
. It is common practice to replace a block variable that is not used in the block with an underscore, in part to so-inform the reader. Note that _
is a perfectly legitimate local variable.