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
160
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
730
Ruby 2.0 から Ruby 3.0 を駆け足で振り返る
osyo
0
1.8k
12月25日にリリースされる Ruby 3.0 に備えよう!
osyo
1
3.1k
Other Decks in Programming
See All in Programming
OpenNext + Hono on Cloudflare でイマドキWeb開発スタックを実現する
rokuosan
0
110
Duke on CRaC with Jakarta EE
ivargrimstad
1
690
REST API設計の実践 – ベストプラクティスとその落とし穴
kentaroutakeda
2
310
型付け力を強化するための Hoogle のすゝめ / Boosting Your Type Mastery with Hoogle
guvalif
1
230
AIにコードを生成するコードを作らせて、再現性を担保しよう! / Let AI generate code to ensure reproducibility
yamachu
7
6k
當開發遇上包裝:AI 如何讓產品從想法變成商品
clonn
0
2.4k
#QiitaBash TDDでAIに設計イメージを伝える
ryosukedtomita
2
1.6k
Interface vs Types ~型推論が過多推論~
hirokiomote
1
230
少数精鋭エンジニアがフルスタック力を磨く理由 -そしてAI時代へ-
rebase_engineering
0
120
技術的負債と戦略的に戦わざるを得ない場合のオブザーバビリティ活用術 / Leveraging Observability When Strategically Dealing with Technical Debt
yoshiyoshifujii
0
160
CQRS/ESのクラスとシステムフロー ~ RailsでフルスクラッチでCQRSESを組んで みたことから得た学び~
suzukimar
0
190
TypeScript エンジニアが Android 開発の世界に飛び込んだ話
yuisakamoto
6
930
Featured
See All Featured
The MySQL Ecosystem @ GitHub 2015
samlambert
251
12k
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.5k
The World Runs on Bad Software
bkeepers
PRO
68
11k
A better future with KSS
kneath
239
17k
Rails Girls Zürich Keynote
gr2m
94
13k
Scaling GitHub
holman
459
140k
YesSQL, Process and Tooling at Scale
rocio
172
14k
Git: the NoSQL Database
bkeepers
PRO
430
65k
Producing Creativity
orderedlist
PRO
346
40k
A designer walks into a library…
pauljervisheath
205
24k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
331
21k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
52
2.8k
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 ` `