2021/01/07 今週の気になった bugs.ruby のチケット

内容は適当です。
今週と言っても今週みかけたチケットなだけでチケット自体は昔からあるやつもあります。
あくまでも『わたしが気になったチケット』で全ての bugs.ruby のチケットを載せているわけではありません。

[Feature #17471] send_if method for improved conditional chaining

  • 以下のような #send_if を追加する提案
class Object
  def send_if(method, *args, proc: nil)
     yield(self) ? self.send(method, *args, &proc) : self
  end
end
  • これは以下のように『条件にマッチしたときのみメソッドチェーンを行う』ような場合に利用できる
puts 'Do you want a loud Merry Christmas? (y or I take it as a no)'
answer = gets.chomp

# 標準入力を受け取り、入力によって呼び出す処理を切り替える
# 'y' が入力されたら大文字に変換して結合する
puts %w(Merry Christmas).send(:map, &->(e) { answer == 'y' ? e.upcase : e }).join(' ')

# 提案されている send_if ならこんな感じで記述できる
puts %w(Merry Christmas).send_if(:map, proc: :upcase) { answer == 'y' }.join(' ')
  • わたしもこういうのがほしいと思っていていろいろと考えているんですが今回の #send_if はかなりやってることが多くて個人的にはちょっと微妙
    • とはいえこうなってしまう理由もわかるのでうーーーーんって感じ
    • 条件条件にマッチした場合の処理 の2つのブロックをメソッドに渡したいんですが Ruby でこのあたりどう表現すべきなのかが難しい
  • ちなみに個人的には以下のような tap + break でいいじゃん、ってなっています
# Proposal
puts %w(Merry Christmas).send_if(:map, proc: :upcase ) { answer == 'y' }.join(' ')

# tap + break
puts %w(Merry Christmas).tap { break _1.map(&:upcase) if answer == 'y' }.join(' ')
  • tap + break に慣れてないとぎょっとするんですが、これはこれで Ruby としてみるとかなり素直なコードになっているので個人的には気に入っています
  • また似たようなチケットとしては以下のようなチケットもあるので気になる人はこちらも見てみると良いです

[Bug #17512] ostruct super regression

  • 以下のように super を経由して OpenStruct を参照した場合に Ruby 3.0 だと意図しない値が返ってきているというバグ報告
require 'ostruct'

class Foo < OpenStruct
  def foo
    super
  end
end

p Foo.new(foo: 123).foo
# Ruby 2.7 => 123
# Ruby 3.0 => nil
  • この問題は OpenStruct 0.3.2 で修正されている
  • 困っている人は個別に OpenStruct をインストールすると改善すると思います

[Misc #16436] hash missing #last method, make it not so consistent (it has #first)

  • Hash#first はあるけど Hash#last はないので一貫性がないよねーっていうチケット
homu = { id: 1, name: "homu", age: 14 }

pp homu.first
# => [:id, 1]

# error: undefined method `last' for {:id=>1, :name=>"homu", :age=>14}:Hash (NoMethodError)
pp homu.last
  • これは Hash#firstEnumerable#first で実装されており Enumerable#last がないからです
    • Enumerable#first があって Enumerable#last がないのは知らなかった
    • まあ確かにイテレーションを考えると #first はあっても #last がないのはなんとなくわかるよな…?
  • ちなみに以下のように #reverse_each を使うと終端の要素を取得することはできます
homu = { id: 1, name: "homu", age: 14 }

pp homu.reverse_each.first
# => [:age, 14]
  • このチケット自体には強い気持ちでの要望とかはないので、もし必要な人とかがいればコメントしてみるといいと思います

[Bug #17488] Regression in Ruby 3: Hash#key? is non-deterministic when argument uses DelegateClass

  • 次のように Ruby 3.0 で Hask#key?DelegateClass を渡すと意図しない結果が返ってくるというバグ報告
    • Ruby 3.0 では Hask#key? の結果が起動毎に変わることがある
puts "Running on Ruby: #{RUBY_DESCRIPTION}"

program = <<~EOS
  require "delegate"
  TypeName = DelegateClass(String)

  hash = {
    "Int" => true,
    "Float" => true,
    "String" => true,
    "Boolean" => true,
    "WidgetFilter" => true,
    "WidgetAggregation" => true,
    "WidgetEdge" => true,
    "WidgetSortOrder" => true,
    "WidgetGrouping" => true,
  }

  puts hash.key?(TypeName.new("WidgetAggregation"))
EOS

iterations = 20
results = iterations.times.map { `ruby -e '#{program}'`.chomp }.tally

# Ruby 3.0 で実行すると false が返ってくることがある
puts "Results of checking `Hash#key?` #{iterations} times: #{results.inspect}"
# Ruby 2.7 => Results of checking `Hash#key?` 20 times: {"true"=>20}
# Ruby 3.0 => Results of checking `Hash#key?` 20 times: {"false"=>12, "true"=>8}

[Bug #17481] Keyword arguments change value after calling super without arguments in Ruby 3.0

  • 次のように super を呼び出す前と後でキーワード引数の値が変わってしまうというバグ報告
class BaseTest
  def call(a:, b:, **)
  end
end

class Test < BaseTest
  def call(a:, b:, **options)
    p options  # =>  {:c=>{}}
    super
    # super を呼び出した後で options の値が変わってしまっている…
    p options  # =>  {:c=>{}, :a=>1, :b=>2}
  end
end

Test.new.call(a: 1, b: 2, c: {})

[Feature #17472] HashWithIndifferentAccess like Hash extension

  • ActiveSupport::HashWithIndifferentAccess をサポートする機能を Ruby で実装する?というチケット
  • ちょっとチケットの意図が読み取れてないので間違ってるかもしれませんが『Ruby 本体で ActiveSupport::HashWithIndifferentAccess を実装する(提供する)』というわけではなくて『 `ActiveSupport::HashWithIndifferentAccess を高速化できる仕組みを Ruby 側で用意する』っていうのが趣旨なのかな?
  • 具体的に言うと Ruby 3.0 で追加された Symbol#name みたいなのを Ruby 本体で ActiveSupport::HashWithIndifferentAccess を高速化できるような機能を提供する感じなんですかね
    • コメント読んでる限りこのあたりちょっと認識のズレがありそう
  • 最初読んだ時に『 ActiveSupport::HashWithIndifferentAccessRuby で提供するのはやめてくれ〜〜〜』と思っていたんですが機能提供って意味だとかなりよさそうですね

[RP] Remove deprecated URI.escape/URI.unescape

使ってる Vim プラグインを紹介する:行番号を指定してファイルを開く

気が向いたら書いていくシリーズ。 よく考えたらアドベントカレンダーで書けばよかったのでは…?

行番号を指定してファイルを開く file-line

このプラグインを入れると vim コマンドでファイルを開くときに

$ vim index.html:20

のように行番号を指定して開くことができるようになります。 また vim コマンドだけではなくて『 vim のコマンド』でも行番号を指定して開けます。

:edit index.html:20
# 新しいタブで開く
:tabnew index.html:20

エラー出力のフォーマットは ファイル名:行番号 みたいになっていることが多いので、エラー出力をそのままコピペすればエラー位置を一発で開くことができるので便利。

使ってる Vim プラグインを紹介する:カーソル下の単語をハイライトする

気が向いたら書いていくシリーズ。

t9md/vim-quickhl

カーソル下の単語をハイライトするプラグインです。
ハイライトされた単語は表示されているウィンドウすべてに反映されます。

# スペース + m でカーソル下の単語をハイライトする
nmap <Space>m <Plug>(quickhl-manual-this)
# 選択したテキストをハイライトする
xmap <Space>m <Plug>(quickhl-manual-this)

# スペース + m ですべてのハイライトを無効にする
nmap <Space>M <Plug>(quickhl-manual-reset)

# operator として定義しておく
# mi( でカッコの中をハイライトする等
nmap m <Plug>(operator-quickhl-manual-this-motion)
vmap m <Plug>(operator-quickhl-manual-this-motion)

こんな感じで変数がどこで使われているのかが視覚的にわかるようになるので便利。

M1 の MacBook で rbenv + Ruby 2.6.6 をビルドする

rbenv で Ruby 2.7 や 3.0 のビルドは問題なかったんですが 2.6 で失敗したのでその対処方法を書いておきます。

rbenv で 2.6.6 をインストールする

rbenv で 2.6.6 をインストールしようとしたらエラーになります。

$ rbenv install 2.6.6
Downloading openssl-1.1.1i.tar.gz...
-> https://dqw8nmjcqpjn7.cloudfront.net/e8be6a35fe41d10603c3cc635e93289ed00bf34b79671a3a4de64fcee00d5242
Installing openssl-1.1.1i...
Installed openssl-1.1.1i to /Users/anzu/.rbenv/versions/2.6.6

Downloading ruby-2.6.6.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.6.tar.bz2
Installing ruby-2.6.6...
ruby-build: using readline from homebrew

BUILD FAILED (macOS 11.1 using ruby-build 20201225-2-g5de6d5f)

Inspect or clean up the working tree at /var/folders/j_/4snw29l52s5g_hwy5fxbvqsw0000gp/T/ruby-build.20210102215022.60171.Wp1e2j
Results logged to /var/folders/j_/4snw29l52s5g_hwy5fxbvqsw0000gp/T/ruby-build.20210102215022.60171.log

Last 10 log lines:
compiling zlib.c
compiling normalize.c
compiling modify.c
compiling set_len.c
compiling enc_str_buf_cat.c
compiling new.c
linking shared-object -test-/string.bundle
linking shared-object date_core.bundle
linking shared-object zlib.bundle
make: *** [build-ext] Error 2

実際のコンパイルエラーは以下な感じです。

compiling nofree.c
linking shared-object -test-/wait_for_single_fd.bundle
linking shared-object -test-/vm/at_exit.bundle
compiling closure.c
compiling zlib.c
compiling ellipsize.c
installing default libraries
compiling conversions.c
closure.c:264:14: error: implicit declaration of function 'ffi_prep_closure' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
    result = ffi_prep_closure(pcl, cif, callback, (void *)self);
             ^
compiling normalize.c
1 error generated.
make[2]: *** [closure.o] Error 1
make[2]: *** Waiting for unfinished jobs....
linking shared-object date_core.bundle
compiling psych_to_ruby.c
compiling escape.c
compiling stringio.c
compiling modify.c
make[1]: *** [ext/fiddle/all] Error 2
make[1]: *** Waiting for unfinished jobs....

ffi 周りでコケてるっぽい…。

RUBY_CFLAGS=-DUSE_FFI_CLOSURE_ALLOC rbenv install 2.6.6 でインストールする

困ってたら以下の issues を教えてもらってそこに書いてあった RUBY_CFLAGS=-DUSE_FFI_CLOSURE_ALLOC rbenv install 2.6.6 で無事にインストールすることができました。

$ RUBY_CFLAGS=-DUSE_FFI_CLOSURE_ALLOC rbenv install 2.6.6
rbenv: /Users/anzu/.rbenv/versions/2.6.6 already exists
continue with installation? (y/N) y
Downloading openssl-1.1.1i.tar.gz...
-> https://dqw8nmjcqpjn7.cloudfront.net/e8be6a35fe41d10603c3cc635e93289ed00bf34b79671a3a4de64fcee00d5242
Installing openssl-1.1.1i...
Installed openssl-1.1.1i to /Users/anzu/.rbenv/versions/2.6.6

Downloading ruby-2.6.6.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.6.tar.bz2
Installing ruby-2.6.6...
ruby-build: using readline from homebrew
Installed ruby-2.6.6 to /Users/anzu/.rbenv/versions/2.6.6

ありがてえありがてえ…。

M1 の MacBook Air のセットアップした

あけましておめでとうございます。
今年は年明けから年末に買っていた M1 の MacBook Air のセットアップをしていました。
この記事も M1 で書いています。
ぶっちゃけ発売前はネガティブな印象が強かった M1 だったんですが発売後はコスパがよかったりソフトウェアの対応なども進んで来ていて割と好印象だったのでつい勢いで買ってしまいました。
実際セットアップもそこまで手間取ることなく普通にアプリケーションなどもインストールできました。
今のところは目立ったトラブルがないのでよかったよかった。
と、言うことで覚書。

homebrew

ちょうど 12/30 に公式でサポートしたらしくていつもどおり公式に載ってるコマンドを実行すればインストールすることができます。

$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

ただし、手元だとこれだけではパスが通らす brew コマンドが使えなかったので .zshrc にパスを追加してやる必要がありました。

# .zshrc
typeset -U path PATH
path=(
    /opt/homebrew/bin(N-/)
    /usr/local/bin(N-/)
    $path
)

これで無事に brew コマンドが使えるようになりました。便利。

rbenv + ruby-build

rbenv は特に問題なく brew でインストールできました。
また ruby-buildbrew 経由でインストールすると最新版が反映されるまでにラグがあるので git から直接 clone しました。

# rbenv をインストールする
$ brew install rbenv

# 一旦消す
$ brew uninstall ruby-build

# git からインストールする
$ mkdir -p "$(rbenv root)"/plugins
$ git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build

また rbenvRuby 3.0 のインストールも特に問題なくできました。便利。

所感

上に書いた以外には macvim とか karabiner とか chrome とか入れたんですが今の所問題なく動いていますね。
実際の開発環境とかはこれから整える予定ですが思ったよりもスムーズにセットアップできてよかったよかった。
まだ感想をかけるほど使ってはいないんですがこれから docker とかそこら辺を試していきたいところ。
あと外観的な感想で言うと思ったよりも小さくて軽いなーっていう印象が強かったです。
まあ今まで使ってた MacBook Pro が重すぎたのかもしれませんが…。
あとベゼルが思ったよりも太い感じはしましたね。
こっちも最近のラップトップはベゼルが細いのが多いのでそれと比較して太い気がしているのかもしれませんが。
とりあえず、せっかく買ったのでもうちょいいろいろと遊んでみたいところです。

f:id:osyo-manga:20210101183023j:plain

参照

2020年を振り返って

技術的な話で振り返ろうかと思ったのですがこころつらくなっているので今年読んで面白かったマンガの紹介をします。
ってちょろっと書こうと思ったら思ったよりもボリュームが増えてしまい…。
内容は薄いですが気になったやつがあればぜひぜひ読んでもらえると〜。
ちなみに今年は kindle で 1000冊以上買っていました。

Fate/kaleid liner プリズマ☆ ドライ!!

Fate/kaleid liner プリズマ☆イリヤ ドライ!!(1) (角川コミックス・エース)

ご存知、魔法少女になるやつです。
アニメはほとんど見てません。
元々途中までは物理本で持ってたんですが kindle でまとめ買いしました。
本編よりも過去編がめっちゃ良かった…。

はしっこアンサンブル

はしっこアンサンブル(1) (アフタヌーンコミックス)

げんしけん』の作者が描く工業高校の合唱部の青春物語。
げんしけん』もそうだけどこの手の青春者を描くうまいよねー。
個人的には『げんしけん』よりもクセがなくて万人受けするような内容になっていると思うのでおすすめです(ちょいちょい重い話が挟まっているのから目をそらしつつ。

よっけ家族

よっけ家族 1 (バンブーコミックス)

一時期『うさぎドロップ』の作者の宇仁田ゆみにハマって買い漁っていたうちの一つです。
特に大きなイベントがあるわけでもなくてただただある家族の日常が書かれており何も考えずに読むことができます。
いまの生活に疲れている人におすすめのマンガです。
このマンガが面白いと思ったら他の宇仁田ゆみマンガも読んでみるとよいです!

クミカのミカク

クミカのミカク(1) (RYU COMICS)

ただただヒロインがご飯を食べているマンガ。
読んでると無限にお腹が空いてくるのでよくない。

サチコと神ねこ様

サチコと神ねこ様【フルカラー】(1)

ねことアラサーリケジョOL とのやり取りが面白いマンガ。
ちょこちょこ入ってくる毒舌の時事ネタが好きです。
うちにも神ねこ様が来てほしい。

シャングリラ・フロンティア ~クソゲーハンター、神ゲーに挑まんとす~

シャングリラ・フロンティア ~クソゲーハンター、神ゲーに挑まんとす~(1) (週刊少年マガジンコミックス)

いわゆるなろう系マンガなんだけど内容自体は普通に面白い。
なろう系特有のご都合主義は結構強めだけどそのあたりが気にならない人は大丈夫だと思う。
まだ、2巻しか出てないのでこれからどういう展開になるのかは気になるところ。

スピリットサークル

スピリットサークル (1) (ヤングキングコミックス)

個人的に人生トップ10に入る『惑星のさみだれ』の作者の水上悟志のマンガ。
前から知り合いにおすすめされてたけどやっとよめた。よかった。
雰囲気とかは『惑星のさみだれ』に似ているけどそれよりももっと設定は複雑になっている。
どうせ読むなら一気読みしてほしいマンガ。

スペクトラルウィザード

スペクトラルウィザード

最近おすすめされて読んだマンガ。
登場キャラクターがかわいい。
一応2巻まで出ているんだけど完結しているかどうかはわからない。
2巻の最後がとてもつらいので救いを求めて続きを読みたいんだけどどうにかならんですかね…。

ダンジョン飯

ダンジョン飯 1巻 (HARTA COMIX)

これも最近読んだマンガ。
前から読みたかったけどやっと読むことができた。
もうちょっと飯中心なのかな、と思ってたけど思ったよりもダンジョンしてた。
これも読んでると腹が減るのでよくない。

ドロヘドロ

ドロヘドロ(1) (IKKI COMIX)

これも前から読みたいと思っていて(ry。
もっと殺伐としているのかと思ってたけど思ったよりもコミカルな内容だった。
キノコで無双するマンガは後にも先にもこれしかないでしょう。
結構中身が長いのと根本的な部分が最後まで引っ張られているので一気読みできてよかった。

ブルーピリオド

ブルーピリオド(1) (アフタヌーンコミックス)

高校生が 0 から美大を目指す青春物。
苦悩しながらも試行錯誤して先に進もうとしていくあたりがぐっと来ますねえ。
読んでて世界観に引き込まれていきます。

ポンコツちゃん検証中

ポンコツちゃん検証中(1) (少年サンデーコミックス)

ポンコツちゃんがかわいいだけのマンガ。
内容は王道ラブコメで久々にこういうの読んだ気がする。

ヤンキー君と白杖ガール

ヤンキー君と白杖ガール 1 (MFC)

あれ、これ去年紹介してなかったっけ?と思ったら紹介してなかった。
多分今年読んだ中で一番よかったマンガ。
内容はタイトルどおりでヤンキーな主人公と「弱視」なヒロインがいちゃつくマンガ。
と、思いきやライトな絵に反して内容はかなりヘビー、ヘビーなんだけど軽く読むことができる内容になっていてそのあたりのバランスがとてもよい。
読んでていろいろと考えさせれられるマンガです。

事情を知らない転校生がグイグイくる。

事情を知らない転校生がグイグイくる。 1巻 (デジタル版ガンガンコミックスJOKER)

グイグイくるマンガです。
夫婦やん?

兄の嫁と暮らしています。

兄の嫁と暮らしています。 1巻 (デジタル版ヤングガンガンコミックス)

共依存』っていう言葉がピッタリのマンガですね(白目。
よくある『がんばって前を向いて生きていこう』みたいなマンガかと思ったらどんどん病んでいくあたりがとてもたまりませんね。
まだまだ落ちていきそうなので続きが楽しみ。

古見さんは、コミュ症です。

古見さんは、コミュ症です。(1) (少年サンデーコミックス)

これも今年読んだマンガだったか。
ひたすら古見さんがかわいいだけのマンガです。
あと登場キャラクターのネーミングセンスが好き。

女の園の星

女の園の星(1)【電子限定特典付】 (FEEL COMICS swing)

面白い!!!以上!!!! とにかく無限に読んでいられるので早く続きが読みたい。

将棋めし

将棋めし 1 (MFコミックス フラッパーシリーズ)

タイトル通り将棋めしの話。
読んでて腹が減ります。
わたしは将棋はあんまりわからんので飯の話しか頭に入ってこなかったんですが将棋要素もあるのでそっちに興味がある人も読んでみると面白いのでは。

忍者と極道

忍者と極道(1) (コミックDAYSコミックス)

忍者と極道がヒャッハー!!するマンガです。
とにかく勢いがすごくて勢いで話が進んでいきます。

怪獣8号

怪獣8号 1 (ジャンプコミックスDIGITAL)

これはもう『面白い!!』の一言に尽きる。
内容は一言で言うと『仮面ライダー』なんですがこういう設定好きなんですよねえ。
まだ 1巻しか出てないけどすぐに続きを読みたい…。

放課後ていぼう日誌

放課後ていぼう日誌 1 (ヤングチャンピオン烈コミックス)

最近アニメを3周ぐらいしました。
いや、アニメ化する前から買ってたんですが。
内容は女子高生が釣りをするだけのマンガ。
よくよく考えると今年は釣りマンガばっかり買ってた気がする。

木曜日は君と泣きたい。

木曜日は君と泣きたい。(1)【電子限定特典付】

もうなんというか脳が混乱するマンガ。
それぞれがそれぞれに依存していいぞこれ〜〜ってなってました。
巻数が少ないのでさくっと読めますね。

波よ聞いてくれ

波よ聞いてくれ(1) (アフタヌーンコミックス)

確かアニメを1話だけ見て面白かったので衝動買いしたような記憶がある。
主人公が破天荒すぎるのが読んでて面白い。
ほとんどラジオは聞いたことないんですが読んでるとラジオを聞きたくなってきますね。
あとカレーも無限に食べたくなってくる。

無能の鷹

無能の鷹(1) (Kissコミックス)

めっちゃいい。

異種族レビュアーズ

異種族レビュアーズ (ドラゴンコミックスエイジ)

スケベが大好きなマンガです。
天原いいよね天原
アニメも好きです。

薬屋のひとりごと~猫猫の後宮謎解き手帳~

薬屋のひとりごと~猫猫の後宮謎解き手帳~(1) (サンデーGXコミックス)

薬屋のひとりごと』のコミカライズは サンデーGX 版と ガンガン 版の2種類ああるんですがわたしは サンデーGX 版の方が好きです。
いや、作画は ガンガン 版の方がいいんですが、話のつくりは サンデーGX の方がいいんですよね〜〜〜〜。
個人的には最初に サンデーGX を是非読んでもらいたいところ。

麻衣の虫ぐらし

麻衣の虫ぐらし(1) (バンブーコミックス)

タイトルに って付いているので虫要素はあるんですが、それ以上に病み要素が強すぎてな…。
むしろ はおまけ程度でヤンデレ百合マンガとして見たほうがいいと思います(こなみ感。
これも今年結構キタマンガでしたねえ。

邦画プレゼン女子高生 邦キチ! 映子さん

邦画プレゼン女子高生 邦キチ! 映子さん (マーガレットコミックスDIGITAL)

タイトル通りひたすら邦画のプレゼンをしているマンガです。
とにかくハチャメチャな邦画の紹介が面白い。
進撃の巨人の実写版ってあんな内容だったのか…。

【一人 cugs.ruby Advent Calendar 2020】[Feature #17016] Enumerable#scan_left【25日目】

一人 bugs.ruby Advent Calendar 2020 25日目の記事になります。
長かったアドベントカレンダーも今日で最後です。

[Feature #17016] Enumerable#scan_left

このチケットは Enumerable#scan_left を追加する提案です。
Enumerable#scan_leftEnumerable#inject と似たようなメソッドなのですが各ブロックの結果を配列で返します。

# inject は最後の結果だけ返す
[1, 2, 3].inject(0, &:+)
# => 6

# scan_left は各ブロックの戻り値を配列として返す
[1, 2, 3].scan_left(0, &:+)
# => [0, 1, 3, 6]

これは HaskellScala に存在する関数らしく Ruby でも欲しいそうです。
PR はちょっと前からあり、gem もあります。

ユースケースとしては累積和を求めるときに便利らしいです。
他にはコメントで以下のようなユースケーズも提示されています。

# 銀行の入出金履歴
gains = [+3000, -2000, +2000, -1000]

# 残高の履歴を計算
sums = [0]
(1..gains.length).each do |i|
  sums[i] = sums[i - 1] + gains[i - 1]
end
pp sums
# => [0, 3000, 1000, 3000, 2000]

# scan_left を使うとシュッとできる
sums = gains.scan_left(0, &:+)
pp sums
# => [0, 3000, 1000, 3000, 2000]

あとは以下のようなケースとか…。

module Enumerable
  # 疑似実装
  def scan_left(init = shift, &block)
    inject([init]) { |a, e| a << (block.call a.last, e) }
  end
end

# 4312.to_s.chars.sort.join.to_i の呼び出し過程を計算したりとか…
p [4312, :to_s, :chars, :sort, :join, :to_i].scan_left(&:send)
# => [4312, "4312", ["4", "3", "1", "2"], ["1", "2", "3", "4"], "1234", 1234]

ちなみに Enumerable#scan_left は以下のように #inject を使っても同じ値を取得する事はできます。

pp [1, 2, 3].inject([0]){ |a, e| a << a.last + e }
# => [0, 1, 3, 6]

ただし、この場合は普通には #lazy 化はできないので注意する必要があります。

# こういうような書き方はできない
(1..).lazy.inject([0]){|a, e| a << a.last + e} # => infinite loop
(1..).lazy.each_with_object([0]){|e, a| a << a.last + e} # => infinite loop
(1..).lazy.scan_left(0, &:+) # => Lazy enumerator

# がんばればできる
p (1..).lazy.enum_for(:inject, 0).map {|a, b| a + b }.take(10).force
# => [1, 3, 6, 10, 15, 21, 28, 36, 45, 55]

# もしくは
# p (1..).lazy.enum_for(:inject, 0).map {|a, b| a + b }.first(10)

#scan_left という名前はあんまりよろしくないと言うことで別の名前の提案がされいて今はそこで議論が止まっている感じです。
候補としては reflectproject interject tranject cumulative などなど…。
このあたりの名前決めは難しそうですねえ。