DEV Community

Weerasak Chongnguluam
Weerasak Chongnguluam

Posted on

Elixir code template with __using__ macro

Macro ใน Elixir เป็นกระบวนการ code transformation คือรับ AST (Abstract Syntax Tree เป็นโครงสร้างแทน source code) เป็น input แล้วสามารถ process บางอย่างเพื่อส่ง AST output ที่อยากได้กลับออกไป

Elixir มี use/2 ซึ่งเป็น macro ที่ติดมากับ Kernel module สำหรับให้เราสร้าง code template แล้วใช้ use เพื่อ inject โค้ดเข้ามาใน module ที่อื่นที่เราต้องการได้

use รับค่า 2 อย่างคือ ชื่อ Module ที่จะเป็นส่วน generate code ที่จะถูก inject เข้ามา กับ option อื่นๆถ้ามี

ส่วน Module ที่ถูก inject เข้ามาสามารถสร้าง code template ได้โดยการสร้าง macro ชื่อ __using__/1 โดยรับ options เป็น parameter แล้วให้เขียนโค้ดที่ต้องการ inject ไว้ใน macro __using__ นี่แหละ

ตัวอย่างเช่น เราจะสร้าง module Greeter เพื่อเก็บ template ของ function say/0 แบบนี้

defmodule Greeter do
  defmacro __using__(opts) do
    quote do
      def say do
        opts = unquote(opts)
        name = opts[:name] || "World"
        IO.puts("Hello #{name}")
      end
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

เราสามารถ inject function say/0 เข้าไปใน module อื่นได้โดยใช้ use แบบนี้

defmodule Hello do
  use Greeter,
    name: "Por"
end
Enter fullscreen mode Exit fullscreen mode

ทำให้ module Hello มี method say ที่จะ print Hello Por แบบนี้

iex(4)> Hello.say
Hello Por
:ok
Enter fullscreen mode Exit fullscreen mode

นี้คือกลไกการทำงานของ use/2 ที่แม้ว่าเราอาจจะไม่ได้เขียน module template เอง แต่คงทำให้เข้าใจมากขึ้นเพราะเราจะได้ใช้ use/2 บ่อยมากๆกับ library อย่าง Phoenix หรือ Ecto

Top comments (0)