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
520
Do Ruby::Box dream of Modular Monolith?
joker1007
1
1.8k
ReproでのicebergのStreaming Writeの検証と実運用にむけた取り組み
joker1007
0
820
マイクロサービスへの5年間 ぶっちゃけ何をしてどうなったか
joker1007
23
11k
Quarkusで作るInteractive Stream Application
joker1007
0
330
今改めて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
Jetpack Compose Mechanisms
skydoves
2
720
UnityでSystem.Net.WebSocketsなWebSocketサーバが動かないのでUnity Monoのコードを覗いてみた / about implementing websocket server with unity mono
drumath2237
1
590
Atomic Design, Enforced: Scaling Mobile Design Systems (next.app devCon / droidCon Berlin 2026)
steliosf
PRO
0
170
全ての永続トークンを、生まれる前に消し去りたい!
sylph01
1
280
Androidだけじゃない、DroidKaigiで広がった私の技術スタック
akkeylab
0
130
[Rails World 2026] Durable orchestration on Rails: from continuation to workflow
palkan
1
730
外から家のPCの電源入れたい!をPHPで解決する
kawashimo0
1
130
Ghostty + Neovimで作る 透明でカッコ良い開発環境
j341nono
0
170
KiroのSpecで「五目並べ」を作ってみる
satoshi256kbyte
1
370
機械に任せるテスト、人が見るテスト ⽣成AIで引き直した、運⽤保守フェーズの線引き
dske104
0
180
AWS CDKのカスタムリソースでContinuum(旧Security Agent)を実装した話 | Implementing Continuum (formerly Security Agent) via AWS CDK Custom Resource
akihisaikeda
2
150
コードレビューのボトルネックを"する側"と"される側"の両面から解消する
yub0n
2
1.6k
Featured
See All Featured
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2.2k
Documentation Writing (for coders)
carmenintech
77
5.6k
Information Architects: The Missing Link in Design Systems
soysaucechin
1
1.2k
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
470
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
33
5.2k
Making Projects Easy
brettharned
120
6.8k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.4k
The World Runs on Bad Software
bkeepers
PRO
72
12k
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
68
59k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
53k
Site-Speed That Sticks
csswizardry
13
1.6k
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.6k
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 より深く楽しみ、より良いコードに繋げよう