The error message states, "TypeError (no implicit conversion of String into Integer)" and that the exception was raised in the line hand[i] == "J". The first element passed to the block by each and assigned to the block variable i is i = hand.first #=> "2". We therefore have hand["2"] == "J", or in fact, hand.[]("2"), but the method Array#[] requires its argument to be an integer, and there is "no implicit conversion of String into Integer".
Let me now address a different aspect of your question.
arr = ["2","3","4","5","6","7","8","9","10","J","Q","K","A"]
You could write the following.
arr.reduce(0) do |tot, s|
tot +
case s
when "J" then 1
when "Q" then 2
when "K" then 3
when "A" then 4
else 0
end
end
#=> 10
I can hear you. You are saying, "I said I wanted to use .each!". Well, you have! Let me explain.
arr is an instance of the class Array. Array has Module#include'd the module Enumerable, which is why we can invoke the instance method Enumerable#reduce on arr. (Array.included_modules #=> [Enumerable, Kernel]).
Like all other instance methods in Enumerable, Enumerable#reduce (aka inject) requires a receiver that is an instance of the class Enumerator, but arr is an instance of Array, not Enumerator. Ruby gets around this as follows. When reduce is invoked on arr, she sees that arr is not an instance of Enumerator so she checks to see if arr has a method each (that is, whether arr's class Array has an instance method each). It does, so she invokes each on arr to obtain
enum = arr.each
#=> #<Enumerator: ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J",
# "Q", "K", "A"]:each>
We now have the enumerator on which reduce can be invoked:
enum.reduce(0) do |tot, s|
tot +
case s
when "J" then 1
when "Q" then 2
when "K" then 3
when "A" then 4
else 0
end
end
#=> 10
You don't see Array#each being invoked, but it certainly is. We can confirm that by including Enumerable in a class that does not have a method each and see what happens.
class C
include Enumerable
end
c = C.new
#=> #<C:0x0000000002a118a8>
c.reduce {}
#=> NoMethodError (undefined method `each' for #<C:0x0000000002a118a8>)
class C
def each
end
end
c.reduce {}
#=> nil
This is why every class that includes Enumerable must have an instance method each that returns an enumerator and why each is invoked on instances of that class before an instance method from Enumerable is called.
Tis used for 10 so they're all single characters.#eachmethod call, probably a typo but worth mentioning