【Rubyist近況 Advent Calendar 2021】2021年の活動履歴【23日目】

Rubyist近況 Advent Calendar 2021 23日目の記事になります。
近状ということでこの記事では今年の活動履歴をまとめてみたいと思います。

Burikaigi2021

今年の1月に Burikaigi2021 というイベントがあり、そこで Ruby 2.0 ~ Ruby 3.0 でどう移り変わっていったのかの話をしました。
Burikaigi 自体は初参加で今年はコロナの影響でオンライン開催でした。
現地でぶりを食べたかったですが残念。

わたしは Ruby 2.5 あたりから Ruby を使い始めた新参者なんですがスライドを書くにあたり古い Ruby の話とかを調べていていろいろと楽しかったですね。
Ruby 1.9 の話とかは読んでて普通におもしろかった。
ちなみに Burikaigi は来年もあるようです。

Misokatsu.rb #1

2月には Misokatsu.rb #1 というイベントがあり Ruby 3.0 で変更された privateattr_xxx の組み合わせの話をしました。

関係ないですが直前まですっかり忘れてたんですが Misokatsu.rb というイベント名はわたしが命名しました。味噌カツ食べたい! 2回目が開催されるのを楽しみにしています!

Hirakata.rb

今年の1月から週1でもくもく会が開催されていた Ruby のコミュニティです。
ほぼ1年間毎週継続して開催しててすごい。
わたしも不定期で参加しており、途中から始まったパーフェクトRails の輪読会は毎回参加していました。
あんまりモブプロの経験がないのでみんなでわいわいいながらコードを書くのが体験としてめっちゃよかったですね。
会終了後も Ruby / Rails について雑談したり他の人の質問に答えたりしてよいコミュニティでした。
土曜日の朝に開催していたので起きるのがちょっと大変でしたがわいわいいいながら話しているのが楽しい時間でした。
最近は諸事上により不定期開催になっちゃったんですがまた開催されるのを楽しみにしています!

Omotesando.rb

オフラインの頃から参加しているコミュニティです。
オフラインの時は毎回参加 + LT していたけど今年は不定期で参加していた事が多かったかな? 割とその場でザッとスライドっぽいものを書いて話したり、コード書きながら話したりすることが多いのであんまり登壇内容を覚えてない…。
スライドがあるものだと以下のような話をしたりしていました。

来年はもっとアウトプットしていきたいですねえ。

Rubyのしくみ 読書会を完走した

一人で読むのが大変!!!ということで去年の11月からクローズドで毎週行っていた Rubyのしくみの輪読会を今年の4月に無事完走しました。
勢いで始めた + 輪読会自体が初めての経験だったんですがちゃんと完走できてよかった…。
いやーほぼ1人で運用、管理、まとめを行っていて正直めちゃくちゃ大変でした…ちゃんと終わらせる事ができてわたしえらい! 本自体も内容がかなり難しいので参加者の足並みを揃えて進めて行くのが大変で毎回全員で『わからねー』っていいながらゆっくりと進めていきました。
読書会の議事録などはちゃんとログとして取ってあるのでどこかのタイミングで公開できるといいですねえ。
あと本自体の感想はまたどこかでまとめて書きたい…。

エディタ好きは語りたい LT会 - vol.2

9月には エディタ好きは語りたい LT会 - vol.2Vim の話をしました。
最近はあんまり LT でエディタの話をしていなかったので久々に Vim の話ができて楽しかったですね。

またどこかで Vim の話がしたい…。

るりまに PR 投げまくった

Ruby への貢献活動の1つとして今年は Ruby リファレンスマニュアルPR を投げまくってました。 いま数えてみたら40個 PR を投げてたっぽい、めっちゃ投げてるやん。
PR の内容は主にサンプルコードのハイライトの追加になります。
最近るりまにサンプルコードがハイライトされる機能が追加されたんですがまだ対応していないサンプルコードが多く残っているのでそれを地道に対応していました。
ほぼ手動でがんばって直しています。
今年の後半は忙しくてあんまり PR 投げられなかったんですが Ruby 3.1 もリリースされるとそれの対応も必要になってくると思うのでまたぼちぼち活動していきたいですねえ。

銀座Rails

去年も何回か登壇させて頂いたんですが、今年も2回登壇させてもらいました。
毎回すごい人数の方が参加されててすごいですね…。

毎回 Ruby のマニアックな話ばかりしているので来年は何かしら Rails 絡みの話をしてみたいですねえ。

RubyKaigi Takeout 2021

今年一番大きいイベントとして 9月に開催された RubyKaigi に初登壇&初参加しました。

いやーーーーこの規模のカンファレンスに登壇するのははじめてだったのでいろいろと大変でした。
RubyKaigi に関しては以下の記事を参照してください。

と、言うことで 2021年の活動履歴でした。
まとめてみると今年もいろいろとやってきたんですが来年もまたほそぼそと活動していきたいですねー。

2021/12/23 今回の気になった bugs.ruby のチケット

今週は Ruby 3.1 で Class.descendants が Revert されたりしました。

[Feature #14394] Class.descendants

  • .descendants はレシーバが『継承されている』クラスの一覧を返すメソッドの追加の提案
class A; end
class B < A; end
class C < B; end

pp A.descendants    #=> [B, C]
pp B.descendants    #=> [C]
pp C.descendants    #=> []

[Bug #17866] Incompatible changes with Psych 4.0.0

【一人 bugs.ruby Advent Calendar 2021】[Bug #17866] Incompatible changes with Psych 4.0.0【23日目】

一人 bugs.ruby Advent Calendar 2021 23日目の記事になります。
今日は Psych4.0.0 にメジャーアップデートすることで非互換になる話です。

[Bug #17866] Incompatible changes with Psych 4.0.0

Psych.loadPsych.safe_load に置き換える PR がマージされて Psych 4.0.0 がリリースされました。
このチケットは Psych 4.0.0 が非互換になるのでそれの対応をするチケットになります。
問題点は大まかに2つあり、1つはデフォルトだとエイリアスが許可されていない問題です。
なので次のように &default を使用している YAML ファイルを読み込むと Psych 4.0.0 ではエラーになってしまいます。

require "psych"
require "date"

data = <<~EOS
default: &default
  aaa: aaa
development:
  <<: *default
EOS

# Psych 4.0.0 以前 => OK 読み込める
# Psych 4.0.0 以降 => NG 読み込めない
pp Psych.load(data)

これの影響でいくつかの gem が対応を行っています。

このエイリアスがデフォルトで不許可になったのは再帰的なエイリアスになった場合に安全ではないケースがあるのが理由になります。
例えば以下のようなデータを読み込んだ際にの場合にクラッシュしてしまうのを防ぐためです。

require "psych"

def process thing
  thing.each do |item|
    case item
    when Array
      process item
    when Hash
      # ...
    when String
      # ...
    end
  end
end

user_input = <<~EOS
--- &1
- *1
EOS

# error: stack level too deep (SystemStackError)
process Psych.load(user_input)

また Psych.load は『キーに Symbol を定義できることを許容している』が YAML.load_file に反映されていない問題があるようです。

# :text: という書き方が許可されてほしいが許可されていない
require "psych"
require "tempfile"
require "yaml"

Tempfile.open "example" do |file|
  file.write %(:text: "Hello.")
  file.rewind
  # load は OK
  puts "YAML Contents: #{YAML.load file}"
  # load_file は NG
  puts "YAML Contents: #{YAML.load_file file}"
end

この Psych 4.0.0Ruby 3.1 からバンドルされる予定なので Ruby 3.1 にアップデートする際は注意する必要があります。

【一人 bugs.ruby Advent Calendar 2021】[Bug #18246] send does not work for unary ! operator when operator isn't a literal symbol【22日目】

一人 bugs.ruby Advent Calendar 2021 22日目の記事になります。
今日は ! 単項演算子send で呼び出す時の話です。

[Bug #18246] send does not work for unary ! operator when operator isn't a literal symbol

! 単項演算子send で呼び出すとエラーになるというバグ報告です。

# これは + 二項演算子を呼ぶ
1.send(:+, 2)    # => 3
1.send(:"+", 2)  # => 3

# これは - 単項演算子を呼ぶ
1.send(:-@)   #=> -1
1.send(:"-@") #=> -1

# これは ! 単項演算子を呼び出してほしい
# ok
false.send(:!@)   #=> true

# error: undefined method `!@' for false:FalseClass (NoMethodError)
false.send(:"!@")

1.send(:"-@") だと - 単項演算子を呼び出すが false.send(:"!@") だとエラーになってしまいます。
これは期待する挙動で ! 単項演算子を呼び出す場合は ! メソッド名で呼び出す必要があります。
なので

false.send(:"!") # => true

は問題なく動作します。
逆に false.send(:!@) がなぜ動くのかと言うと :!@ というシンボルは :! と等価なので結果的に false.send(:!@)false.send(:!) になるからです。

p :!@     # => :!
p :"!@"   # => :"!@"

これは知らなかった。

【一人 bugs.ruby Advent Calendar 2021】[Bug #17423] `Prepend` should prepend a module before the class【21日目】

一人 bugs.ruby Advent Calendar 2021 21日目の記事になります。
今日は prepend の挙動がちょっと変わる話です。

[Bug #17423] Prepend should prepend a module before the class

Ruby 3.0 では継承リスト周りの処理が色々と改善されました。
が、結果 #prepend が意図する挙動をしていないケースがありました。

module M; end
module A; end
class B; include A; end

A.prepend M
B.prepend M

# B に prepend M しているのに反映されてないように見える
p B.ancestors
# 2.7 => [M, B, A, Object, Kernel, BasicObject]
# 3.0 => [B, M, A, Object, Kernel, BasicObject]

これの対処として [M, B, M, A, Object, Kernel, BasicObject] を返すようにする、というのがこのチケットの内容です。
この場合は ancestors の結果に対して M が重複してしまうんですが、次のようなコードでも重複するので問題ないとのこと。

module M; end
class A; end
class B<A; end

A.prepend M
B.prepend M

# これは Ruby 3.0 以前からこのような挙動になっている
p B.ancestors # => [M, B, M, A, Object, Kernel, BasicObject]

これは既にマージされており、 Ruby 3.1 以降は以下のような挙動になる予定です。

module M; end
module A; end
class B; include A; end

A.prepend M
B.prepend M

p B.ancestors
# 2.7 => [M, B, A, Object, Kernel, BasicObject]
# 3.0 => [B, M, A, Object, Kernel, BasicObject]
# 3.1 => [M, B, M, A, Object, Kernel, BasicObject]

このあたりはちょっと注意して使う必要がありそうですねえ。
ちなみにこのチケットは matz が立ててました。珍しいものをみた。

【一人 bugs.ruby Advent Calendar 2021】[Bug #17719] Irregular evaluation order in hash literals【20日目】

一人 bugs.ruby Advent Calendar 2021 20日目の記事になります。
今日は Hash リテラルでキーが重複したときの話です。

[Bug #17719] Irregular evaluation order in hash literals

Hash リテラルでキーが重複している場合に以下のような評価順になります。

# 1個目と2個目の foo の要素が先に評価される
$ ruby -e '{ foo: p(1), bar: p(2), foo: p(3) }'
-e:1: warning: key :foo is duplicated and overwritten on line 1
1
3
2

上記の場合だと左から順に評価されるのではなくて先に foo のキーの値が評価される形になっています。
これはバグだったようで重複するキーがあっても左から順に評価されるように以下のように修正されました。

ary = []
{ a: ary << 1, b: ary << 2, a: ary << 3 }
pp ary
# Ruby 3.0 => [1, 3, 2]
# Ruby 3.1 => [1, 2, 3]

以下のような問題もあるしもうエラーにしちゃっていいんじゃないかなあ…と思わなくもない。

【一人 bugs.ruby Advent Calendar 2021】[Feature #17743] Show argument types in backtrace【19日目】

一人 bugs.ruby Advent Calendar 2021 19日目の記事になります。
今日はバックトレースに引数情報も追加する話です。

[Feature #17743] Show argument types in backtrace

バックトレースに引数情報も追加する提案です。
例えば以下のようなコードを実行すると

def say_hi(person)
  puts message(person)
end

def message(person)
  "hi: #{person.name}"
end

say_hi(nil)

以下のようなバックトレースが出力されますが、

hi.rb:6:in `message': undefined method `name' for nil:NilClass (NoMethodError)
  from hi.rb:2:in `say_hi'
  from hi.rb:9:in `<main>'

これを以下のようにする提案になります。

hi.rb:6:in `message': undefined method `name' for nil:NilClass (NoMethodError)
    from hi.rb:2:in `say_hi' called with NilClass
    from hi.rb:9:in `<main>' called with NilClass

どのような表記にするのか(クラスだけ?値は必要がない?複数の引数の場合は?)やパフォーマンス的な懸念点がないか議論されています。
デバッグ情報としては全ての情報が表示されているとよいのですが、普段遣いで全部表示されてもノイズが多そうなのでトレードオフがむずかしそうですねえ。