Slide 1

Slide 1 text

シン・リファインメンツ 劇場版 @joker1007

Slide 2

Slide 2 text

私はRefinements が好きだ

Slide 3

Slide 3 text

しかし理想的ではない 何とかしてproc 限定でrefine したい r e f i n i n g ( E x t ) d o " j o k e r 1 0 0 7 " . h e l l o # = > " H e l l o j o k e r 1 0 0 7 " e n d

Slide 4

Slide 4 text

よろしい ならばeval だ

Slide 5

Slide 5 text

ただ単純にeval するだけだと m o d u l e K e r n e l d e f r e f i n i n g ( m o d ) T O P L E V E L _ B I N D I N G . e v a l ( < < ~ R U B Y ) u s i n g # { m o d . t o _ s } " j o k e r 1 0 0 7 " . h e l l o R U B Y e n d e n d

Slide 6

Slide 6 text

決め打ちしかできねえ 何とかしてproc 渡したい ソースコードが欲しい 大丈夫!parser & unparser がある!

Slide 7

Slide 7 text

parser, unparser を使ってproc からsource を取る proc_to_ast というgem を昔作った r e q u i r e ' p r o c _ t o _ a s t ' d e f r e f i n i n g ( m o d , & b l o c k ) m a t c h e d = b l o c k . t o _ s o u r c e . m a t c h ( / d o ( . * ) e n d / m ) p r o c _ s o u r c e = " p r o c # { m a t c h e d [ 0 ] } " T O P L E V E L _ B I N D I N G . e v a l ( < < ~ R U B Y ) u s i n g # { m o d . t o _ s } p r = # { p r o c _ s o u r c e } p r . c a l l R U B Y e n d

Slide 8

Slide 8 text

これでいける? r e f i n i n g ( E x t ) d o " j o k e r 1 0 0 7 " . h e l l o e n d m o d u l e D u m m y ; e n d r e f i n i n g ( D u m m y ) d o " t a g o m o r i s " . h e l l o e n d

Slide 9

Slide 9 text

実は駄目 r e f i n i n g ( E x t ) d o " j o k e r 1 0 0 7 " . h e l l o e n d m o d u l e D u m m y ; e n d r e f i n i n g ( D u m m y ) d o " t a g o m o r i s " . h e l l o # = > 呼べてしまう! e n d

Slide 10

Slide 10 text

TOPLEVEL_BINDING は常に同じbinding 一回eval でusing したら効果が残る 大丈夫!Class.new がある!

Slide 11

Slide 11 text

d e f r e f i n i n g ( m o d , & b l o c k ) p r o c _ s o u r c e = b l o c k . t o _ s o u r c e . m a t c h ( / d o ( . * ) e n d / m ) . y i e l d _ s e l f { | m | m [ 0 ] } c = T O P L E V E L _ B I N D I N G . e v a l ( < < ~ R U B Y ) C l a s s . n e w d o u s i n g # { m o d . t o _ s } d e f s e l f . p r o c e s s p r = # { w r a p e d _ s o u r c e } p r . c a l l e n d e n d R U B Y c . p r o c e s s e n d

Slide 12

Slide 12 text

r e f i n i n g ( E x t ) d o " j o k e r 1 0 0 7 " . h e l l o e n d m o d u l e D u m m y ; e n d r e f i n i n g ( D u m m y ) d o " t a g o m o r i s " . h e l l o # = > N o M e t h o d E r r o r e n d

Slide 13

Slide 13 text

やったか?! => やってない

Slide 14

Slide 14 text

評価コンテキストの壁 c l a s s F o o d e f i n i t i a l i z e @ n a m e = " j o k e r 1 0 0 7 " e n d d e f h e l l o r e f i n i n g ( E x t ) d o @ n a m e . h e l l o e n d e n d e n d F o o . n e w . h e l l o # = > d e a d

Slide 15

Slide 15 text

まずは落ち着け 落ち着いてobject を渡せばいい instance_exec だ

Slide 16

Slide 16 text

d e f r e f i n i n g ( o b j , m o d , & b l o c k ) p r o c _ s o u r c e = b l o c k . t o _ s o u r c e . m a t c h ( / d o ( . * ) e n d / m ) . y i e l d _ s e l f { | m | " p r o c # { m [ 0 ] } " } c = T O P L E V E L _ B I N D I N G . e v a l ( < < ~ R U B Y ) C l a s s . n e w d o u s i n g # { m o d . t o _ s } d e f s e l f . p r o c e s s ( o b j ) # = > 引数を増やす p r = # { p r o c _ s o u r c e } o b j . i n s t a n c e _ e x e c ( & p r ) # = > コンテキストゲット e n d e n d R U B Y c . p r o c e s s ( o b j ) # = > 引数で渡す e n d

Slide 17

Slide 17 text

c l a s s F o o d e f i n i t i a l i z e @ n a m e = " j o k e r 1 0 0 7 " e n d d e f h e l l o r e f i n i n g ( E x t , s e l f ) d o @ n a m e . h e l l o e n d e n d e n d F o o . n e w . h e l l o # = > Y a y

Slide 18

Slide 18 text

いけるやん!

Slide 19

Slide 19 text

ローカル変数がッ! proc はクロージャ! c l a s s F o o d e f h e l l o ( n a m e ) r e f i n i n g ( E x t , s e l f ) d o n a m e . h e l l o e n d e n d e n d F o o . n e w . h e l l o ( " j o k e r 1 0 0 7 " ) # = > D e a d a g a i n ! !

Slide 20

Slide 20 text

Binding 「俺様の出番の様だな」

Slide 21

Slide 21 text

d e f r e f i n i n g ( b , m o d , & b l o c k ) p r o c _ s o u r c e = b l o c k . t o _ s o u r c e . m a t c h ( / d o ( . * ) e n d / m ) . y i e l d _ s e l f { | m | " p r o c # { m [ 0 ] } " } c = T O P L E V E L _ B I N D I N G . e v a l ( < < ~ R U B Y ) C l a s s . n e w d o u s i n g # { m o d . t o _ s } d e f s e l f . p r o c e s s ( b ) # { b . l o c a l _ v a r i a b l e s . m a p d o | v | " # { v } = b . l o c a l _ v a r i a b l e _ g e t ( : # { v } ) " e n d . j o i n ( " \ n " ) } # = > ローカル変数をe v a l でコピー p r = # { p r o c _ s o u r c e } b . r e c e i v e r . i n s t a n c e _ e x e c ( & p r ) e n d e n d R U B Y c . p r o c e s s ( b ) e n d

Slide 22

Slide 22 text

勝ったッ!

Slide 23

Slide 23 text

ブロック内で使わないローカル変数…… c l a s s F o o d e f h e l l o ( n a m e ) r e f i n i n g ( E x t , b i n d i n g ) d o n a m e . h e l l o e n d e n d d e f h e l l o _ k o i c p r o c e s s = p r o c { " k o i c " . h e l l o } r e f i n i n g ( E x t , b i n d i n g , & p r o c e s s ) e n d e n d F o o . n e w . h e l l o ( " j o k e r 1 0 0 7 " ) # = > Y a y ! F o o . n e w . h e l l o _ k o i c # = > u n u s e d l o c a l v a r i a b l e ` p r o c e s s `

Slide 24

Slide 24 text

あーもう、めちゃくちゃだよ! もういいや、AST 使おう

Slide 25

Slide 25 text

parser gem の出力を読んでブロック内のローカル 変数読み出しっぽい所を全部リストアップする d e f g e t _ l o c a l _ v a r i a b l e _ n a m e s ( a s t , b u f = [ ] ) i f a s t . t y p e = = : s e n d p a r a m s = a s t . t o _ a i f p a r a m s [ 0 ] . n i l ? & & p a r a m s . l e n g t h = = 2 b u f < < p a r a m s [ 1 ] e n d e n d a s t . c h i l d r e n . e a c h d o | n o d e | i f n o d e . i s _ a ? ( P a r s e r : : A S T : : N o d e ) g e t _ l o c a l _ v a r i a b l e _ n a m e s ( n o d e , b u f ) e n d e n d b u f e n d

Slide 26

Slide 26 text

d e f r e f i n i n g ( b , m o d , & b l o c k ) b l o c k _ s o u r c e = b l o c k . t o _ s o u r c e m a t c h e d = b l o c k _ s o u r c e . m a t c h ( / d o ( . * ) e n d / m ) p r o c _ s o u r c e = " p r o c # { m a t c h e d [ 0 ] } " u s e d _ l o c a l _ v a r i a b l e s = g e t _ l o c a l _ v a r i a b l e _ n a m e s ( P a r s e r : : C u r c = T O P L E V E L _ B I N D I N G . e v a l ( < < ~ R U B Y ) C l a s s . n e w d o u s i n g # { m o d . t o _ s } d e f s e l f . p r o c e s s ( b ) # 使っている可能性のあるローカル変数だけをコピる # { b . l o c a l _ v a r i a b l e s . s e l e c t { | v | u s e d _ l o c a l _ v a r i a b l e s . i n c l u d e ? ( v ) } . m a p { | v | " # { v } = b . l o c a l _ v a r i a b l e _ g e t ( : # { v } ) " } . j o i p r = # { p r o c _ s o u r c e } b . r e c e i v e r . i n s t a n c e _ e x e c ( & p r ) e n d e n d R U B Y c . p r o c e s s ( b ) e n d

Slide 27

Slide 27 text

なんかbinding 渡すのダサくね? 「ドーモ、バインディング・ニンジャで す」 アイエエエエ!ニンジャ?!

Slide 28

Slide 28 text

binding_ninja でbinding 渡しを隠蔽する e x t e n d B i n d i n g N i n j a a u t o _ i n j e c t _ b i n d i n g d e f r e f i n i n g ( b , m o d , & b l o c k ) b l o c k _ s o u r c e = b l o c k . t o _ s o u r c e m a t c h e d = b l o c k _ s o u r c e . m a t c h ( / d o ( . * ) e n d / m ) # . . . e n d

Slide 29

Slide 29 text

最終系 c l a s s C o n t e x t d e f i n i t i a l i z e ( n a m e = n i l ) @ n a m e = n a m e e n d d e f h e l l o ( s t r ) T r u e R e f i n e m e n t s . r e f i n i n g ( E x t ) d o s t r . h e l l o e n d e n d d e f h e l l o 2 T r u e R e f i n e m e n t s . r e f i n i n g ( E x t ) d o @ n a m e . h e l l o e n d e n d e n d C o n t e x t . n e w ( " j o k e r 1 0 0 7 " ) . h e l l o 2 C o n t e x t . n e w . h e l l o ( " h o g e " )

Slide 30

Slide 30 text

圧倒的じゃないか!

Slide 31

Slide 31 text

実はproc のソース化がめっちゃ危うい… proc の開始と終端取れるAPI 欲しいです!

Slide 32

Slide 32 text

パフォーマンス?何ですか、それ? W a r m i n g u p ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ p l a i n 1 5 3 . 7 7 0 k i / 1 0 0 m s r e f i n i n g 5 6 . 0 0 0 i / 1 0 0 m s C a l c u l a t i n g ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ p l a i n 2 . 0 9 4 M ( ± 3 . 3 % ) r e f i n i n g 5 6 0 . 4 1 3 ( ± 1 . 2 % ) C o m p a r i s o n : p l a i n : 2 0 9 3 8 3 3 . 1 i / s r e f i n i n g : 5 6 0 . 4 i / s ­ 3 7 3 6 . 2 3 x s l o w e r ソースコードパースして、AST からソースコードに戻して、eval し て動的にクラス定義してbinding 作って、ローカル変数引っ張って きてbinding からオブジェクト取得してinstance_exec している結果 がこれだよ。

Slide 33

Slide 33 text

ローカル変数さえ諦めれば10 倍でFA W a r m i n g u p ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ p l a i n 1 4 5 . 0 7 8 k i / 1 0 0 m s r e f i n i n g 1 8 . 1 2 3 k i / 1 0 0 m s C a l c u l a t i n g ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ p l a i n 1 . 9 4 1 M ( ± 3 . 0 ) r e f i n i n g 1 8 9 . 5 1 8 k ( ± 2 . 6 ) C o m p a r i s o n : p l a i n : 1 9 4 1 4 9 1 . 1 i / s r e f i n i n g : 1 8 9 5 1 8 . 0 i / s ­ 1 0 . 2 4 x s l o w e r proc って大変ですね