Olá Leandro,
O dup
serve para criar uma cópia do array do herói, se a gente não fizer isso ao modificar o heroi dentro dessa função vai afetar também o heroi inicial que está fora da função. É um pouco confuso mas segue um exemplo para ajudar a representar:
heroi_lucas = [2, 4]
# Passando o valor sem utilizar o dup
heroi_leandro = heroi_lucas
# Estamos modificando apenas o heroi_leandro
heroi_leandro[0] = 8
# Mas vemos que o heroi_lucas também foi modificado
print(heroi_lucas) # Resultado [8, 4]
print(heroi_leandro) # Resultado [8, 4]
Isso acontece porque ao fazer heroi_leandro = heroi_lucas
o ruby não vai copiar o valor de um para o outro fisicamente, vai apenas apontar as duas variáveis para o mesmo endereço de memória. Isso é um detalhe interno do ruby que é feito para melhorar a performance mas afeta apenas alguns objetos mais complexos como um array. Então existe o dup
para fazer a cópia física:
heroi_lucas = [2, 4]
heroi_leandro = heroi_lucas.dup
# Estamos modificando apenas o heroi_leandro
heroi_leandro[0] = 8
# Agora o heroi_lucas não foi modificado
print(heroi_lucas) # Resultado [2, 4]
print(heroi_leandro) # Resultado [8, 4]
Espero ter ajudado, qualquer dúvida é só falar!