O OP escreveu
Parece-me estranho que a construção acima não produza o resultado esperado. Qual é a razão disso? Quais são as situações em que esse comportamento é razoável?
não 'Isso pode ser feito?' mas para responder à pergunta que não foi feita antes de chegar à pergunta que realmente foi feita:
$ irb
2.1.5 :001 > (0..4)
=> 0..4
2.1.5 :002 > (0..4).each { |i| puts i }
0
1
2
3
4
=> 0..4
2.1.5 :003 > (4..0).each { |i| puts i }
=> 4..0
2.1.5 :007 > (0..4).reverse_each { |i| puts i }
4
3
2
1
0
=> 0..4
2.1.5 :009 > 4.downto(0).each { |i| puts i }
4
3
2
1
0
=> 4
Uma vez que é afirmado que reverse_each constrói um array inteiro, downto será claramente mais eficiente. O fato de que um designer de linguagem pode até mesmo considerar a implementação de coisas como essa meio que se vincula à resposta à pergunta real quando feita.
Para responder à pergunta como realmente feita ...
A razão é porque Ruby é uma linguagem infinitamente surpreendente. Algumas surpresas são agradáveis, mas há muitos comportamentos que estão completamente quebrados. Mesmo que alguns dos exemplos a seguir sejam corrigidos por versões mais recentes, há muitos outros e eles permanecem como acusações sobre a mentalidade do design original:
nil.to_s
.to_s
.inspect
resulta em "" mas
nil.to_s
# .to_s # Don't want this one for now
.inspect
resulta em
syntax error, unexpected '.', expecting end-of-input
.inspect
^
Você provavelmente esperaria que << e push fossem iguais para anexar a matrizes, mas
a = []
a << *[:A, :B] # is illegal but
a.push *[:A, :B] # isn't.
Você provavelmente esperaria que 'grep' se comportasse como seu equivalente de linha de comando do Unix, mas faz === não correspondendo a = ~, apesar de seu nome.
$ echo foo | grep .
foo
$ ruby -le 'p ["foo"].grep(".")'
[]
Vários métodos são inesperadamente apelidos uns para os outros, então você precisa aprender vários nomes para a mesma coisa - por exemplo, find
e detect
- mesmo se você gosta da maioria dos desenvolvedores e usa apenas um ou outro. Praticamente o mesmo vale para size
, count
e length
, exceto para classes que definem cada um de forma diferente, ou não definem um ou dois.
A menos que alguém tenha implementado algo diferente - como o método principal tap
foi redefinido em várias bibliotecas de automação para pressionar algo na tela. Boa sorte para descobrir o que está acontecendo, especialmente se algum módulo exigido por algum outro módulo manipulou outro módulo para fazer algo não documentado.
O objeto de variável de ambiente, ENV não suporta 'mesclar', então você tem que escrever
ENV.to_h.merge('a': '1')
Como um bônus, você pode até mesmo redefinir suas constantes ou as de outra pessoa se mudar de ideia sobre como elas deveriam ser.