When specifying a range say (‘A’..’Z’) you get the expected results
A
B
C
...
Z
When you specify the second charcter as lower you get the range of all lower and uppercase letters. Abbreviated …
[9] pry(main)> ('A'..'z').each {|letter| puts letter}
A
B
C
...
Z
[
\
]
^
_
`
a
b
...
z
When I specify a range with a string using the same above premise I don’t get the same result. Shouldn’t a lowercase string occurred in both ranges?
[11] pry(main)> ('a'..'bat').include?('ace')
=> true
[12] pry(main)> ('A'..'bat').include?('ace')
=> false
instead I just get capitals.
[15] pry(main)> ('A'..'at').each {|letter| puts letter}
A
B
C
...
ZV
ZW
ZX
ZY
ZZ
=> "A".."at"
Those are two different types of ranges.
If you ask for a range of single characters, then you get all the characters in between as defined by the character encoding (e.g. ASCII), as you saw. But if you ask for a range including strings that are longer than one character, then it no longer uses character set order.
What happens instead is that Ruby treats each character position as a “digit”, where the set of possible digits is based on the type of character. Letters of the alphabet are grouped by case, so an uppercase “digit” will always be uppercase throughout the range; a range that starts with all uppercase letters will never contain a lowercase letter. Your range that starts at “A” will never get to “at”, but rather than continue to infinity, Ruby stops after “ZZ” because it would have to go to three characters after that, and your specified upper limit is only two characters long.