Chapter 23
Exercise: LinkingModules-BehavioursAndUse-1
name
and args
are parameters passed to a macro, which are the tuples representing their code. Therefore, unquote
is used to evaluate them. On the other hand, result
is just a value, so unquote
is not necessary.
Exercise: LinkingModules-BehavioursAndUse-2 & 3
defmodule Tracer do
import IO.ANSI
def dump_args(args) do
args |> Enum.map(&inspect/1) |> Enum.join(", ")
end
def dump_defn(name, args) do
"#{name}(#{dump_args(args)})"
end
def add_tracer(definition = {name, _, args}, do: content) do
quote do
Kernel.def unquote(definition) do
IO.puts([
red(),
"==> call: #{Tracer.dump_defn(unquote(name), unquote(args))}",
default_color()
])
result = unquote(content)
IO.puts([green(), "<== result: #{result}", default_color()])
result
end
end
end
defmacro def({:when, _, [definition | _]}, do: content) do
add_tracer(definition, do: content)
end
defmacro def(definition, do: content) do
add_tracer(definition, do: content)
end
defmacro __using__(_opts) do
quote do
import Kernel, except: [def: 2]
import unquote(__MODULE__), only: [def: 2]
end
end
end
defmodule Test do
use Tracer
def puts_sum_three(a, b, c) when a == 1 and b == 2, do: IO.inspect(a + b + c)
def add_list(list), do: Enum.reduce(list, 0, &+/2)
end
Test.puts_sum_three(1, 2, 3)
Test.add_list([5, 6, 7, 8])
Exercise: LinkingModules-BehavioursAndUse-3
If add a method definition with a guard clause to the Test module, the value of definition
has changed as follows.
{:when, [line: 41],
[
{:puts_sum_three, [line: 41],
[{:a, [line: 41], nil}, {:b, [line: 41], nil}, {:c, [line: 41], nil}]},
{:and, [line: 41],
[
{:==, [line: 41], [{:a, [line: 41], nil}, 1]},
{:==, [line: 41], [{:b, [line: 41], nil}, 2]}
]}
]}
And then unquote(args)
never returned. I don’t know why, maybe because args
is not a tuple for representing the code, but a list.