Slide 1

Slide 1 text

Elixir 黒魔術入門 @tamanugi

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

今日話すこと

Slide 5

Slide 5 text

⿊魔術

Slide 6

Slide 6 text

Elixirで⿊魔術といえば?

Slide 7

Slide 7 text

defmacro

Slide 8

Slide 8 text

ごめんなさい

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

(改めて)今日話すこと

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

基礎魔術Lv.1 Summon Module

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

summon = fn -> defmodule Tamanugi do def say(), do: IO.puts("転生したらモジュールだった件") end end summon.() Tamanugi.say() # → 転生したらモジュールだった件 ͂ defmoduleの正体は実はマクロ 匿名関数内であってもdefmoduleが実行されれば モジュールが召喚される mix compile時に実行される関数に書けば compile時に召喚できる

Slide 15

Slide 15 text

基礎魔術Lv.2 Naming

Slide 16

Slide 16 text

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した^ω^

Slide 17

Slide 17 text

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


Slide 18

Slide 18 text

基礎魔術Lv.3 unquote

Slide 19

Slide 19 text

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です

Slide 20

Slide 20 text

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に式を注入するもの
 イメージは文字列に変数を展開するのと同じ感じ

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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を使うことで複数の 関数を生成することも可能!!

Slide 23

Slide 23 text

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]

Slide 24

Slide 24 text

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]

Slide 25

Slide 25 text

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にしておく必要がある

Slide 26

Slide 26 text

実際に使ってみた

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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