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

True Refinements #tqrk12

True Refinements #tqrk12

Enable Proc level Refinements forcibly in Ruby

A5e5ee2fb9e4ce3c728ed9e3ef6e916f?s=128

Tomohiro Hashidate

July 29, 2018
Tweet

Transcript

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

  2. 私はRefinements が好きだ

  3. しかし理想的ではない 何とかして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
  4. よろしい ならばeval だ

  5. ただ単純に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
  6. 決め打ちしかできねえ 何とかしてproc 渡したい ソースコードが欲しい 大丈夫!parser & unparser がある!

  7. 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
  8. これでいける? 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
  9. 実は駄目 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
  10. TOPLEVEL_BINDING は常に同じbinding 一回eval でusing したら効果が残る 大丈夫!Class.new がある!

  11. 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
  12. 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
  13. やったか?! => やってない

  14. 評価コンテキストの壁 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
  15. まずは落ち着け 落ち着いてobject を渡せばいい instance_exec だ

  16. 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
  17. 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
  18. いけるやん!

  19. ローカル変数がッ! 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 ! !
  20. Binding 「俺様の出番の様だな」

  21. 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
  22. 勝ったッ!

  23. ブロック内で使わないローカル変数…… 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 `
  24. あーもう、めちゃくちゃだよ! もういいや、AST 使おう

  25. 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
  26. 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
  27. なんかbinding 渡すのダサくね? 「ドーモ、バインディング・ニンジャで す」 アイエエエエ!ニンジャ?!

  28. 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
  29. 最終系 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 " )
  30. 圧倒的じゃないか!

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

  32. パフォーマンス?何ですか、それ? 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 している結果 がこれだよ。
  33. ローカル変数さえ諦めれば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 って大変ですね