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
270
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
130
AST を使って ActiveRecord の where の条件式をブロックで記述しよう
osyo
2
1.1k
Vim の開発環境自慢
osyo
5
3k
Use Macro all the time ~ マクロを使いまくろ ~ (English)
osyo
3
360
Use Macro all the time ~ マクロを使いまくろ ~ (日本語)
osyo
0
2.1k
月単位でイテレーションする
osyo
0
290
Ruby 3.0 で変わった private と attr_xxx
osyo
1
680
Ruby 2.0 から Ruby 3.0 を駆け足で振り返る
osyo
0
1.7k
12月25日にリリースされる Ruby 3.0 に備えよう!
osyo
1
3k
Other Decks in Programming
See All in Programming
Scalaから始めるOpenFeature入門 / Scalaわいわい勉強会 #4
arthur1
1
340
선언형 UI에서의 상태관리
l2hyunwoo
0
180
nekko cloudにおけるProxmox VE利用事例
irumaru
3
440
フロントエンドのディレクトリ構成どうしてる? Feature-Sliced Design 導入体験談
osakatechlab
8
4.1k
ブラウザ単体でmp4書き出すまで - muddy-web - 2024-12
yue4u
3
480
php-conference-japan-2024
tasuku43
0
320
たのしいparse.y
ydah
3
120
どうして手を動かすよりもチーム内のコードレビューを優先するべきなのか
okashoi
3
170
htmxって知っていますか?次世代のHTML
hiro_ghap1
0
340
testcontainers のススメ
sgash708
1
120
Fibonacci Function Gallery - Part 1
philipschwarz
PRO
0
220
range over funcの使い道と非同期N+1リゾルバーの夢 / about a range over func
mackee
0
110
Featured
See All Featured
Speed Design
sergeychernyshev
25
670
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
44
6.9k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
507
140k
Testing 201, or: Great Expectations
jmmastey
40
7.1k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
28
9.1k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
111
49k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
26
1.5k
Java REST API Framework Comparison - PWX 2021
mraible
28
8.3k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
28
4.4k
Code Review Best Practice
trishagee
65
17k
The Invisible Side of Design
smashingmag
298
50k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
17
2.3k
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 ` `