20. ということで、レッツ
defmacro sigil_T
@doc """
~T is detect to translate target string.
"""
defmacro sigil_T({:<<>>, _line, [string]}, options) do
binary = Macro.unescape_string(string)
case options do
[] ->
quote do: txt(unquote(binary))
options ->
options = List.to_atom(options)
v = {:"var!", [], [{options, [], nil}]}
quote do
txt(unquote(binary), unquote(v))
end
end
end
本当の神秘はtxt/2
var = ja ;
T foo var などとすると、動的
に言語指定できるための仕組み
リテラル文字列のAST表現(バ
イナリ)
21. 本体はこちら
@doc """
translate target string by lang.
"""
defmacro txt(s, lang) do
r = __CALLER__
path = System.get_env("PWD")
app = get_app()
put_dets(s, %{line: r.line,
file: Exgettext.Util.relative(r.file, path),
function: r.function })
quote bind_quoted: [app: app, s: s, lang: lang] do
Exgettext.Runtime.gettext(app, s, lang)
end
end
• コンパイル時にマクロ展開の副作用と
して、detsへ文字列が登録される。
• プログラム実行時は影響なし。
• line, fileなどは、マクロ呼び出し元
• コンパイル時、マクロはこのASTを返し、コード生成される。
• したがって、プログラム実行時はコレが実行され、gettext/3
関数を呼び出し、langに合わせた翻訳文に変換される。
24. 実験: オレオレh/2の作成
defmodule Exgettexttalk do
require IEx.Helpers
defmacro h() do
quote do
IEx.Helpers.h()
end
end
defmacro h({:/, _, [:iiiii, 0]}) do
"you success :overwritting iex helper."
end
defmacro h(call) do
quote do
IEx.Helpers.h(unquote(call))
end
end
end
h :iiiii/0という独自コマンドの定義
その他は、本物のhコマンドを呼び出
す
25. 実験: オレオレh/2の組み込み
$ iex -S mix
Eshell V6.3 (abort with ^G)
Interactive Elixir (1.1.0-dev) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> import Exgettexttalk
nil
iex(2)> h :iiiii/0
"you success :overwritting iex helper."
iex(3)> h Enum.reverse/1
def reverse(collection)
Reverses the collection.
Examples
┃ iex> Enum.reverse([1, 2, 3])
┃ [3, 2, 1]
iex(4)>
ちゃんと割り込んで仕込んだメッセージを
表示できた。
その他のコマンドのヘルプは通常どおり表
示された。ということで、原理的には翻訳
できなかったら、本物を呼び出して表示す
ればよい!