Upgrade to Pro — share decks privately, control downloads, hide ads and more …

True Refinements #tqrk12

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

True Refinements #tqrk12

Enable Proc level Refinements forcibly in Ruby

Avatar for Tomohiro Hashidate

Tomohiro Hashidate

July 29, 2018
Tweet

More Decks by Tomohiro Hashidate

Other Decks in Technology

Transcript

  1. しかし理想的ではない 何とかして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
  2. ただ単純に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
  3. 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
  4. これでいける? 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
  5. 実は駄目 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
  6. 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
  7. 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
  8. 評価コンテキストの壁 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
  9. 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
  10. 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
  11. ローカル変数がッ! 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 ! !
  12. 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
  13. ブロック内で使わないローカル変数…… 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 `
  14. 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
  15. 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
  16. 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
  17. 最終系 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 " )
  18. パフォーマンス?何ですか、それ? 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 している結果 がこれだよ。
  19. ローカル変数さえ諦めれば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 って大変ですね