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

【Crystal】Macroについて

 【Crystal】Macroについて

東京 Crystal 勉強会 #6 in 渋谷
https://crystal.connpass.com/event/90745/

イベント資料です。

at_grandpa

June 21, 2018
Tweet

More Decks by at_grandpa

Other Decks in Technology

Transcript

  1. Macroについて
    2018.06.21 @at_grandpa
    Crystal 勉強会 #6 in 渋谷

    View full-size slide

  2. 圧倒亭グランパのブログ

    View full-size slide

  3. Crystal Advent Calendar 2017

    View full-size slide

  4. Crystal Advent Calendar 2017

    View full-size slide

  5. Macroについて

    View full-size slide

  6. ✔ Macro の雰囲気を話します
    ✔ 細かい syntax などはドキュメント参照

    View full-size slide

  7. ✔ 「Crystalのコード」を書くコード
    ✔ コンパイル前に実行される
    Macro

    View full-size slide

  8. Macro呼出
    Macro展開

    View full-size slide

  9. Macro展開後のコードがコンパイルされる

    View full-size slide

  10. どういった利点があるのか

    View full-size slide

  11. ✔ 重複を排除しやすい

    ✔ メタプロ風味
    ✔ DSLを提供しやすい

    View full-size slide

  12. 重複を排除しやすい

    View full-size slide

  13. 重複
    重複排除

    View full-size slide

  14. getter だけなのに複雑では…

    View full-size slide

  15. getterあります
    Object クラスに定義されている Macro

    View full-size slide

  16. 便利 Macro たくさん!
    https://crystal-lang.org/api/Object.html

    View full-size slide

  17. Crystal Advent Calendar 2017
    便利 Macro 紹介してます

    View full-size slide

  18. 重複を排除しやすい
    ✔ ある程度は重複排除できる

    ✔ 便利 Macro がすでにいくつかある

    View full-size slide

  19. メタプロ風味

    View full-size slide

  20. ✔ rubyだと instance_methods と define_method ?
    各メソッドの実行時間を出力したい!
    お題

    View full-size slide

  21. 簡単なライブラリクラスを書いてみる
    「MethodProf」クラスとでも名付けよう

    View full-size slide

  22. まずは使用例

    View full-size slide

  23. 出来上がりイメージ

    View full-size slide

  24. 出来上がりイメージ
    1秒 sleep して String を返す

    View full-size slide

  25. 出来上がりイメージ
    100万回 String を結合する

    View full-size slide

  26. 出来上がりイメージ
    100万回 String を2つ結合している

    View full-size slide

  27. 出来上がりイメージ
    MethodProf を include して Macro を展開している

    View full-size slide

  28. 出来上がりイメージ
    インスタンスを生成してメソッド呼び出し

    View full-size slide

  29. 出来上がりイメージ

    View full-size slide

  30. MethodProf クラス

    View full-size slide

  31. macro構文で定義(引数はio)

    View full-size slide

  32. ・@type は型情報にアクセスできる
    ・@type.methods で型に定義されているmethodの配列を得る
     - ArrayLiteral(Crystal::Macros::Def)
    ・initializeメソッドは計測対象から外すので配列から除去
    → initialize 以外の method 情報で for を回す

    View full-size slide

  33. ・展開される Crystal のコードを定義
    ・呼出先に def 構文が展開される

    View full-size slide

  34. ・メソッド名は Crystal::Macros::Def#name で得る
    ・引数は Crystal::Macros::Def#args で得る
     - 「*」をつけて splat展開 している

    View full-size slide

  35. ・計測のために時間を保持

    View full-size slide

  36. ・lambda を生成
     - 引数は対象のメソッドと同じ
     - メソッドの中身は Crystal::Macros::Def#body で得る
    ・lambda を即座に call する

     - 渡す引数は args の名前を羅列
     - *(m.args) は型情報も含まれてしまうので、ここでは名前だけ展開
    ・return_value に格納

    View full-size slide

  37. ・計測結果を io に出力

    View full-size slide

  38. ・lambda の結果を返す

    View full-size slide

  39. Macro を展開するとこうなります
    loop2を例に

    View full-size slide

  40. Macro定義
    loop2展開後

    View full-size slide

  41. Macro定義
    loop2展開後

    View full-size slide

  42. Macro定義
    loop2展開後

    View full-size slide

  43. Macro定義
    loop2展開後

    View full-size slide

  44. Macro定義
    loop2展開後

    View full-size slide

  45. Macro定義
    loop2展開後

    View full-size slide

  46. ✔ ASTNodeの情報からコンパイル時にコードを生成

    ✔ splat展開が優秀だった!
    ✔ もちろん「動的なclass定義」はできない
    メタプロ風味

    View full-size slide

  47. DSLを提供しやすい

    View full-size slide

  48. https://github.com/at-grandpa/clim

    View full-size slide

  49. https://github.com/at-grandpa/clim
    ✔ ruby の thor 風 syntax
    ✔ オプションの型指定

    ✔ default / required

    ✔ サブコマンド

    ✔ カスタムヘルプ

    View full-size slide

  50. すべて Macro
    ・最終的に全てクラスやメソッドの定義に展開される

    View full-size slide

  51. コンパイル時に raise で落としてエラーメッセージを出す

    View full-size slide

  52. DSLに渡された文字列を使ってオプションの独自のクラスを定義
    DSLに渡された文字列を使ってコマンドの独自のクラスを定義

    View full-size slide

  53. DSLを提供しやすい
    ✔ 複雑なコードも簡単に記述できるようになる

    View full-size slide

  54. ✔ 重複を排除しやすい

    ✔ メタプロ風味
    ✔ DSLを提供しやすい
    Macro の利点おさらい

    View full-size slide

  55. Macro周りのtips

    View full-size slide

  56. デバッグしづらいのでは?

    View full-size slide

  57. エラー文が親切です!

    View full-size slide

  58. エラー文が親切です!
    Macro 展開後のどこでエラーが起きているかわかる

    View full-size slide

  59. エラー文が親切です!
    エラー内容も具体的

    View full-size slide

  60. `crystal tool expand` があります!
    ✔ ファイルとカーソル位置指定
    ✔ カーソル位置の Macro を展開して表示

    View full-size slide

  61. crystal tool expand
    ファイルとカーソル位置を指定

    View full-size slide

  62. crystal tool expand
    展開されたコードを見ることができる

    View full-size slide

  63. `macro` ディレクティブなしでもOK

    View full-size slide

  64. 実は直接書けます
    環境変数でcrystalコードを切り替えたりできます

    View full-size slide

  65. 展開後は正しいのにエラーなんだけど

    View full-size slide

  66. ❌ Macro展開後、全体のコードが正しい
    ⭕ Macro展開のみで出来たコードが正しい

    View full-size slide

  67. ❌ Macro展開後、全体のコードが正しい
    ⭕ Macro展開のみで出来たコードが正しい

    View full-size slide

  68. ❌ Macro展開後、全体のコードが正しい
    ⭕ Macro展開のみで出来たコードが正しい
    この Macro 展開だけでは `when` だけしか展開されない

    → Macro展開だけのコードを見ると syntax error
    → コンパイラ落ちる

    View full-size slide

  69. begin ~ end を使う

    View full-size slide

  70. begin ~ end を使う
    begin ~ end で囲めば、
    ひとつのMacroとして扱われる
    → 展開後のコードは正しい
    ※ 実は {% begin %} は {% if true %} のシンタックスシュガーです

    View full-size slide

  71. ✔ 「Crystalのコード」を書くコード
    ✔ コンパイル前に実行される

    ✔ 重複を排除しやすい

    ✔ メタプロ風味
    ✔ DSLを提供しやすい
    Macro とは

    View full-size slide

  72. Happy Crystalling
    fin

    View full-size slide