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
480
Do Ruby::Box dream of Modular Monolith?
joker1007
1
1.7k
ReproでのicebergのStreaming Writeの検証と実運用にむけた取り組み
joker1007
0
810
マイクロサービスへの5年間 ぶっちゃけ何をしてどうなったか
joker1007
23
11k
Quarkusで作るInteractive Stream Application
joker1007
0
320
今改めて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
Are APIs Still Relevant in the AI Era?
soyuka
0
300
Security issues being discussed on Web Platforms
petamoriken
0
1.2k
Go × SIMDで高速化するベクトル検索 ~ルーフラインモデルでSIMDが効く境界を探れ! ~
po3rin
1
3.1k
技術的負債の返済は、AI時代の複利で効く投資 — 経営としての意思決定とその遂行
curekoshimizu
0
1.8k
Building an Out-of-Order CPU
latte72
1
800
AGENTS.md Is Not Enough:Build Skills, Don't Download Them
lx_t
0
130
スマート反転とウェブアクセシビリティ
camiha
0
210
マイコン向けの軽量Ruby「PicoRuby」で各種デバイスを制御するネイティブアプリの実現手法
bash0c7
0
440
市販E-Readerを乗っ取れ 〜Embedded Swiftで電子ペーパーガジェットを制御する〜
trickart
0
210
WebMCP Challenge に星空観察アプリで参加した話
okajun35
0
190
AWS Step Functions 大規模並列の壁を越える / jaws-sonic-2026-niigata-step-functions
kasacchiful
PRO
1
520
Java 27新機能 / Java 27 new features
kishida
2
170
Featured
See All Featured
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
730
Build your cross-platform service in a week with App Engine
jlugia
234
19k
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
530
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
18k
How to Think Like a Performance Engineer
csswizardry
28
2.8k
Pawsitive SEO: Lessons from My Dog (and Many Mistakes) on Thriving as a Consultant in the Age of AI
davidcarrasco
0
250
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
2
2.9k
Java REST API Framework Comparison - PWX 2021
mraible
34
9.7k
Documentation Writing (for coders)
carmenintech
77
5.5k
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.6k
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.8k
Building the Perfect Custom Keyboard
takai
2
880
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 より深く楽しみ、より良いコードに繋げよう