chapter_1
Math
defmodule Math do
defmacro say({:+, _, [lhs, rhs]}) do
quote do
lhs = unquote(lhs)
rhs = unquote(rhs)
result = lhs + rhs
IO.puts("#{lhs} plus #{rhs} is #{result}")
result
end
end
defmacro say({:*, _, [lhs, rhs]}) do
quote do
lhs = unquote(lhs)
rhs = unquote(rhs)
result = lhs * rhs
IO.puts("#{lhs} times #{rhs} is #{result}")
result
end
end
end
require Math
Math.say(5 + 2)
require Math
Math.say(5 * 2)
The Building Blocks of Elixir
Re-Creating Elixir’s unless Macro
defmodule ControlFlow do
defmacro unless(expression, do: block) do
quote do
if !unquote(expression), do: unquote(block)
end
end
end
require ControlFlow
ControlFlow.unless 2 == 5, do: "block entered"
ControlFlow.unless 2 == 2 do
"block entered"
end
Expanding the function
ast = quote do
ControlFlow.unless 2 = 5, do: "block entered"
end
expanded_once = Macro.expand_once(ast, __ENV__)
expanded_fully = Macro.expand_once(expanded_once, __ENV__)
unquote
Without unquote
number = 5
ast = quote do
number + 10
end
Code.eval_quoted(ast)
With unquote
number = 5
ast = quote do
unquote(number) + 10
end
Code.eval_quoted(ast)
Code Injection and the Caller’s Context
defmodule Mod do
defmacro definfo do
IO.puts "In macro`s context (#{__MODULE__})."
quote do
IO.puts "In caller`s context (#{__MODULE__})"
def friendly_info do
IO.puts """
My name is #{__MODULE__}
My functions are #{inspect __MODULE__.__info__(:functions)}
"""
end
end
end
end
defmodule MyModule do
require Mod
Mod.definfo
end
MyModule.friendly_info()
Overriding Hygiene
ast = quote do
if var!(meaning_of_life) == 42 do
"It is time"
else
"It remains to be seen"
end
end
Code.eval_quoted(ast, meaning_of_life: 42)
If we have scope hygiene in place varible dont like outside
defmodule Setter1 do
defmacro bind_name(string) do
quote do
name = unquote(string)
end
end
end
require Setter1
name = "Chris"
Setter1.bind_name("max")
name
Code without hygiene protection
defmodule Setter2 do
defmacro bind_name(string) do
quote do
var!(name) = unquote(string)
end
end
end
require Setter2
name = "King"
Setter2.bind_name("Queen")
name