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

Elixir 黒魔術入門

Elixir 黒魔術入門

Erlang & Elixir Fest 2019 LT 資料

8e9c7ba7d90afce7f2dc3cfcb1553de7?s=128

tamanugi

May 30, 2019
Tweet

Transcript

  1. Elixir 黒魔術入門 @tamanugi

  2. 自己紹介 @tamanugi Elixirは完全に理解したぐらいに理解しました 仕事ではJavaを書いてます

  3. 自己紹介 @tamanugi Elixirは完全に理解したぐらいに理解しました 仕事ではJavaを書いてます

  4. 今日話すこと

  5. ⿊魔術

  6. Elixirで⿊魔術といえば?

  7. defmacro

  8. ごめんなさい

  9. defmacro... (本当の意味で)何もわからん

  10. (改めて)今日話すこと

  11. 高等黒魔術(defmacro)を 使わない基礎黒魔術 今日から できる̇

  12. 基礎魔術Lv.1 Summon Module

  13. summon = fn -> defmodule Tamanugi do def say(), do:

    IO.puts("転生したらモジュールだった件") end end summon.() Tamanugi.say() # → 転生したらモジュールだった件
  14. summon = fn -> defmodule Tamanugi do def say(), do:

    IO.puts("転生したらモジュールだった件") end end summon.() Tamanugi.say() # → 転生したらモジュールだった件 ͂ defmoduleの正体は実はマクロ 匿名関数内であってもdefmoduleが実行されれば モジュールが召喚される mix compile時に実行される関数に書けば compile時に召喚できる
  15. 基礎魔術Lv.2 Naming

  16. summon = fn mod -> defmodule Module.concat(Kanzen, mod) do def

    say() do IO.puts("#{__MODULE__}した^ω^") end end end summon.(Rikai) Kanzen.Rikai.say() # Elixir.Kanzen.Rikaiした^ω^
  17. summon = fn mod -> defmodule Module.concat(Kanzen, mod) do def

    say() do IO.puts("#{__MODULE__}した^ω^") end end end summon.(Rikai) Rikai.say() # Elixir.Kanzen.Rikaiした^ω^ モジュール名の動的な名前付けも可能 モジュールの親子関係はModule.concat/2を使う 文字列からモジュール名つける場合は Module.concat/1が使える
 iex> Module.concat(["Hoge"]) Hoge

  18. 基礎魔術Lv.3 unquote

  19. summon = fn fun_name -> defmodule Hoge do def unquote(fun_name)(arg)

    do IO.puts("#{unquote(fun_name)}#{arg}です") end end end summon.(:hoge) Hoge.hoge("fuga") # hogefugaです
  20. summon = fn fun_name -> defmodule Hoge do def unquote(fun_name)(arg)

    do IO.puts("#{unquote(fun_name)}#{arg}です") end end end summon.(:hoge) Hoge.hoge("fuga") # hogefugaです unquoteを使えば関数名を動的に生成できる
 unquoteはASTに式を注入するもの
 イメージは文字列に変数を展開するのと同じ感じ
  21. summon = fn funs -> defmodule Tamanugi do Enum.each(funs, fn

    fun -> def unquote(fun)(arg), do: :ok end) end end summon.([:hoge, :fuga, :piyo]) Tamanugi.module_info(:exports) # [fuga: 1, hoge: 1, piyo: 1, ...] Tamanugi.fuga() # :ok
  22. summon = fn funs -> defmodule Tamanugi do Enum.each(funs, fn

    fun -> def unquote(fun)(arg), do: :ok end) end end summon.([:hoge, :fuga, :piyo]) Tamanugi.module_info(:exports) # [fuga: 1, hoge: 1, piyo: 1, ...] Tamanugi.fuga() # :ok Enum.each/2を使うことで複数の 関数を生成することも可能!!
  23. summon = fn args -> defmodule Hoge do vars =

    Enum.map(args, fn arg -> arg |> String.to_atom |> Macro.var(__MODULE__) end) def say(unquote_splicing(vars)) do IO.inspect unquote(vars) end end end summon.(["arg1", "arg2", "arg3"]) Hoge.say(1, 2, 3) # [1, 2, 3]
  24. summon = fn args -> defmodule Hoge do vars =

    Enum.map(args, fn arg -> arg |> String.to_atom |> Macro.var(__MODULE__) end) def say(unquote_splicing(vars)) do IO.inspect unquote(vars) end end end summon.(["arg1", "arg2", "arg3"]) Hoge.say(1, 2, 3) # [1, 2, 3]
  25. summon = fn args -> defmodule Hoge do vars =

    Enum.map(args, fn arg -> arg |> String.to_atom |> Macro.var(__MODULE__) end) def say(unquote_splicing(vars)) do IO.inspect unquote(vars) end end end summon.(["arg1", "arg2", "arg3"]) Hoge.say(1, 2, 3) # [1, 2, 3] unquote_splicingを使えば複数引数の関数も生成できる 引数は Macro.var/2 を使ってASTにしておく必要がある
  26. 実際に使ってみた

  27. https://hex.pm/packages/qiitex 拙作: QiitaのAPIクライアント
 Qiitaが提供しているJSON Schemeから生成 ドキュメントも生成

  28. Elixirの黒魔術は簡単!
 Write 黒魔術! Enjoy 黒魔術!

  29. ※自己責任でお願いします

  30. ご清聴ありがとうございました! (ぼっち参加なので懇親会では話しかけてもらえてると うれしいです!)