Попробуйте:
words = ["horses", "follow", "useful", "offset"]
words.reverse.each_with_index.map{|s,i| " " * i + s }.inject(Array.new(words.size + words.last.size-1,"")) do |a,s|
s.chars.each_with_index do |c,i|
a[i] = c + a[i]
end
a
end.map(&:strip)
# => ["o", "uf", "fsf", "hoes", "olfe", "rlut", "sol", "ew", "s"]
Сначала words.reverse.each_with_index.map{|s,i| " " * i + s }
создает массив со смещением пробела:
offset
useful
follow
horses
Inject создает массив пустых строк, а внутри основного блока добавляются символы каждой строки.правильному элементу массива