Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Use Macro all the time ~ マクロを使いまくろ ~ 感想戦
Search
osyo
September 15, 2021
Programming
0
310
Use Macro all the time ~ マクロを使いまくろ ~ 感想戦
Fukuoka.rb #226 - RubyKaigi 感想戦
osyo
September 15, 2021
Tweet
Share
More Decks by osyo
See All by osyo
5分で話せる Ruby 3.1
osyo
0
170
AST を使って ActiveRecord の where の条件式をブロックで記述しよう
osyo
2
1.2k
Vim の開発環境自慢
osyo
5
3.1k
Use Macro all the time ~ マクロを使いまくろ ~ (English)
osyo
3
400
Use Macro all the time ~ マクロを使いまくろ ~ (日本語)
osyo
0
2.2k
月単位でイテレーションする
osyo
0
350
Ruby 3.0 で変わった private と attr_xxx
osyo
1
760
Ruby 2.0 から Ruby 3.0 を駆け足で振り返る
osyo
0
2k
12月25日にリリースされる Ruby 3.0 に備えよう!
osyo
1
3.3k
Other Decks in Programming
See All in Programming
TransformerからMCPまで(現代AIを理解するための羅針盤)
mickey_kubo
7
6.1k
contribution to astral-sh/uv
shunsock
0
590
KoogではじめるAIエージェント開発
hiroaki404
1
400
組織もソフトウェアも難しく考えない、もっとシンプルな考え方で設計する #phpconfuk
o0h
PRO
10
3.5k
Webサーバーサイド言語としてのRustについて
kouyuume
1
5.1k
開発組織の戦略的な役割と 設計スキル向上の効果
masuda220
PRO
10
2.1k
Migration to Signals, Resource API, and NgRx Signal Store
manfredsteyer
PRO
0
160
AsyncSequenceとAsyncStreamのプロポーザルを全部読む!!
s_shimotori
1
260
pnpm に provenance のダウングレード を検出する PR を出してみた
ryo_manba
1
220
Researchlyの開発で参考にしたデザイン
adsholoko
0
120
GitHub Copilotを使いこなせ!/mastering_github_copilot!
kotakageyama
2
860
Register is more than clipboard
satorunooshie
1
430
Featured
See All Featured
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
48
9.8k
GitHub's CSS Performance
jonrohan
1032
470k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Docker and Python
trallard
46
3.6k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
10
660
BBQ
matthewcrist
89
9.9k
Code Review Best Practice
trishagee
72
19k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.2k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.6k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
660
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
Building Flexible Design Systems
yeseniaperezcruz
329
39k
Transcript
Use Macro all the time ~ マクロを使いまくろ ~ 感想戦 Fukuoka.rb
#226 - RubyKaigi 感想戦
自己紹介 osyo @pink_bangbi: https://twitter.com/pink_bangbi osyo-manga: https://github.com/osyo-manga Secret Garden(Instrumental): http://secret-garden.hatenablog.com Rails
エンジニア 好きな Ruby の機能は Refinements RubyKaigi は初参加 Use Macro all the time ~ マクロを使いまくろ ~ https://speakerdeck.com/osyo/use-macro-all-the-time-makurowoshi-imakuro-ri-ben-yu
RubyKaigi の感想戦と補足
元々のモチベーション
元々のモチベーション 元々はブロックから Ruby のコードを取得したい要求があった 最初は iseq から位置情報を取得してファイルから読み込んできてた ただ、これだとパフォーマンス的な懸念点があった
元々のモチベーション 元々はブロックから Ruby のコードを取得したい要求があった 最初は iseq から位置情報を取得してファイルから読み込んできてた ただ、これだとパフォーマンス的な懸念点があった RubyVM::AST だとブロックから
AST を取得できる実装を書いた ` `
元々のモチベーション 元々はブロックから Ruby のコードを取得したい要求があった 最初は iseq から位置情報を取得してファイルから読み込んできてた ただ、これだとパフォーマンス的な懸念点があった RubyVM::AST だとブロックから
AST を取得できる実装を書いた これを利用するとマクロができるのでは…? この構想自体は1年ぐらい前からあった ` `
元々のモチベーション 元々はブロックから Ruby のコードを取得したい要求があった 最初は iseq から位置情報を取得してファイルから読み込んできてた ただ、これだとパフォーマンス的な懸念点があった RubyVM::AST だとブロックから
AST を取得できる実装を書いた これを利用するとマクロができるのでは…? この構想自体は1年ぐらい前からあった 知り合いに釣られて RubyKaigi に参加するモチベーションが湧いたので今回マクロを実 装した RubyKaigi 駆動開発 ` `
Rensei の作業期間・苦労話
Rensei の作業期間・苦労話 作業期間は 3〜4ヶ月 実際作業してたのは去年の今頃
Rensei の作業期間・苦労話 作業期間は 3〜4ヶ月 実際作業してたのは去年の今頃 Rensei は作業量とバグ修正が無限にあってつらかった 100種類以上の AST を1つずつ実装していた
Rensei の作業期間・苦労話 作業期間は 3〜4ヶ月 実際作業してたのは去年の今頃 Rensei は作業量とバグ修正が無限にあってつらかった 100種類以上の AST を1つずつ実装していた
1 proc { |z, (a, b), c = 1, d = 2, *, (e, f, g), (h, i), j, k, l:, **kwd| foo }
Rensei の作業期間・苦労話 作業期間は 3〜4ヶ月 実際作業してたのは去年の今頃 Rensei は作業量とバグ修正が無限にあってつらかった 100種類以上の AST を1つずつ実装していた
1 proc { |z, (a, b), c = 1, d = 2, *, (e, f, g), (h, i), j, k, l:, **kwd| foo } 実装した後も ActiveRecord のソースファイルを1つずつ食わせていくとバグが無限に発 生して1つずつ直していった エッジケースの問題が大量にあった…
Rensei の作業期間・苦労話 作業期間は 3〜4ヶ月 実際作業してたのは去年の今頃 Rensei は作業量とバグ修正が無限にあってつらかった 100種類以上の AST を1つずつ実装していた
1 proc { |z, (a, b), c = 1, d = 2, *, (e, f, g), (h, i), j, k, l:, **kwd| foo } 実装した後も ActiveRecord のソースファイルを1つずつ食わせていくとバグが無限に発 生して1つずつ直していった エッジケースの問題が大量にあった… テストはかなり力を入れて書いた AST から復元したコードが元の AST と同じかどうかでテストしてる https://github.com/osyo-manga/gem- rensei/blob/82aaf139935a8b4eb7fd1029cdc5fc86e4fb692a/spec/unparser_spec.rb
Rensei の実装に関して 当日は時間がなかったので割愛したが以下のような感じで実装してる 1 def unparse(node) 2 case node&.type 3
when :SCOPE 4 unparse(node.children.last) 5 when :LIT 6 "#{node.children.last}" 7 when :STR 8 "#{node.children.last}" 9 when :CALL 10 recv, meth = node.children 11 "#{unparse(recv)}.#{meth}" 12 when :OPCALL 13 left, op, args = node.children 14 "(#{unparse(left)} #{op} #{unparse(args.children[0])})" 15 end 16 end 17 node = RubyVM::AbstractSyntaxTree.parse("1 + 2 * '42'.to_i") 18 pp unparse(node) # => "(1 + (2 * 42.to_i))"
Kenma の作業期間・苦労話
Kenma の作業期間・苦労話 作業期間 1〜2ヶ月 今回の RubyKaigi に向けて実装した
Kenma の作業期間・苦労話 作業期間 1〜2ヶ月 今回の RubyKaigi に向けて実装した 実装自体はそこまで難しくなかったが、とにかく書き心地を重視して API を設計した
何回も実装を書き直しながら方向性が確定してから gem をつくりはじめた いろんな人に壁打ちしながらつくってた感謝
Kenma の作業期間・苦労話 作業期間 1〜2ヶ月 今回の RubyKaigi に向けて実装した 実装自体はそこまで難しくなかったが、とにかく書き心地を重視して API を設計した
何回も実装を書き直しながら方向性が確定してから gem をつくりはじめた いろんな人に壁打ちしながらつくってた感謝 マクロのデザインに関してはかなり Rust を意識した マクロ関数に ! 付けたりとか ` `
Kenma の作業期間・苦労話 作業期間 1〜2ヶ月 今回の RubyKaigi に向けて実装した 実装自体はそこまで難しくなかったが、とにかく書き心地を重視して API を設計した
何回も実装を書き直しながら方向性が確定してから gem をつくりはじめた いろんな人に壁打ちしながらつくってた感謝 マクロのデザインに関してはかなり Rust を意識した マクロ関数に ! 付けたりとか 結果的に定義方法を種類分けしつつ、抽象的なマクロの定義ができて個人的には満足 パターンマクロがかなり抽象的にかけてよい ` `
RubyVM::AST の互換性 ` `
RubyVM::AST の互換性 Ruby のバージョン間で互換性が保証されてない つらかったのは Ruby 2.6 -> 2.7 で
:ARRAY -> :LIST にタイプ名が変わったところ ` ` ` `
RubyVM::AST の互換性 Ruby のバージョン間で互換性が保証されてない つらかったのは Ruby 2.6 -> 2.7 で
:ARRAY -> :LIST にタイプ名が変わったところ 1 pp RUBY_VERSION # => "2.6.8" 2 pp RubyVM::AbstractSyntaxTree.parse("[1, 2, 3]").children.last 3 # => (ARRAY@1:0-1:9 (LIT@1:1-1:2 1) (LIT@1:4-1:5 2) (LIT@1:7-1:8 3) nil) ` ` ` `
RubyVM::AST の互換性 Ruby のバージョン間で互換性が保証されてない つらかったのは Ruby 2.6 -> 2.7 で
:ARRAY -> :LIST にタイプ名が変わったところ 1 pp RUBY_VERSION # => "2.6.8" 2 pp RubyVM::AbstractSyntaxTree.parse("[1, 2, 3]").children.last 3 # => (ARRAY@1:0-1:9 (LIT@1:1-1:2 1) (LIT@1:4-1:5 2) (LIT@1:7-1:8 3) nil) 1 pp RUBY_VERSION # => "2.7.4" 2 pp RubyVM::AbstractSyntaxTree.parse("[1, 2, 3]").children.last 3 # => (LIST@1:0-1:9 (LIT@1:1-1:2 1) (LIT@1:4-1:5 2) (LIT@1:7-1:8 3) nil) ` ` ` `
RubyVM::AST の互換性 Ruby のバージョン間で互換性が保証されてない つらかったのは Ruby 2.6 -> 2.7 で
:ARRAY -> :LIST にタイプ名が変わったところ 1 pp RUBY_VERSION # => "2.6.8" 2 pp RubyVM::AbstractSyntaxTree.parse("[1, 2, 3]").children.last 3 # => (ARRAY@1:0-1:9 (LIT@1:1-1:2 1) (LIT@1:4-1:5 2) (LIT@1:7-1:8 3) nil) 1 pp RUBY_VERSION # => "2.7.4" 2 pp RubyVM::AbstractSyntaxTree.parse("[1, 2, 3]").children.last 3 # => (LIST@1:0-1:9 (LIT@1:1-1:2 1) (LIT@1:4-1:5 2) (LIT@1:7-1:8 3) nil) どっちかって言うと細かいところでバグってるところのほうがつらかった Ruby の構文としては意味が異なるのに AST としては同じになるとか… proc { |a| } と proc { |a,| } が同じ AST になる とか https://bugs.ruby-lang.org/issues/17015 ` ` ` ` ` ` ` `
Rensei の AST 間のバージョン対応
Rensei の AST 間のバージョン対応 Rensei は現時点で存在してるバージョンはすべて対応している Ruby 2.6 ~ 3.1-dev
Rensei の AST 間のバージョン対応 Rensei は現時点で存在してるバージョンはすべて対応している Ruby 2.6 ~ 3.1-dev
バージョン間で細かい非互換はあるけど基本的には新しい構文を追加するような実装に なっている
Rensei の AST 間のバージョン対応 Rensei は現時点で存在してるバージョンはすべて対応している Ruby 2.6 ~ 3.1-dev
バージョン間で細かい非互換はあるけど基本的には新しい構文を追加するような実装に なっている 詳しくは実装を見てね!! https://github.com/osyo-manga/gem- rensei/blob/82aaf139935a8b4eb7fd1029cdc5fc86e4fb692a/lib/rensei/unparser.rb
マクロの今後
マクロの今後 エンドユーザがマクロを使うと言うよりかは間接的にマクロが利用できるようにしたい ファイル全体ではなくて局所的にマクロを利用したい ユーザが定義したブロックでのみ使用するなど
マクロの今後 エンドユーザがマクロを使うと言うよりかは間接的にマクロが利用できるようにしたい ファイル全体ではなくて局所的にマクロを利用したい ユーザが定義したブロックでのみ使用するなど 例えばこんな感じ
マクロの今後 エンドユーザがマクロを使うと言うよりかは間接的にマクロが利用できるようにしたい ファイル全体ではなくて局所的にマクロを利用したい ユーザが定義したブロックでのみ使用するなど 例えばこんな感じ 1 User.where { :age <
20 }
マクロの今後 エンドユーザがマクロを使うと言うよりかは間接的にマクロが利用できるようにしたい ファイル全体ではなくて局所的にマクロを利用したい ユーザが定義したブロックでのみ使用するなど 例えばこんな感じ 1 User.where { :age <
20 } 1 User.where("age < 20")
マクロの今後 エンドユーザがマクロを使うと言うよりかは間接的にマクロが利用できるようにしたい ファイル全体ではなくて局所的にマクロを利用したい ユーザが定義したブロックでのみ使用するなど 例えばこんな感じ 1 User.where { :age <
20 } 1 User.where("age < 20") マクロと言っているがどちらかというと AST というデータに対して今後フォーカスを当 てて行くような未来が見えてきた気がする マクロでないにしても今後 AST を使って便利ななにかができてきそう
おまけ
おまけ Ruby 3.1 で RubyVM::AST::Node から元のコードが取得できるようになる(かも) ` `
おまけ Ruby 3.1 で RubyVM::AST::Node から元のコードが取得できるようになる(かも) 1 src = <<~EOS
2 if hoge 3 puts hoge + foo 4 end 5 EOS 6 7 # keep_script_lines を true にすると 8 node = RubyVM::AbstractSyntaxTree.parse(src, keep_script_lines: true) 9 10 # #source メソッドでコードを取得できるようになる 11 puts node.source 12 # => if hoge 13 # puts hoge + foo 14 # end ` `