初参加&初登壇の RubyKaigi Takeout 2021 で Ruby のマクロの話をしてきたよレポート
書こう書こうと思って気がついたら1ヶ月立っていましたこんにちは。
(去年を除いて)今回が RubyKaigi 初参加&初登壇ということでいろいろと書き残しておこうと思います。
ちなみに今週末に以下のようなイベントで雑に話すので興味がある方がぜひぜひ参加してみてくださいー。
ちなみに『Ruby のマクロ』という主語がクソデカなんですがあくまでも『この登壇では』という前提になります。
Use Macro all the time ~ マクロを使いまくろ ~
動画
補足
RubyVM::AST
はバージョンごとに非互換- Ruby 3.1dev では
RubyVM::AST::Node
から元のソースコードを取得する機能が入った- ただし『配列形式の AST』は依然として復元することができない
- それはそう
src = <<~EOS if hoge puts hoge + foo end EOS # keep_script_lines を true にすると node = RubyVM::AbstractSyntaxTree.parse(src, keep_script_lines: true) # #source メソッドでコードを取得できるようになる puts node.source # => if hoge # puts hoge + foo # end
Ruby でマクロを実装しようと思った経緯
元々は1年ぐらい前に『ブロック内のコードをテキストで取得したい』ということをやりたくて最初はこんな感じで iseq からブロックが定義されているファイルや位置情報を取得してきて実際にそのファイルからソースコードを取得する実装を書いていました。
最初はこれを使っていろいろと遊んでたんですがファイルを読み込む必要がある都合上どうしてもパフォーマンスが気になっていました。
そこで RubyVM::AbstractSyntaxTree.of
を利用してブロックから AST を取得し、それを元にして Ruby のコードを復元しよう!としたのが rensei-gem をつくりはじめたきっかけですね。
しばらくは『AST から Ruby のコードに変換する』を目的ととして rensei-gem をつくっていたんですが『あれ、AST を好きに変えたら Ruby のコードの意味を変えれるのでは…?』『これってマクロでは…?』などと考えるようになりました。
元々は Rust のようなマクロが Ruby にもほしいな〜〜〜と思っていて Rust のマクロを調べていた事もあったんですが Rust のマクロがまさに AST レベルでコードを変更するような機能になりますね。
とはいえ構想だけで1年ぐらい何もしていなかったんですが今回の RubyKaigi をきっかけに実際に実装してみた、って感じですね。
RubyKaigi への登壇のきっかけ
最初は RubyKaigi に登壇する事は考えてなかったんですが知り合いが CFP を出すという事で『じゃあ、わたしも出してみるか〜〜〜』というのが直接的なきっかけになります。
Ruby のマクロの話も前々からどこかではしたいと思っていたのでそれで CFP を出してみたって感じです。
なので CFP を書き始めたのは結構ギリギリでしたね。
具体的には CFP の締切が6月末で、6月23日から CFP を書きはじめました。
時系列的には以下のような感じですね。
全体的な時系列
- 2020/07〜08頃:この頃から
AST -> Ruby
に変換する実装のたたき台を書き始める - 2020/09〜:各 AST の種類から Ruby のコードに変換する処理をチマチマ書き始める
- 1日1対応する、みたいなことをしていた記憶
- 2020/12/01:Ruby Advent Calendar で AST -> Ruby のコードに変換する記事を書く
- 【Ruby Advent Calendar 2020】Ruby の AST から Ruby のソースコードを復元しよう【1日目】 - Secret Garden(Instrumental)
- 同時に rensei-gem (AST -> Ruby のコードに変換する gem)も公開
- ここで一旦燃え尽きた
- 2021/06/23:知り合いに触発されて RubyKaigi の CFP を書き始める
- 2021/06/30:RubyKaigi の CFP 締切
- 知り合いに翻訳のチェックなど行ってもらいだいぶ助かった…
- 2021/07/01:CFP の結果はまだだったがすぐに作業を開始
- 2021/07/05:Scrapbox に日報を書くように開始
- 今回これをやったのがかなりよかった
- ほぼほぼ毎日書いてた
- 2021/07/14:CFP が Accept されたと連絡をもらう
- 録画かリアルタイムか選択できて無限に悩み始める
- 内容が膨れることはわかっていたので録画の方がよさそうだなあ、と思いつつリアルタイムの方がギリギリまでスライドをかけるので…
- 結局リアルタイムを選択
- 録画かリアルタイムか選択できて無限に悩み始める
- 2021/07/14:ここから『Ruby のマクロとは…』を考え始める
- Rensei のバグ修正に終わりが見えずにこのままではやばいと気づき始める
- Rensei のバグ修正は最悪直ってなくても大丈夫ではあった
- この時にはじめて kenma-gem(Ruby のマクロを実装する gem)のたたき台を書き始める
- Rensei のバグ修正に終わりが見えずにこのままではやばいと気づき始める
- 2021/07/23:スライドのアウトラインを考え始める
- 2021/07/28:kenma-gem の仮実装が固まる
- 一段落したのでここからしばらく虚無が続く…
- 仮実装を知り合いに見てもらいつつ意見をもらい始める
- 2021/08/01:作業再開
- kenma(仮実装)を gem 化した
- 2021/08/11:実際に kenma-gem でオレオレマクロを定義しつつ課題を探し始める
- 2021/08/23:スライドを書き始め、ここで Scrapbox のログが途絶える
- ここからしばらく(プライベートで)超絶つらい期間が続く…
- 何も記憶がない
- ひたすらスライドを書いては知り合いに壁打ちをお願いしてたような…
- 2021/09/11:登壇当日
- なのか無事に終わらせた…
スライドに関して
スライド作成はいつも Reveal.js を使っていたんですがもうちょっとリッチなスライドをつくりたくて今回 slidev を使用してスライドをつくりました。
最初は slidev でいい感じに作れるやろ〜〜〜と軽く考えてたんですが実際はスライドを作っていた期間のうち半分は slidev と戦っていましたね…。なかなかいい感じにアニメーションとか作ることができなくて…。
スライド自体もなるべく前提知識がなくてもわかるように構成しようとすると無限にスライドが膨らんでしまいどこを削るのかかなり悩んでいました。
RubyVM::AST
の説明は最後まで入れるべきかどうか悩んでいましたねえ…。今思うと入れなくてもよかったかなあ…。
本当は rensei-gem や kenma-gem の実装の話とかもしたかったんですが今回はあくあまでも『Ruby のマクロとは』という店にフォーカスを当てた内容にしました。
実装に関してはまたどこかで機会があれば話してみたいですねえ。
所感
はい、ということで RubyKaigi 初参加で初登壇する実績を解除しました。
今回はじめての参加だったので当日まで本当にどうなってしまうのかめちゃくちゃ不安だったんですがなんとか(登壇も時間どおり)無事に終わらせることができたのでそこが一番よかったです。
登壇自体は事前にかなり練習していたのでそれはやってよかったです。
内容的には結構ウケてたんですかね?あんまり実感がなくてよくわからないんですが終わった後に特に話を聞くこともないのでまあそんな感じだったのでしょう。
そういう意味では手応え的なのは全然なかったですねえ。
それはそれとして個人的には言いたかった事は全部言えたと思うので満足感はかなりあります。
マクロの機能自体も当初から想像していた形にほぼほぼできたと思うのでそういう意味だと達成感がありすぎて逆にやる気が虚無になっていますね…。
登壇でも言ってたんですが、ファイル単位でガッツリ書き換える、っていう運用はまだまだ先だろうけど局所的にマクロを使うのはそんなにハードルが高くないとは思っているのでそのあたりは実用的にしてみたいなあ、という気持ち。
あとマジで Scrapbox にログを残すようにする運用はよかったので今後も利用していきたい。
最後に運営の方々、マクロ実装・登壇の壁打ちに付き合ってくれた方々ありがとうございましたー。
反省
- スライドが大盛りになって時間がかなりカツカツになってしまった…
- かなり削ったけどもうちょい削れる事ができそうだったなあ…
- 結果的には時間ちょうどで終わらせる事ができたけどゆっくり喋れなくて翻訳の方に申し訳ない…
- Rensei が対応している Ruby のバージョンを表記しておくべきだった
- Ruby 2.6 ~ 3.1dev まで対応している
- スライドの作成がギリギリになっていた
- 練習するたびにスライドのミスを見つけてつらい
- 最後の1週間はずーっとスライドの練習に付き合ってもらっていた。めっちゃ感謝
- 実際の配信画面を見てなかったので実際にどう映っていたのかなんもわからねえ
RubyKaigi で気になった発表
- TypeProf for IDE: Enrich Dev-Experience without Annotations
- Ruby の TypeProf を利用して静的片付けのような開発体験を実現する話
- 静的片付けがほしいのではなくて開発体験がほしいわかる
- 静的片付けがほしいのではなくて開発体験をよくしたい〜〜〜
- 型シグネチャ表示がほしい…ほしい…
- VSCode 高機能なので Vim でもほしい
- 静的コードチェックは Rubocop 使っているけどもうちょい別の Lint を使いたい
- 言語的な意味でのエラーチェックを行ってほしい
- gem のコード開発は基本的に自身では呼ばれない事があるのでそのあたりどう TypeProf で解析するようになるのかは気になる
- テストコードを含めて TypeProf で解析するようにしたい
- RBS ファイルをシュッと記述する機能は Vim にもほしい
- こういうのは TypeProf 側で提供されている機能になるんかな
- なるべく VSCode に依存しないような機能として提供されてほしい
- プロジェクトごとに TypeProf の LSP を起動するのはどうするのがいいんじゃろうか
- The Art of Execution Control for Ruby's Debugger
- Parallel testing with Ractors: putting CPUs to work
- Demystifying DSLs for better analysis and understanding
- Parsing Ruby
- Ruby の歴史を追っていく話
- 知らない話がでてきて面白い
- 今までいろんなことをやってきたんだなあ
- parser-gem は 2.0 の時代につくられたのか
- include/prepend in refinements should be prohibited
- Refinements つらい話
- 話の中であったハマりポイントは実際自分も何度かハマっているので代替機能はほしいんだが〜〜〜
include / prepend
は多用しているので将来的に deprecated になるのは怖いがある程度しょうがなさそう- 代替機能があるならまあがんばって移行していくしかないなあ
- Beware the Dead End!!
end
がなかった時などのシンタックスエラーがどこでエラーになっているのかを検知する gem の話- 内容がコミカルで面白い
gem-dead_end
今すぐ使いたい!!
- Graphical Terminal User Interface of Ruby 3.1
- Dive into Encoding