Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
†Ruby黒魔術経典†
Search
Tomohiro Hashidate
June 08, 2019
Programming
6.8k
15
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
†Ruby黒魔術経典†
名古屋Ruby会議04 発表資料
Tomohiro Hashidate
June 08, 2019
More Decks by Tomohiro Hashidate
See All by Tomohiro Hashidate
Ruby::Boxでできること、Refinementsでできること
joker1007
3
540
Do Ruby::Box dream of Modular Monolith?
joker1007
1
1.9k
ReproでのicebergのStreaming Writeの検証と実運用にむけた取り組み
joker1007
0
870
マイクロサービスへの5年間 ぶっちゃけ何をしてどうなったか
joker1007
23
11k
Quarkusで作るInteractive Stream Application
joker1007
0
340
今改めてServiceクラスについて考える 〜あるRails開発者の10年〜
joker1007
25
29k
rubygem開発で鍛える設計力
joker1007
5
1.5k
実践Kafka Streams 〜イベント駆動型アーキテクチャを添えて〜
joker1007
3
1.5k
本番のトラフィック量でHudiを検証して見えてきた課題
joker1007
2
1.4k
Other Decks in Programming
See All in Programming
AIで開発が速くなった先で、開発チームは何を目指すか
shihochan
1
2k
Spec-driven Development with AI
simas
PRO
0
2.2k
Railsのためのパスキー実践入門 〜マルチテナントSaaSでの意思決定〜
utakaha
4
3.1k
クラウドエージェントは、 何がそんなに便利なのか / what makes cloud agents so useful
rkaga
5
760
ChromeでローカルLLM
ryu1013
0
190
AI時代のIaC入門 〜なぜインフラをコードで管理したいのか?〜 / Introduction to IaC in the AI Era
akihisaikeda
6
1.4k
Long Living Tokens, Die, Die, Die! (or: The One Ring is Banned in Modern)
sylph01
0
410
느린 네트워크와 저사양 디바이스 사용자를 위한 웹뷰 로딩 시간 개선기
kmkim
1
190
Performance Optimization With LLMs
xleitix
0
240
3回つくってわかった、 定期実行ジョブ基盤の本質情報
takai
4
3.7k
自作Discord音声botをLambda MicroVMsに移行した話 / Migrating My Discord Voice Bot to Lambda MicroVMs
akihisaikeda
1
290
Kotlinize Is Not Just Converting to Kotlin
chigichan24
1
220
Featured
See All Featured
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.7k
Gemini Prompt Engineering: Practical Techniques for Tangible AI Outcomes
mfonobong
2
620
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.7k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.6k
Speed Design
sergeychernyshev
33
2.2k
Bash Introduction
62gerente
615
220k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
360
31k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.7k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
20k
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
6
1.3k
First, design no harm
axbom
PRO
2
1.4k
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
590
Transcript
†Ruby 黒魔術経典† @joker1007 (Repro inc. CTO) 名古屋Ruby 会議04
self.inspect @joker1007 Repro inc. CTO Data Engineering, Architect Ruby で悪事を働く⼈と⾒做されている
We provide a web service as ... Analytics of Mobile
Apps, Web Apps. Marketing Automation. We're hiring!!
https://youtu.be/1mauqP9zWbM?t=31
⼤いなる⼒には ⼤いなる責任が 伴う
メタプログラミングや魔術的な挙動をする コードは強⼒だが 侵してはならないこともある
今⽇の議題 以下の内容について話す。 黒魔術において守るべきルール 実際に魔術を編み出すために使えるパーツ 考え⽅の具体例
Part1 守りの黒魔術
守りの黒魔術 その1 組込みクラスを壊さない 特に require しただけで挙動を変えない 上書きさせたい場合は、必ずユーザーに指定させる 組込みのクラス・メソッドは全てのRuby ユーザーが期待している挙動が ある。(
当たり前の話) 暗黙的に弄って挙動を変えたら、何が起こるのか分からなくなる。
守りの黒魔術 その2 スタックが追える様にすること eval を使う場合に定義場所のロケーションを適切に設定する。 でないと例外が発⽣した時にどこで定義されたコードなのか分からない。 実はRuby の例外のバックトレースは⾃分で上書きできるので、ノイズに なりそうな情報を隠すこともできる。
守りの黒魔術 その3 パフォーマンスを意識すること eval やbinding は負荷が⾼い。 呼び出し回数を少なくするために以下の様な⽅法が使える。 クラスレベルでソースコードをキャッシュする クラス定義時や初回実⾏時のみ動作する様にする メソッド定義にだけ利⽤する
初回実⾏時にメソッドを上書きする
守りの黒魔術 その4 TracePoint の利⽤は明⽰的に そして、絶対にensure でdisable すること。 途中で例外が発⽣するとtrace が有効のままになる。 trace
が有効のままになるとマジで何が起きるか分からない。 フックが暴⾛してstack level too deep になるのはまだ良い⽅。
Part2 黒魔術に使えるAPI の探し⽅
基本はリファレンスをひたすら読むこと それだけだと雑過ぎるので、もうちょい解説する。
るりまのここを読むべし BasicObject Object Module/Class Method Proc Kernel (ObjectSpace)
⼀回読んでも忘れるから、 とりあえずこの辺りを読み返す癖を付けておく。 ちなみに、 RubyVM::AbstractSyntaxTree はまだるりまが無いです。 ( プルリクチャンス)
使えそうな機能の例 評価コンテキスト操作 eval 系 トリガー/ フック メソッドフック, TracePoint, included, inherited,
method_missing, trace_var, trap, finalizer ⼤域脱出 throw/catch, Fiber
使えそうな機能の例 ( 続き) オブジェクト参照 _variable_get 系, const_get, ObjectSpace 変数/ 定数操作
_variable_set 系, const_set メタデータ取得 Method やProc から取れる情報 メソッドの動的定義 define_method, module_eval
メタプログラミングパターン メソッド定義 DSL 動的解析 静的解析 ⾃動的/ 暗黙的処理の追加 ⾔語拡張 ↓ に向かう程魔術度が増す
Part3 考え⽅の具体例 暗黙のブロック引数 it を作ってみよう see. https://bugs.ruby-lang.org/issues/15897
proc の中で暗黙の内に it でパラメータを参照できるとは、 Ruby の動作に置き換えるとどういうことかを考えてみる。 評価コンテキスト内で it というローカル変数に値が⼊っている proc
のself に it というメソッドが定義されていて、パラメータを取 得できる proc の外側で it が定義されている。 ローカル変数 or 引数 これらのどれかが実現できれば良さそう。
ローカル変数追加⽅式について検討 local_variable_set が使えそう local_variable_set は変数書き換えは簡単だが、新規に追加するのは難 しい binding が毎回新しく⽣成されるため binding を固定してeval
しなければならない そもそもブロック呼び出しに実際に使われている値をどうやって事前 に取得する? なんか無理っぽい
メソッド追加⽅式について検討 評価コンテキストにおけるself は取得できる Proc#binding やTracePoint で可能 単純にメソッドを定義するとあるクラスのインスタンス全てが影響す る 特異メソッドとして定義すれば可能かも しかしスコープを抜けた後も参照できてしまう
Refinements は使えないか ブロックの定義が別の場所なのでeval が必要 ローカル変数⽅式と同様の問題がある
外側でit を定義する⽅法について検討 新しいproc でラップして追加できる ブロックに渡される引数を事前に知る必要が無い やはりeval する必要がある
結論: 恐らくeval が必須 そしてproc でwrap ⽅式が現実的 eval するためにはソースコード断⽚が必要
ブロックのソースコードを取る⽅法 RubyVM::AST.of or parser gem で位置を特定し読む ( またお前か)
特定のメソッドを対象にPoC を書く module Ext def map(*args, &block) source = File.readlines(block.source_location[0])
proc_binding = block.binding ast = RubyVM::AbstractSyntaxTree.of(block) args_tbl = ast.children[0] block_node = ast.children[2] if args_tbl.empty? extracted = extract_source( source, block_node.first_lineno, block_node.first_column, block_node.last_lineno, block_node.last_column) new_block = proc_binding.eval("proc { |it| #{extracted} }") super(*args, &new_block) else super(*args, &block) end end end Array.prepend(Ext) n = 3 [1, 2, 3].map { p it + n } # => [4, 5, 6]
出来た! 後はgem にするだけ
こんな感じで、⾃分の場合はゴールから逆算して考える。 やりたい事が出来るとはRuby においてオブジェクトの状態や変数のスコ ープ、メソッドの定義がどうなっていればいいかを想像し、そこに⾄る⽅ 法を逆向きに辿って実現可能な⽅法を考える。
ちなみに、実はこれ RubyKaigi2019 で話したものと同じ パターンを使っている
最後に 黒魔術を使うためにはRuby の挙動や各オブジェクトが何なのかというこ とを詳しく知る必要がある。 魔術的な挙動を起こす⽅法を知ることは、安全なコードの書き⽅を知るこ とにも繋がる。 いざという時の選択肢も増える。 Ruby より深く楽しみ、より良いコードに繋げよう