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
300
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
3k
Use Macro all the time ~ マクロを使いまくろ ~ (English)
osyo
3
390
Use Macro all the time ~ マクロを使いまくろ ~ (日本語)
osyo
0
2.2k
月単位でイテレーションする
osyo
0
330
Ruby 3.0 で変わった private と attr_xxx
osyo
1
740
Ruby 2.0 から Ruby 3.0 を駆け足で振り返る
osyo
0
1.9k
12月25日にリリースされる Ruby 3.0 に備えよう!
osyo
1
3.2k
Other Decks in Programming
See All in Programming
ペアプロ × 生成AI 現場での実践と課題について / generative-ai-in-pair-programming
codmoninc
2
19k
Claude Code + Container Use と Cursor で作る ローカル並列開発環境のススメ / ccc local dev
kaelaela
10
5.9k
チームで開発し事業を加速するための"良い"設計の考え方 @ サポーターズCoLab 2025-07-08
agatan
1
440
MCPを使ってイベントソーシングのAIコーディングを効率化する / Streamlining Event Sourcing AI Coding with MCP
tomohisa
0
100
The Modern View Layer Rails Deserves: A Vision For 2025 And Beyond @ RailsConf 2025, Philadelphia, PA
marcoroth
2
450
プロダクト志向ってなんなんだろうね
righttouch
PRO
0
190
AI駆動のマルチエージェントによる業務フロー自動化の設計と実践
h_okkah
0
170
Blazing Fast UI Development with Compose Hot Reload (droidcon New York 2025)
zsmb
1
300
Porting a visionOS App to Android XR
akkeylab
0
560
VS Code Update for GitHub Copilot
74th
2
660
テストから始めるAgentic Coding 〜Claude Codeと共に行うTDD〜 / Agentic Coding starts with testing
rkaga
13
4.8k
「Cursor/Devin全社導入の理想と現実」のその後
saitoryc
0
830
Featured
See All Featured
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
29
9.6k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
18
970
Into the Great Unknown - MozCon
thekraken
40
1.9k
Navigating Team Friction
lara
187
15k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
161
15k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
181
54k
GraphQLの誤解/rethinking-graphql
sonatard
71
11k
For a Future-Friendly Web
brad_frost
179
9.8k
Bootstrapping a Software Product
garrettdimon
PRO
307
110k
Facilitating Awesome Meetings
lara
54
6.4k
Building a Modern Day E-commerce SEO Strategy
aleyda
42
7.4k
Rails Girls Zürich Keynote
gr2m
95
14k
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 ` `