Erlang Emakefile の実行には erl -make
Emakefile の実行は対話環境から make:all(). でもよいけど、コマンドラインの erl -make でもよいです。
Makefile に書くには erl -make がすっきりしてていいですね。escript だなんて戯言を言っていました。
%%-*-erlang-*-
{'*', [debug_info,
{outdir, "../ebin"}]}.
erlc を使ってもいいのですが。
Emakefile の実行は対話環境から make:all(). でもよいけど、コマンドラインの erl -make でもよいです。
Makefile に書くには erl -make がすっきりしてていいですね。escript だなんて戯言を言っていました。
%%-*-erlang-*-
{'*', [debug_info,
{outdir, "../ebin"}]}.
filelib:fold_files/5 という関数があります。
1番目の引数がディレクトリ。
2番目が処理対象か否かを判定するための正規表現。
3番目がサブディレクトリも再帰的に処理するか否か。
4番目が各ファイルに適用する関数。
5番目が初期値。
4番目の引数である関数は引数を2つとります。最初の引数は処理対象のファイル。次は最初は5番目に指定した引数で、それ以降はこの関数の返り値です。
サフィックスが erl のファイルをリストにして取得するには次のように書きます。
>1 filelib:fold_files("/home/ancient/letter/erlang", "\\.erl$", true, fun(X, Acc) -> [X|Acc] end, []).
["/home/ancient/letter/erlang/a/fib.erl",
"/home/ancient/letter/erlang/chat/_darcs/pristine/chat.erl",
"/home/ancient/letter/erlang/chat/_darcs/pristine/test_chat.erl",
"/home/ancient/letter/erlang/chat/chat.erl",
[...]|...]
やはりそうでしょう。
では、思考の可能性を最も広げてくれる言語は何でしょうか。
もっとも、広げるだけ広げてもそれでよい思考が生まれるわけでもないでしょう。
すくなくとも思考の可能性は生まれる。
間違いを犯しやすいからといって限定する言語は嫌いです。
新しい視野を示してくれる言語は素晴らしい。
想像力しだいで何もかもが自由になる言語は素晴らしい。
やっぱりプロセスを使わないと。
-module(make_index).
-compile(export_all).
start() ->
lists:foreach(fun(X) -> register(X, spawn_link(?MODULE, holder, [[]])) end,
[head, tail, index]),
register(contents, spawn_link(?MODULE, contents, [head])),
{ok, In} = file:read_file("cookbook_src.html"),
loop(binary_to_list(In)).
holder(V) ->
receive
{get, From} ->
From ! lists:reverse(V);
X ->
holder([X|V])
end.
contents(HorT) ->
receive
tail ->
contents(tail);
'終ったよ' ->
file:write_file("cookbook.html",
[begin
P ! {get, self()},
receive X -> X end
end || P <- [head, index, tail]]);
X ->
HorT ! X,
contents(HorT)
end.
loop([]) ->
contents ! '終ったよ';
loop("****index_place****" ++ T) ->
contents ! tail,
loop(T);
loop("<h2>" ++ T) ->
[Ast|Ref] = erlang:ref_to_list(make_ref()),
index ! io_lib:format("<h3><a href='~s'>", [[Ast|Ref]]),
contents ! io_lib:format("<h2><a name='~s'>", [Ref]),
h2(T);
loop("<h3>" ++ T) ->
[Ast|Ref] = erlang:ref_to_list(make_ref()),
index ! io_lib:format("<a href='~s'>", [[Ast|Ref]]),
contents ! io_lib:format("<h3><a name='~s'>", [Ref]),
h3(T);
loop([X|T]) ->
contents ! X,
loop(T).
h2("</h2>" ++ T) ->
index ! "</a></h3>",
contents ! "</a></h2>",
loop(T);
h2([X|T]) ->
index ! X,
contents ! X,
h2(T).
h3("</h3>" ++ T) ->
index ! "</a><br>",
contents ! "</a></h3>",
loop(T);
h3([X|T]) ->
index ! X,
contents ! X,
h3(T).
Erlang クエックブック にインデックスを付けました。
手でつけるのはめんどうだったので、Erlang でインデックスを付けるようにしました。
そのソースです。P とか R だったらもっと簡単にできる、というのはここではなしで。
if も case もなしで。
さらに、”クエック”って何よ、というのもなしで。
#!/usr/bin/env escript
main(_) ->
{ok, In} = file:read_file("cookbook_src.html"),
{Index, Contents} = f(binary_to_list(In), [], []),
Dest = insert_index(Index, Contents),
file:write_file("cookbook.html", Dest).
insert_index(Index, Contents) ->
P = find_index(Contents, 0),
{X, Y} = lists:split(P, Contents),
X ++ Index ++ (Y -- "*index_place*").
find_index("*index_place*" ++ _, N) ->
N;
find_index([_|C], N) ->
find_index(C, N+1).
f([], Index, Contents) ->
{lists:reverse(Index), lists:reverse(Contents)};
f("<h2>" ++ T, I, C) ->
[Ast|Ref] = erlang:ref_to_list(make_ref()),
I2 = io_lib:format("<h3><a href='~s'>", [[Ast|Ref]]),
H2 = io_lib:format("<h2><a name='~s'>", [Ref]),
h2(T, [I2|I], [H2|C]);
f("<h3>" ++ T, I, C) ->
[Ast|Ref] = erlang:ref_to_list(make_ref()),
I3 = io_lib:format("<a href='~s'>", [[Ast|Ref]]),
H3 = io_lib:format("<h3><a name='~s'>", [Ref]),
h3(T, [I3|I], [H3|C]);
f([X|T], I, C) ->
f(T, I, [X|C]).
h2("</h2>" ++ T, I, C) ->
f(T, ["</a></h3>"|I], ["</a></h2>"|C]);
h2([X|T], I, C) ->
h2(T, [X|I], [X|C]).
h3("</h3>" ++ T, I, C) ->
f(T, ["</a><br>"|I], ["</a></h3>"|C]);
h3([X|T], I, C) ->
h3(T, [X|I], [X|C]).
Emacs の indent-tabs-mode はバッファローカルなんですね。
グローバルに値を変えたい場合は setq ではなく setq-default を使かいます。
(setq-default indent-tabs-mode nil) ;タブではなくスペースを使う。
perl - telnetコマンドを自作する の Erlang(escript)バージョンです。
#!/usr/bin/env escript
main([Host]) ->
main([Host, telnet]);
main([Host, Port]) when is_list(Port) ->
main([Host,
case catch list_to_integer(Port) of
{'EXIT', _} ->
list_to_atom(Port);
Num ->
Num
end]);
main([Host, Port]) when is_atom(Port) ->
{ok, Num} = inet:getservbyname(Port, tcp),
main([Host, Num]);
main([Host, Port]) ->
{ok, S} = gen_tcp:connect(Host, Port, []),
spawn_link(fun() -> send_loop(S) end),
recv_loop(S).
send_loop(S) ->
Line = io:get_line(''),
gen_tcp:send(S, Line),
send_loop(S).
recv_loop(S) ->
receive
{tcp, _Port, Data} ->
io:format(Data);
{tcp_closed, _Port} ->
exit(normal)
end,
recv_loop(S).
Erlang の io モジュールで明示的に標準入出力を指定する場合は standard_io を指定するとなっています。
その standard_io って何でしょう。
io モジュールのソースを見ると IoDevice を省略、または stadard_io を指定すると、group_leader() を IoDevice に指定するようになっています。
group_leader() は erlang モジュールで定義されています。
Erlang の全プロセスはいずれかのプロセスグループのメンバーとなっています。
erlang:group_leader/0 はそのプロセスグループのリーダーを返します。
グループ内の IO 処理はそのグループリーダーを通して行われます。
すなわち、Erlang の各プロセスにとって標準入出力とはグループリーダーそのものなのです。
というわけで、標準入出力を使用する時に group_leader() 呼んでいるのです。
以上が、前置きです。
本題は file:read/2 で標準入出力からリードする方法です。
file:read/2 に standard_io を渡しても {error,einval} が返ってきます。
上記をふまえ、ここでは group_leader() の返り値を渡せばいいのです。
1> file:read(standard_io, 1).
{error,einval}
2> file:read(group_leader(), 1).
a
{ok,"a"}
使わないよね。case は使うけど、if は本当に使いません。
以下、とりとめのない文章ですが。。。
普段の仕事で(Erlang ではない)if → 条件分岐 → テストケース増 という図式があるので、if がないプログラムはとても好ましいのです。
case も条件分岐なので if と変わりないかもしれませんが、case は条件分岐というよりむしろパターンマッチング感が強いので、心理的抵抗が低いのです。
case も関数呼び出しのパターンマッチングに置き換えられるので使わないで済ませられます。
Common Lisp でも if より and や or の方が気持ちがいいです。
単に if 嫌いなのかもしれません。
というわけで、if 嫌いなあなたに Erlang を。
Windows に TeX をインストールする際のメモです.
まず、あべのり[阿部紀行]さん作成のTeXインストーラ3を使います。
http://www.ms.u-tokyo.ac.jp/~abenori/mycreate/index.html から TeXインストーラ3 0.58 kakuto3_0_58.zip をダウンロードします。
ダウンロードした kakuto3_0_58.zip を解凍して kakuto3\kakuto3.exe を実行します。
インストール先は C:\home\ancient\local\opt\tex を指定。
他は何もかえずに「次へ」ボタンを数回押すと, ファイルのダウンロードとインストールが開始します。
AFPL Ghostscript Setup のダイアログでは Install to directory を c:\home\ancient\local\opt\gs\gs に, Use Windows True Type fonts for Chinese, Japanese and Korean を チェックします。
GSView は全てデフォルトのままでインストール。
うながされるまま再起動します。
次に WinShell をインストールします。
http://www.winshell.de/ から WinShell31.exe をダウンロードして実行します。
インストールが完了したら、WinShell が起動するので、Choose Language で Japanese を選択しましょう。
WinShell の設定を行います。UTF-8 を使用する設定にします。
メニューの「オプション」「全般」をクリックします。
「一般」タブで、言語に Japanese、ファイル形式に Unix を指定します。
「主なTeXプログラムの設定」タブで、
LaTeX: platex、コマンドライン: --kanji=utf8 -src-specials -interaction=nonstopmode "%s.tex"
BibTeX: jbibtex
DVI -> PS: dvipsk
PDFLaTeX: dvipdfmx、コマンドライン: "%s.dvi"
「ユーザ指定プログラム」のタブで、
Tool1: mendex、exeファイル名: mendex、コマンドライン: "%s.idx"
「フォント」タブで、「文章」のフォントを「MS ゴシック」、スクリプトを「日本語」、エンコーディングを「UTF-8」
というように設定します。
dvipdfmx で otf が使えるように設定します。
c:/home/ancient/local/opt/tex/share/texmf/dvipdfm/config/dvipdfmx.cfg の末尾に
f cid-x-local.map
を追記します。
c:/home/ancient/local/opt/tex/share/texmf-local/fonts/map/dvipdfm/local/cid-x-local.map を http://oku.edu.mie-u.ac.jp/~okumura/texwiki/?OTF#z044b3e2 の For dvipdfmx の フォントを埋め込まない場合 にあるとおり内容で作成します。
最後に mktexlsr.exe を実行します。
dviout もいい加減な設定をしておきます。
WinJFont で hminr-h を MS 明朝、hgothr-h を MS ゴシック で Define して Save します。
Erlang でやっておこう。
-module(a).
-compile(export_all).
m() ->
F = fun
(_, 0, 0) ->
"FizzBuzz";
(_, 0, _) ->
"Fizz";
(_, _, 0) ->
"Buzz";
(X, _, _) ->
integer_to_list(X)
end,
erlang:display([F(X, X rem 3, X rem 5) || X <- lists:seq(1, 100)]).
(loop for i from 1 to 100
collect (cond ((zerop (rem i 15)) "FizzBuzz")
((zerop (rem i 5)) "Buzz")
((zerop (rem i 3)) "Fizz")
(t i)))
(defmacro f (sym &rest args)
`(cond
((and ,@(mapcar #'(lambda (a)
`(zerop (rem i ,(car a))))
args)
,(format nil "~{~a~}" (mapcar #'cadr args))))
,@(mapcar #'(lambda (a)
`((zerop (rem i ,(car a))) ,(cadr a)))
args)
(t ,sym)))
(loop for i from 1 to 100
collect (f i (3 "Fizz") (5 "Buzz")))
(loop for i from 1 to 100
collect (f i (3 "Fizz") (5 "Buzz") (6 "Huzz")))
投稿者 Yoshinori Tahara 時刻: 06:09 0 コメント
ラベル: Common Lisp, Erlang
Erlang ファイルサーバの置き換えですが、次のようにリレーしなくても登録するだけでいけるのでは、と思って試してみました。
register で badarg が発生して、動きませんでした。
register ではローカルプロセスまたはローカルポートしか登録できないのでリレーが必要のなですね。
-module(pseudo_file_server2).
-export([start/0]).
start() ->
%% ローカルノードのファイルサーバを登録解除
unregister(file_server_2),
%% リモートノードのファイルサーバの pid を取得
Pid = rpc:call('ubu@172.22.10.22', erlang, whereis, [file_server_2]),
%% そのプロセスをローカルノードのファイルサーバとして登録
register(file_server_2, Pid).
やはり Erlang はすごいです。
古い方の Erlang 本『Concurrent Programing in ERLANG』の 11.9 Relay Techniques に載っていたものですが、心底驚きました。
Erlang ではファイルIOは file_server_2 という名前で登録されたプロセス経由で行います。
その file_server_2 をリモートノードのプロセスで置き換えることにより全てのファイルIOがリモートノードが走っているマシンのファイルシステム対しての操作になります。
-module(pseudo_file_server).
-export([start/0, relay/1]).
start() ->
%% ローカルノードのファイルサーバを登録解除
unregister(file_server_2),
%% リモートノードへのリレーループプロセスを開始
Pid = spawn(?MODULE, relay, ['ubu@172.22.10.22']),
%% そのプロセスをローカルノードのファイルサーバとして登録
register(file_server_2, Pid).
relay(Node) ->
%% リモートノードのファイルサーバの pid を取得
Pid = rpc:call(Node, erlang, whereis, [file_server_2]),
%% リレーループ開始
loop(Pid).
loop(Pid) ->
%% ファイルサーバとして受信したものをリモートノードへリレー
receive
Any ->
Pid ! Any
end,
loop(Pid).
2> pseudo_file_server:start().
ture
3> file:write_file("/tmp/a.txt", "hello").
ok
~/.emacs
;;;;AUCTeX
(load "auctex.el" nil t t)
(load "preview-latex.el" nil t t)
(setq TeX-auto-save t)
(setq TeX-parse-self t)
(setq-default TeX-master nil)
(setq TeX-default-mode 'japanese-latex-mode)
(setq japanese-TeX-command-default "pTeX")
(setq japanese-LaTeX-command-default "pLaTeX")
(setq japanese-LaTeX-default-style "jsarticle")
(setq TeX-print-command "%(o?)dvips -P%p %r %s")
(add-hook 'TeX-mode-hook
(function
(lambda ()
(TeX-source-specials-mode 1)
;; (add-to-list 'TeX-output-view-style
;; '("^dvi$" "." "dvipdfmx %dS %d && acroread %s.pdf"))
(local-set-key "\C-c\C-i" 'TeX-complete-symbol)
;; (local-set-key "\C-@" 'TeX-next-error))))
)))
Yaws 組み込みモードで他のマシンからアクセスできるようにするには、listen と servername の指定も必要です。
SC = [{port, 8880}, % ポート番号
{servername, "www.example.com"}, % サーバ名
{listen, {0, 0, 0, 0}}], % リッスンアドレス
GC = [{logdir, "/tmp"}], % グローバル設定
yaws:start_embedded("/var/www", SC, GC). % 組み込みモードでスタート
io_lib:format/2 の返り値が、単なる文字列ではなく、文字と文字列のリストになるのは不便なのに何故だろう、と思っていました。
ふとしたことで文字と文字列のリストそのままで出力できることに気づきました。
lists:flatten はいらないのですね。
file:write_file/2 でもネストしたリストそのままで大丈夫でした。
49> io_lib:format("Hello ~s!~n", ["World"]).
[72,101,108,108,111,32,"World",33,"\n"]
50> io:format([72,101,108,108,111,32,"World",33,"\n"]).
Hello World!
ok
51> "Hello" " " "World" "!\n".
"Hello World!\n"
モジュールの attributes とは - で始まっているもの。
任意の属性を定義できる。
-lisp(yes).
5> beam_lib:chunks(lisp_bif, [attributes]).
{ok,{lisp_bif,[{attributes,[{lisp,[yes]},
{vsn,[302273399647271765179114790951201449381]}]}]}}
SPAM フィルタのように学習する RSS リーダってないかしら?
エントリ毎に好き嫌いが指定して、学習していく。
学習結果に基づくスコア順に表示。
突然変異でスコアの低いものが上位に表示され、たまには他の分野の情報も目にできる。
のような RSS リーダが欲しい。
もはやブログが多すぎて、そろそろフィルタリングする時期です。
みかログさんでErlangでCometが書かれていますが、同様に Erlang で Comet です。こちらの方が随分長いソースになっていますが。
クライアント(ブラウザ、セッション)毎に受信プロセスを常駐させます。
送信されたメッセージは全ての受信プロセスに送信され、受信プロセスはクライアントが受信待ちの場合、クライアントへメッセージを返します。
受信プロセスにはタイムアウト管理プロセスがリンクしてあり、一定時間クライアントへの送信を行わない場合、受信プロセスは exit します。
クライアント1つにつき、受信プロセスとタイムアウト管理プロセス(あとおそらく、Yaws のリクエスト処理プロセス)が常駐します。プロセス大盤振る舞いです。
ファイルの構成は次のようになっています。
-module(chat).
-compile(export_all).
%%-define(LOG(X), error_logger:info_msg("~p = ~p~n", [??X, X])).
-define(LOG(X), ok).
-define(COOKIE_KEY, "chat").
-include_lib("yaws/include/yaws_api.hrl").
-record(receive_status, {pid, ref, waiting=false, messages=[], timeout_pid}).
%% Yaws と チャットサーバを開始します。
start() ->
LogDir = filename:absname("log"),
DocRoot = filename:absname("www"),
start(LogDir, DocRoot).
%% Yaws と チャットサーバを開始します。
start(LogDir, DocRoot) ->
pg2:create(receive_proc_group), % 受信プロセスグループを作成
start_yaws(LogDir, DocRoot). % Yaws 開始
%% Yaws を開始します。
start_yaws(LogDir, DocRoot) ->
SC = [{port, 9999}], % サーバ設定
GC = [{logdir, LogDir}], % グローバル設定
yaws:start_embedded(DocRoot, SC, GC). % 組み込みモードでスタート
%% 受信プロセス初期化
receive_init(S) ->
Pid = spawn_link(?MODULE, receive_timeout, []),
receive_loop(S#receive_status{timeout_pid=Pid}).
%% 受信プロセス
receive_loop(S) ->
receive
{ping, Ref, Pid} -> % 受信プロセスの生存確認
S2 = S,
Pid ! {pong, Ref};
{wait, Ref, Pid} -> % クライアントが受信待ち
?LOG({wait, Ref, Pid}),
S2 = S#receive_status{pid=Pid, ref=Ref, waiting=true };
{message, Message} -> % メッセージが来た
?LOG({message, Message}),
S2 = S#receive_status{messages=[Message|S#receive_status.messages]}
end,
?LOG(S2),
%% 受信待ち状態かつメッセージがあるときのみ送信します。
case S2 of
#receive_status{waiting=false} -> % 受信待ちではない
?MODULE:receive_loop(S2);
#receive_status{messages=[]} -> % メッセージがない
?MODULE:receive_loop(S2);
_ -> % 受信待ちでメッセージあり
S#receive_status.timeout_pid ! ok, % タイムアウトをリセット
S2#receive_status.pid ! {message, % メッセージ送信
S2#receive_status.ref,
S2#receive_status.messages},
?MODULE:receive_loop(
S2#receive_status{waiting=false, messages=[]})
end.
%% 受信プロセスのタイムアウト管理プロセス
receive_timeout() ->
receive
_ -> % タイムアウトをリセット
receive_timeout()
after
1000 * 60 * 10 -> % 10分で受信プロセスは終了
erlang:exit(timeout)
end.
%% send.yaws から呼ばれます。
send_message(A) ->
?LOG(send_message),
{ok, User} = yaws_api:queryvar(A, "user"),
{ok, Message} = yaws_api:queryvar(A, "message"),
M = timestamp() ++ "(" ++ User ++ ")" ++ Message,
Pids = pg2:get_members(receive_proc_group), % 受信待ちプロセスを取得
%%error_logger:info_msg("~p", [length(Pids)]),
lists:foreach(fun(P) -> P ! {message, M} end, Pids), % 1つずつ送信
%%error_logger:info_msg("finish!", []).
{html, "ok"}.
%% receive.yaws から呼ばれます。
receive_message(A) ->
?LOG(receive_message),
{Pid, Header} = get_receive_proc(A),
Ref = make_ref(),
Pid ! {wait, Ref, self()}, % 待ってるよ、と送信。
receive
{message, Ref, Messages} -> % メッセージ受信。
?LOG({message, Ref, Messages}),
receive_message_response(edit_response(Messages), Header)
after 10 * 60 * 1000 -> % 10分でタイムアウトします。
receive_message_response(
io_lib:format(
"({'st': 'ok', 'mes': '~s メッセージがありません。
'})",
[timestamp()]),
Header)
end.
%% レスポンスの編集を行います。
edit_response(Messages) ->
M = lists:foldl(fun(X, Acc) -> yaws_api:htmlize(X) ++ "
" ++ Acc end,
[], Messages),
f("(~s)", [json:encode({struct, [{st, "ok"}, {mes, M}]})]).
%% クッキーをセットしない場合のレスポンス
receive_message_response(Html, undefined) ->
{html,Html};
%% クッキーをセットする場合のレスポンス
receive_message_response(Html, Header) ->
[{html, Html}, Header].
%% 受信プロセスIDを取得します。
get_receive_proc(A) ->
H = A#arg.headers,
C = H#headers.cookie,
case yaws_api:find_cookie_val(?COOKIE_KEY, C) of
[] ->
create_new_receive_proc();
Cookie ->
case yaws_api:cookieval_to_opaque(Cookie) of
{ok, Pid} ->
case check_receive_proc(Pid) of
ok ->
{Pid, undefined};
_ ->
create_new_receive_proc()
end;
_ ->
create_new_receive_proc()
end
end.
%% 受信プロセスが生きていることを確認します。
check_receive_proc(Pid) ->
Ref = make_ref(),
Pid ! {ping, Ref, self()},
receive
{pong, Ref} ->
ok
after
1000 ->
error
end.
%% 受信プロセスを作成します。
create_new_receive_proc() ->
Pid = spawn(?MODULE, receive_init, [#receive_status{pid=self()}]),
pg2:join(receive_proc_group, Pid), % プロセスグループに参加
Cookie = yaws_api:new_cookie_session(Pid),
{Pid, yaws_api:setcookie(?COOKIE_KEY, Cookie, "/")}.
%% タイムスタンプも欲しいよね。
timestamp() ->
{{_Y, _M, _D}, {H, Mi, S}} = erlang:localtime(),
f("~b:~b:~b", [H, Mi, S]).
%% 文字列化の関数です。
f(Format, Args) ->
lists:flatten(io_lib:format(Format, Args)).
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>チャット</title>
<style>
#screen {
border: 1px solid black;
height: 20em;
overflow: scroll;
}
</style>
<script src="js/prototype.js"></script>
<script>
function debug(x) {
$('debug').innerHTML = x;
}
function send() {
$('message').select();
var param = 'message=' + $F('message') + '&user=' + $F('user');
var ajax = new Ajax.Request(
"send.yaws",
{
method: 'get',
parameters: param
});
}
function receive_call_back(res) {
debug(res.responseText);
eval("var obj = " + res.responseText);
if (obj.st == 'ok') {
$('screen').innerHTML = obj.mes + $('screen').innerHTML;
receive();
} else {
alert("error: " + res.responseText);
}
}
function receive() {
var param = 'user=' + $F('user');
var ajax = new Ajax.Request(
"receive.yaws",
{
method: 'get',
parameters: param,
onComplete: receive_call_back
});
}
Event.observe(window, 'load', receive, false);
</script>
</head>
<body>
<h1>チャット</h1>
<form action="javascript:send()">
名前 <input type="text" id="user"><br>
メッセージ <input type="text" id="message" size="80">
<input type="submit" value="送信">
</form>
<div id="screen"></div>
<hr>
デバッグ
<div id="debug"></div>
</body>
</html>
<erl>
out(Arg) ->
chat:send_message(Arg).
</erl>
<erl>
out(Arg) ->
chat:receive_message(Arg).
</erl>
* soft nofile 50000
* hard nofile 50000
darcsum で最初に record するときの email のデフォルト値。
~/.emacs
(setq user-mail-address "user@example.com")
(setq user-full-name "名前")
Erlang のマクロは C のマクロに似ています。
-define で定義し使用するときは ? を付けます。
モジュール名やファイル名を表す定義済マクロがあります。
定義時にマクロに引数に ?? を付けるとその引数をそのまま文字列として展開します。EUnit で便利に使われています。
-ifdef, -ifndef, -else, -endif で条件付きコンパイルができます。
-module(macro_sample).
-compile(export_all).
-define(MacroValue, "Not Debug!").
-define(MacroPreDef, io:format("MODULE: ~p, MODULE_STRING: ~p, FILE: ~p, LINE: ~p, MACHINE: ~p~n", [?MODULE, ?MODULE_STRING, ?FILE, ?LINE, ?MACHINE])).
-ifdef(debug).
-undef(MacroValue).
-define(MacroValue, "Debug Mode!").
-define(LOG(X), io:format("{~p,~p}: ~s = ~p~n", [?MODULE,?LINE,??X,X])).
-else.
-define(LOG(X), ok).
-endif.
-ifndef(debug).
-define(MM, not_debug).
-else.
-define(MM, debug).
-endif.
main() ->
io:format("~p, ~p~n", [?MacroValue, ?MM]),
?MacroPreDef,
?LOG(1 + 2),
?LOG(begin {H, M, S} = time(), lists:flatten(io_lib:format("~p:~p:~p", [H, M, S])) end).
(emacs@localhost)83> c("/home/ancient/letter/erlang/junk/macro_sample", [{outdir, "/home/ancient/letter/erlang/junk/"}]).
{ok,macro_sample}
(emacs@localhost)84> macro_sample:main().
"Not Debug!", not_debug
MODULE: macro_sample, MODULE_STRING: "macro_sample", FILE: "/home/ancient/letter/erlang/junk/macro_sample.erl", LINE: 24, MACHINE: 'BEAM'
ok
(emacs@localhost)85> c("/home/ancient/letter/erlang/junk/macro_sample", [{outdir, "/home/ancient/letter/erlang/junk/"}, {d, debug}]).
{ok,macro_sample}
(emacs@localhost)86> macro_sample:main().
"Debug Mode!", debug
MODULE: macro_sample, MODULE_STRING: "macro_sample", FILE: "/home/ancient/letter/erlang/junk/macro_sample.erl", LINE: 24, MACHINE: 'BEAM'
{macro_sample,25}: 1 + 2 = 3
{macro_sample,26}: begin { H , M , S } = time ( ) , lists : flatten ( io_lib : format ( "~p:~p:~p" , [ H , M , S ] ) ) end = "5:22:54"
ok
(emacs@localhost)87> c("/home/ancient/letter/erlang/junk/macro_sample", [{outdir, "/home/ancient/letter/erlang/junk/"}, {d, debug}, 'P']).
** Warning: No object file created - nothing loaded **
ok
-file("/home/ancient/letter/erlang/junk/macro_sample.erl", 1).
-module(macro_sample).
-compile(export_all).
main() ->
io:format("~p, ~p~n", ["Debug Mode!",debug]),
io:format("MODULE: ~p, MODULE_STRING: ~p, FILE: ~p, LINE: ~p, MACHI"
"NE: ~p~n",
[macro_sample,
"macro_sample",
"/home/ancient/letter/erlang/junk/macro_sample.erl",
24,
'BEAM']),
io:format("{~p,~p}: ~s = ~p~n", [macro_sample,25,"1 + 2",1 + 2]),
io:format("{~p,~p}: ~s = ~p~n",
[macro_sample,
26,
"begin { H , M , S } = time ( ) , lists : flatten ( io_l"
"ib : format ( \"~p:~p:~p\" , [ H , M , S ] ) ) end",
begin
{H,M,S} = time(),
lists:flatten(io_lib:format("~p:~p:~p", [H,M,S]))
end]).
Common Lisp での次の式は
(unwind-protect (print "protected") (error error))
try erlang:error(error) after io:format("protected") end.
-module(with).
-compile(export_all).
open_file(File, Fun, Mode) ->
{ok, IoDevice} = file:open(File, Mode),
try Fun(IoDevice)
after
file:close(IoDevice)
end.
test() ->
File = "/tmp/a.txt",
open_file(File,
fun(IoDevice) ->
io:write(IoDevice, "Hello")
end,
write),
open_file(File,
fun(IoDevice) ->
io:get_line(IoDevice, "")
end,
read).
はてなから移行しました。
SET PATH=c:\WINDOWS;c:\WINDOWS\system32
install.cmd ALL
C:\Documents and Settings\ancient>SET PATH=C:\Program Files\yaws-1.66;c:\WINDOWS;c:\WINDOWS\system32
C:\Documents and Settings\ancient>yaws -i
Eshell V5.5.2 (abort with ^G)
1>
=INFO REPORT==== 28-Dec-2006::17:19:46 ===
Yaws: Using config file C:/Documents and Settings/ancient/Application Data/yaws-1.66/yaws.conf
1> yaws:Add path "c:/Documents and Settings/ancient/My Documents/yaws/examples/ebin"
1> yaws:Add path "c:/Program Files/yaws-1.66/examples/ebin"
1> yaws:Running with id=undefined
Running with debug checks turned on (slower server)
Logging to directory "c:/Documents and Settings/ancient/My Documents/yaws/log"
1>
=INFO REPORT==== 28-Dec-2006::17:19:47 ===
Yaws: Listening to 0.0.0.0:8000 for servers - http://OUTIS:8000 under c:/Documents and Settings/ancient/My Documents/yaws/www
- http://localhost:8000 under c:/tmp
1>
14> erlyweb:create_app("music", "C:\\apps").
info:erlyweb_util:30: creating "C:\\apps/music"
info:erlyweb_util:30: creating "C:\\apps/music/src"
info:erlyweb_util:30: creating "C:\\apps/music/src/components"
info:erlyweb_util:30: creating "C:\\apps/music/ebin"
info:erlyweb_util:30: creating "C:\\apps/music/www"
info:erlyweb_util:65: creating "C:\\apps/music/src/music_app_view.et"
info:erlyweb_util:65: creating "C:\\apps/music/src/music_app_controller.erl"
info:erlyweb_util:65: creating "C:\\apps/music/www/index.html"
info:erlyweb_util:65: creating "C:\\apps/music/www/style.css"
ok
1> erlyweb:create_component("musician", "/apps/music").
info:erlyweb_util:65: creating "/apps/music/src/components/musician.erl"
info:erlyweb_util:65: creating "/apps/music/src/components/musician_controller.erl"
info:erlyweb_util:65: creating "/apps/music/src/components/musician_view.erl"
ok
2> erlydb:start(mysql, [{hostname, "localhost"}, {username, "root"}, {password, "password"}, {database, "music"}]).
mysql_conn:609: greeting version "5.0.27-community-nt" (protocol 10) salt "N$fV[H7y" caps 41516 serverchar <<95,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>salt2 "}(M,4][0{=\\:"
mysql_auth:187: mysql_auth send packet 1: <<5,162,0,0,64,66,15,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,114,111,111,116,0,20,100,108,48,224,97,31,19,109,153,47,33,191,183,196,29,210,251,67,99,29>>
mysql_conn:418: fetch <<"use music">> (id <0.61.0>)
ok
3> erlyweb:compile("/apps/music", [{erlydb_driver, mysql}]).
debug:erlyweb:114: Compiling app controller: music_app_controller.erl
debug:erlyweb:124: Trying to invoke music_app_controller:before_compile/1
debug:erlyweb:286: Compiling ErlTL file "music_app_view"
debug:erlyweb:289: Compiling Erlang file "music_app_controller"
debug:erlyweb:289: Compiling Erlang file "musician_view"
debug:erlyweb:289: Compiling Erlang file "musician_controller"
debug:erlyweb:289: Compiling Erlang file "musician"
debug:erlyweb:143: Generating ErlyDB code for models: "musician.erl "
mysql_conn:418: fetch <<"show tables">> (id <0.61.0>)
mysql_conn:418: fetch <<"describe musician">> (id <0.61.0>)
debug:erlyweb:166: Trying to invoke music_app_controller:after_compile/1
{ok,{{2006,12,29},{15,17,27}}}
4>
-module(musician).
-module(try_erlydb).
-export([start/0]).
start() ->
erlydb:start(mysql, [{hostname, "localhost"}, {username, "root"}, {password, "password"}, {database, "music"}]),
erlydb:code_gen(mysql, [musician]),
io:format("~p~n", [musician:find({name, '=', "Ringo Star"})]),
io:format("~p~n", [musician:find({name, like, "R%"})]).
1> c("c:/home/ancient/letter/erlang/a/musician", [{outdir, "c:/home/ancient/letter/erlang/a/"}]).
{ok,musician}
2> c("c:/home/ancient/letter/erlang/a/try_erlydb", [{outdir, "c:/home/ancient/letter/erlang/a/"}]).
{ok,try_erlydb}
3> try_erlydb:start().
mysql_conn:609: greeting version "5.0.27-community-nt" (protocol 10) salt "}\\8?tKZc" caps 41516 serverchar <<95,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>salt2 "a@XyxoEI~`G!"
mysql_auth:187: mysql_auth send packet 1: <<5,162,0,0,64,66,15,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,114,111,111,116,0,20,244,135,64,58,95,79,42,15,19,223,3,156,183,234,11,52,19,242,201,53>>
mysql_conn:418: fetch <<"use music">> (id <0.48.0>)
mysql_conn:418: fetch <<"show tables">> (id <0.48.0>)
mysql_conn:418: fetch <<"describe musician">> (id <0.48.0>)
mysql_conn:418: fetch <<"SELECT * FROM musician WHERE (name = 'Ringo Star')">> (id <0.48.0>)
[{musician,false,
4,
<<"Ringo Star">>,
{date,{1940,7,7}},
<<"drums">>,
<<"Richard Starkey, known by his stage name\r\n Ringo Starr, is an English popular musician,\r\n singer, and actor, best known as the\r\n drummer for The Beatles...">>}]
mysql_conn:418: fetch <<"SELECT * FROM musician WHERE (name LIKE 'R%')">> (id <0.48.0>)
[{musician,false,
4,
<<"Ringo Star">>,
{date,{1940,7,7}},
<<"drums">>,
<<"Richard Starkey, known by his stage name\r\n Ringo Starr, is an English popular musician,\r\n singer, and actor, best known as the\r\n drummer for The Beatles...">>}]
ok
(setq inferior-erlang-machine-options
'("-pa" "c:/home/ancient/letter/erlang/lib/oregexp-1.0/ebin"))
15> fun() ->
{ok, R} = oregexp:parse("い(.)", [sjis]),
{matches, [M|_]} = oregexp:scan("あいうえお", R),
oregexp:free(R),
{value, G} = oregexp:group(1, M),
io:format("~s~n", [G])
end().
う
ok
SET PATH=C:\Program Files\yaws-1.66;c:\WINDOWS;c:\WINDOWS\system32
cd C:\Program Files\yaws-1.66
yaws -i
(defun run-yaws ()
(interactive)
(let ((inferior-erlang-machine "C:/Docume~1/ancient/デスクトップ/yaws.bat"))
(run-erlang)))
erlyweb:create_app("blog", "/apps").
create table entries (
id integer auto_increment primary key,
title varchar(100),
body text,
author varchar(100)
);
erlyweb:create_component("entries", "/apps/blog").
-module(blog_start).
-compile(export_all).
boot() ->
boot(true).
boot(false) ->
compile();
boot(true) ->
mysql_start(),
compile().
mysql_start() ->
erlydb:start(mysql, [{hostname, "localhost"},
{username, "root"},
{password, "password"},
{database, "blog"}]).
compile() ->
erlyweb:compile("/apps/blog", [{erlydb_driver, mysql}]).
<server localhost>
port = 8889
listen = 0.0.0.0
docroot = /apps/blog/www
appmods = <"/blog", erlyweb>
<opaque>
appname = blog
</opaque>
</server>
-module(entries_controller).
%%-erlyweb_magic(on).
-export([index/1]).
index(A) ->
Entries = entries:find(), % 全レコード取得
{data, Entries}. % 全レコードをビューへ
-module(entries_view).
%%-erlyweb_magic(on).
-export([index/1]).
index(Data) ->
entries_show:show_entries(Data).
<%@ show_entries(Entries) %>
<div class="entries"><% [entry(E) || E <- Entries] %></div>
<%@ entry(Entry) %>
<div class="entry">
<div class="title"><% helpers:value(entries:title(Entry)) %></div>
<div class="body"><% helpers:value(entries:body(Entry)) %></div>
<div class="author">by: <% helpers:value(entries:author(Entry)) %></div>
</div>
-module(helpers).
-export([value/1]).
value(Val) ->
case Val of
undefined ->
"";
_ ->
Val
end.
div.entry {
margin: 0.25em 0.25em 0.25em 0.25em;
padding: 0.25em 0.25em 0.25em 0.25em;
}
div.title {
font-weight: bold;
}
div.author {
font-style: italic;
}
-module(helpers).
-export([value/1, validate/3]).
value(Val) ->
case Val of
undefined ->
"";
_ ->
Val
end.
validate(ValidatorModule, Model, Item) ->
Fields = Model:use_fields(),
Results = [ValidatorModule:Field(Model:Field(Item)) || Field <- Fields],
Errors = [Error || Error <- Results,
element(1, Error) == error],
case Errors of
[] ->
ok;
_ ->
Errors
end.
-module(entries_controller).
%%-erlyweb_magic(on).
-export([index/1, new/1, new_get/0, new_post/1]).
index(_A) ->
Entries = entries:find(), % 全レコード取得
{data, Entries}. % 全レコードをビューへ
new(A) ->
case yaws_arg:method(A) of
'GET' ->
{data, {[], new_get()}};
'POST' ->
Vals = yaws_api:parse_post(A),
{Errors, Entry} = new_post(Vals),
case Errors of
ok ->
{ewr, index};
_ ->
{data, {Errors, Entry}}
end
end.
new_get() ->
Entry = entries:new(),
Entry.
new_post(Vals) ->
Entry = entries:set_fields_from_strs(entries:new(), Vals),
Errors = helpers:validate(entries_validate, entries, Entry),
case Errors of
ok ->
entries:save(Entry),
{ok, Entry};
_ ->
{Errors, Entry}
end.
-module(entries_validate).
-export([title/1, body/1, author/1]).
title(undefined) ->
{error, title, "The title field is blank."};
title(_) ->
ok.
body(undefined) ->
{error, body, "The body field is blank."};
body(_) ->
ok.
author(undefined) ->
{error, author, "The author field is blank."};
author(_) ->
ok.
-module(entries).
-export([use_fields/0]).
use_fields() ->
[title, body, author].
-module(entries_view).
%%-erlyweb_magic(on).
-export([index/1, new/1]).
index(Data) ->
entries_show:show_entries(Data).
new(Data) ->
entries_show:display_form(Data).
<%@ show_entries(Entries) %>
<div class="entries"><% [entry(E) || E <- Entries] %></div>
<%@ entry(Entry) %>
<div class="entry">
<div class="title"><% helpers:value(entries:title(Entry)) %></div>
<div class="body"><% helpers:value(entries:body(Entry)) %></div>
<div class="author">by: <% helpers:value(entries:author(Entry)) %></div>
</div>
<%@ display_form(Items) %>
<%? {Errors, Data} = Items %>
<% helpers_html:show_errors(Errors) %>
<form action="new" method="post">
<table>
<tr>
<th>Title:</th>
<td><% erlyweb_html:input("title", text_field, undefined,
helpers:value(entries:title(Data))) %></td>
</tr>
<tr>
<th>Body:</th>
<td><% erlyweb_html:input("body", text_field, undefined,
helpers:value(entries:body(Data))) %></td>
</tr>
<tr>
<th>Author:</th>
<td><% erlyweb_html:input("author", text_field, undefined,
helpers:value(entries:author(Data))) %></td>
</tr>
<tr>
<td colspan="2"><input type="submit"></td>
</tr>
</table>
</form>
<%@ show_errors(Errors) %>
<ul>
<% [error(E) || E <- Errors] %>
</ul>
<%@ error({error, _Field, Message}) %>
<li><% Message %></li>
<html>
<body>
<div>あいう</div>
<erl>
out(Arg) ->
{html, "<div>ばのびの</div>"}.
</erl>
<erl>
out(Arg) ->
{ehtml, {table, [{border, 1}, {bgcolor, green}],
[{tr, [],
[{td, [], "こんにちは"},
{td, [], "Hello"}]}]}}.
</erl>
<erl>
out(Arg) ->
{html, io_lib:format("<pre>~p</pre>", [Arg])}.
</erl>
</body>
</html>
{html, p("<pre>~p</pre>", [Arg])}.
<html>
<body>
<erl>
out(Arg) ->
{html, f("<pre>~p</pre>", [yaws_api:parse_query(Arg)])}.
</erl>
</body>
</html>
<html>
<body>
<form method="post">
<input type="text" name="c">
<input type="text" name="cc">
<input type="submit">
<erl>
out(Arg) ->
{html, f("<pre>~p</pre>", [yaws_api:parse_post(Arg)])}.
</erl>
</body>
</html>
new_post(Vals) ->
Entry = entries:new(),
new_or_edit(Entry, Vals).
new_or_edit(Entry, Vals) ->
EntryV = entries:set_fields_from_strs(Entry, Vals),
Errors = helpers:validate(entries_validate, entries, EntryV),
case Errors of
ok ->
entries:save(EntryV),
{ok, Entry};
_ ->
{Errors, EntryV}
end.
edit(A, Id) ->
case yaws_arg:method(A) of
'GET' ->
{data, {"", edit_get(Id)}};
'POST' ->
Vals = yaws_api:parse_post(A),
{Errors, Entry} = edit_post(Vals, Id),
case Errors of
ok ->
{ewr, entries, index};
_ ->
{data, {Errors, Entry}}
end
end.
edit_get(Id) ->
Entry = entries:find_id(Id),
Entry.
edit_post(Vals, Id) ->
Entry = entries:find_id(Id),
new_or_edit(Entry, Vals).
form_process(A,
GetAction,
ModelAction,
PostSuccessAction,
PostFailureAction) ->
case yaws_arg:method(A) of
'GET' ->
GetAction();
'POST' ->
Vals = yaws_api:parse_post(A),
{Errors, Record} = ModelAction(Vals),
case Errors of
ok ->
PostSuccessAction();
_ ->
PostFailureAction(Errors, Record)
end
end.
new(A) ->
GetAction = fun() -> {data, {[], new_get()}} end,
ModelAction = fun(Vals) -> new_post(Vals) end,
PostSuccessAction = fun() -> {ewr, entries, index} end,
PostFailureAction = fun(Errors, Entry) -> {data, {Errors, Entry}} end,
form_process(A, GetAction, ModelAction,
PostSuccessAction, PostFailureAction).
edit(A, Id) ->
GetAction = fun() -> {data, {"", edit_get(Id)}} end,
ModelAction = fun(Vals) -> edit_post(Vals, Id) end,
PostSuccessAction = fun() -> {ewr, entries, index} end,
PostFailureAction = fun(Errors, Entry) -> {data, {Errors, Entry}} end,
form_process(A, GetAction, ModelAction,
PostSuccessAction, PostFailureAction).
new(Data) ->
entry_form:display_form(Data, "../new", "").
edit({Errors, Entry}) ->
entry_form:display_form({Errors, Entry}, "../edit",
integer_to_list(entries:id(Entry))).
<%@ display_form(Items, GoTo, Id) %>
<%? {Errors, Data} = Items %>
<% helpers_html:show_errors(Errors) %>
<form action="<% GoTo %>/<% Id %>" method="post">
<table>
<tr>
<th>Title:</th>
<td><% erlyweb_html:input("title", text_field, undefined,
helpers:value(entries:title(Data))) %></td>
</tr>
<tr>
<th>Body:</th>
<td><% erlyweb_html:input("body", text_field, undefined,
helpers:value(entries:body(Data))) %></td>
</tr>
<tr>
<th>Author:</th>
<td><% erlyweb_html:input("author", text_field, undefined,
helpers:value(entries:author(Data))) %></td>
</tr>
<tr>
<td colspan="2"><input type="submit"></td>
</tr>
</table>
</form>
view(_A, Id) ->
Entry = entries:find_id(Id),
{data, Entry}.
view(Data) ->
entry_view:view(Data).
<%@ view(Data) %>
<b><% entries:title(Data) %></b>
<br><br>
<% entries:body(Data) %>
<br>
<i>by: <% entries:author(Data) %></i>
<br><br>
<% erlyweb_html:a(["../edit", integer_to_list(entries:id(Data))],
"Edit Entry") %>
<%@ entry(Entry) %>
<div class="entry">
<div class="title"><% helpers:value(entries:title(Entry)) %></div>
<div class="body"><% helpers:value(entries:body(Entry)) %></div>
<div class="author">by: <% helpers:value(entries:author(Entry)) %></div>
<div class="view"><% erlyweb_html:a(["view",
integer_to_list(entries:id(Entry))],
"view") %></div>
</div>
#include <memory.h>
#include <errno.h>
#include "erl_driver.h"
#include "iconv.h"
typedef struct {
ErlDrvPort port;
} Self;
static ErlDrvData start(ErlDrvPort port, char *command);
static void stop(ErlDrvData drv_data);
static void output(ErlDrvData drv_data, char *buf, int len);
static void send_value(Self* self, ErlDrvBinary* bin, int size);
static void send_error(Self* self, ErlDrvTermData* error);
#define OUTBUFSIZ 1024
#define OK 0
#define INVALID_ENCODE 1
#define OUT_OF_MEMORY 2
static ErlDrvEntry anErlDrvEntry = {
NULL,
start,
stop,
output, /* output */
NULL, /* ready_input */
NULL, /* ready_output */
"eliconv", /* driver name */
NULL, /* finish */
NULL, /* handle */
NULL, /* control */
NULL, /* timeout */
NULL, /* outputv */
NULL, /* ready_async */
NULL, /* flush */
NULL, /* call */
NULL /* event */
};
static ErlDrvTermData atom_value;
static ErlDrvTermData atom_error;
static ErlDrvTermData atom_invalid_encode;
static ErlDrvTermData atom_out_of_memory;
DRIVER_INIT(eliconv) {
atom_value = driver_mk_atom("value");
atom_error = driver_mk_atom("error");
atom_invalid_encode = driver_mk_atom("invalid_encode");
atom_out_of_memory = driver_mk_atom("out_of_memory");
return &anErlDrvEntry;
}
static ErlDrvData start(ErlDrvPort port, char *command) {
Self* self = NULL;
self = (Self*)driver_alloc(sizeof(Self));
self->port = port;
return (ErlDrvData)self;
}
static void stop(ErlDrvData drv_data) {
driver_free(drv_data);
}
static void output(ErlDrvData drv_data, char *buf, int len) {
Self* self = (Self*)drv_data;
ErlDrvBinary* bin;
char* outbuf;
size_t outbytesleft;
const char* tocode = buf;
int tocode_len = strlen(tocode);
const char* fromcode = &buf[tocode_len + 1];
int fromcode_len = strlen(fromcode);
int to_from_len = tocode_len + 1 + fromcode_len + 1;
const char* inbuf = &buf[to_from_len];
size_t inbytesleft = len - to_from_len;
int out_size = 0;
iconv_t cd = iconv_open(tocode, fromcode);
if (cd == (iconv_t)-1) {
send_error(self, &atom_invalid_encode);
return;
}
bin = driver_alloc_binary(OUTBUFSIZ);
if (bin == NULL) {
send_error(self, &atom_out_of_memory);
return;
}
outbytesleft = OUTBUFSIZ;
outbuf = bin->orig_bytes;
while(1) {
size_t ret = iconv(cd, &inbuf, &inbytesleft,
&outbuf, &outbytesleft);
if (ret == -1) {
if (errno == E2BIG) {
out_size += OUTBUFSIZ - outbytesleft;
bin = driver_realloc_binary(bin, out_size + OUTBUFSIZ);
if (bin == NULL) {
send_error(self, &atom_out_of_memory);
return;
}
outbuf = bin->orig_bytes + out_size;
outbytesleft = OUTBUFSIZ;
continue;
}
--inbytesleft;
++inbuf;
continue;
}
out_size += OUTBUFSIZ - outbytesleft;
break;
}
send_value(self, bin, out_size);
driver_free_binary(bin);
iconv_close(cd);
}
void send_value(Self* self, ErlDrvBinary* bin, int size) {
/* {Port, value, Bin} */
ErlDrvTermData spec[] = {
ERL_DRV_PORT, driver_mk_port(self->port),
ERL_DRV_ATOM, atom_value,
ERL_DRV_BINARY, (ErlDrvTermData)bin, size, 0,
ERL_DRV_TUPLE, 3
};
driver_send_term(self->port, driver_caller(self->port),
spec, sizeof(spec)/sizeof(spec[0]));
}
void send_error(Self* self, ErlDrvTermData* error) {
/* {Port, error, Error} */
ErlDrvTermData spec[] = {
ERL_DRV_PORT, driver_mk_port(self->port),
ERL_DRV_ATOM, atom_error,
ERL_DRV_ATOM, *error,
ERL_DRV_TUPLE, 3
};
driver_send_term(self->port, driver_caller(self->port),
spec, sizeof(spec)/sizeof(spec[0]));
}
all:
gcc -mno-cygwin -shared -Wall -o ../priv/lib/win32/eliconv.dll -I. -I"c:/Program Files/erl5.5.2/erts-5.5.2/include" -L. eliconv.c -liconv
%%%-------------------------------------------------------------------
%%% File : eliconv_server.erl
%%% Author :
%%% Description : eliconv
%%%
%%% Created : 7 Jan 2007 by Yoshinori Tahara <read.eval.print@gmail.com>
%%%-------------------------------------------------------------------
-module(eliconv_server).
-behaviour(gen_server).
%% API
-export([start_link/0]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-record(state, {port}).
-define(SERVER, ?MODULE).
%%====================================================================
%% API
%%====================================================================
%%--------------------------------------------------------------------
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
%% Description: Starts the server
%%--------------------------------------------------------------------
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
%%====================================================================
%% gen_server callbacks
%%====================================================================
%%--------------------------------------------------------------------
%% Function: init(Args) -> {ok, State} |
%% {ok, State, Timeout} |
%% ignore |
%% {stop, Reason}
%% Description: Initiates the server
%%--------------------------------------------------------------------
init([]) ->
Arch = erlang:system_info(system_architecture),
Libs = filename:join([code:priv_dir(eliconv), "lib", Arch]),
ok = erl_ddll:load_driver(Libs, "eliconv"),
Port = open_port({spawn, "eliconv"}, []),
{ok, #state{port = Port}}.
%%--------------------------------------------------------------------
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
%% {reply, Reply, State, Timeout} |
%% {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, Reply, State} |
%% {stop, Reason, State}
%% Description: Handling call messages
%%--------------------------------------------------------------------
handle_call({ToEncode, FromEncode, Src}, _From, State) ->
Reply = do(State#state.port, ToEncode, FromEncode, Src),
{reply, Reply, State}.
%%--------------------------------------------------------------------
%% Function: handle_cast(Msg, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% Description: Handling cast messages
%%--------------------------------------------------------------------
handle_cast(stop, State) ->
{stop, normal, State};
handle_cast(_Msg, State) ->
{noreply, State}.
%%--------------------------------------------------------------------
%% Function: handle_info(Info, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% Description: Handling all non call/cast messages
%%--------------------------------------------------------------------
handle_info(_Info, State) ->
{noreply, State}.
%%--------------------------------------------------------------------
%% Function: terminate(Reason, State) -> void()
%% Description: This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any necessary
%% cleaning up. When it returns, the gen_server terminates with Reason.
%% The return value is ignored.
%%--------------------------------------------------------------------
terminate(_Reason, State) ->
Port = State#state.port,
Port ! {self(), close},
receive
{Port, closed} ->
ok;
_ ->
io:format("close failed.~n")
after
1000 ->
io:format("close timeout.~n")
end,
erl_ddll:unload_driver("eliconv"),
ok.
%%--------------------------------------------------------------------
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
%% Description: Convert process state when code is changed
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
do(Port, ToEndoce, FromEncode, String) when list(String) ->
do(Port, ToEndoce, FromEncode, list_to_binary(String));
do(Port, ToEndoce, FromEncode, Binary) when binary(Binary) ->
To = list_to_binary(ToEndoce),
From = list_to_binary(FromEncode),
Port ! {self(),
{command, <<To/binary, 0, From/binary, 0, Binary/binary>>}},
receive
{Port, Result, Data} ->
Reply = {Result, Data}
end,
Reply.
% eliconv:start_link().
% gen_server:call(eliconv_server, {"UTF-8", "CP932", "あいうえお"}).
% gen_server:cast(eliconv_server, stop).
%%%-------------------------------------------------------------------
%%% File : eliconv.erl
%%% Author :
%%% Description : eliconv
%%%
%%% Created : 8 Jan 2007 by Yoshinori Tahara <read.eval.print@gmail.com>
%%%-------------------------------------------------------------------
-module(eliconv).
%% API
-export([do/3, start/0, stop/0]).
-define(SERVER, eliconv_server).
%%====================================================================
%% API
%%====================================================================
%%--------------------------------------------------------------------
%% Function:
%% Description:
%%--------------------------------------------------------------------
do(ToEncode, FromEncode, BinaryOrString) ->
case erlang:whereis(?SERVER) of
undefined ->
io:format("start server...~n"),
start();
_ ->
ok
end,
gen_server:call(?SERVER, {ToEncode, FromEncode, BinaryOrString}).
start() ->
eliconv_server:start_link().
stop() ->
gen_server:cast(?SERVER, stop).
%%====================================================================
%% Internal functions
%%====================================================================
1> eliconv:do("UTF-8", "CP932", "あいう").
start server...
{value,<<227,129,130,227,129,132,227,129,134>>}
2>
1> {A,B,C,D} = {192,168,2,3},
<<IPDecimal:32>> = <<A:8,B:8,C:8,D:8>>.
<<192,168,2,3>>
2> IPDecimal.
3232236035
fun(Url) ->
{ok, {_Code, _Head, Body}} = http:request(Url),
io:format("~s~n", [Body]),
string:str(Body, "検索")
end("http://www.google.co.jp").
1> X = 1.
1
2> Y = 1.
1
3> X = 1.
1
4> X = Y.
1
5> X = 2.
=ERROR REPORT==== 18-Mar-2007::15:40:21 ===
Error in process <0.29.0> with exit value: {{badmatch,2},[{erl_eval,expr,3}]}exited: {{badmatch,2},[{erl_eval,expr,3}]} **
-module(fib_mp).
-export([main/1, fib/1]).
main(N) ->
start(N),
start(N).
start(N) ->
spawn(?MODULE, fib, [N]).
fib(1) ->
1;
fib(2) ->
1;
fib(N) ->
fib(N - 1) + fib(N - 2).
;;;; Erlang
(setq load-path (cons "C:/Program Files/erl5.5.2/lib/tools-2.5.2/emacs"
load-path))
(setq erlang-root-dir "C:/Program Files/erl5.5.2")
(setq exec-path (cons "C:/Program Files/erl5.5.2/bin" exec-path))
(setq inferior-erlang-machine-options
'("-smp" "auto"
"-mnesia" "dir" "\"/tmp/mnesia\""
"-pa" "c:/home/ancient/letter/erlang/lib/oregexp-1.0/ebin"
"-pa" "c:/home/ancient/letter/erlang/eliconv-1.0/ebin"))
(require 'erlang-start)
(defun run-yaws ()
(interactive)
(let ((inferior-erlang-machine "C:/Progra~1/yaws-1.66/run_yaws.bat"))
(run-erlang)))
sudo port install yaws
~% cd /opt/local/etc
/opt/local/etc% cp yaws.conf.template yaws.conf
<server Macintosh.local>
port = 4080 # 80番から書換えた
listen = 0.0.0.0
docroot = /opt/local/var/yaws/www
</server>
<server localhost>
port = 4080 # 80番から書換えた
listen = 0.0.0.0
docroot = /opt/local/tmp
dir_listings = true
dav = true
<auth>
realm = foobar
dir = /
user = foo:bar
user = baz:bar
</auth>
</server>
# And then an ssl server
<server Macintosh.local>
port = 4443 # 443番から書換えた
docroot = /opt/local/tmp
listen = 0.0.0.0
dir_listings = true
<ssl>
keyfile = /opt/local/etc/yaws-key.pem
certfile = /opt/local/etc/yaws-cert.pem
</ssl>
</server>
/opt/local/etc% mkdir /opt/local/tmp
/opt/local/etc% yaws -i
Erlang (BEAM) emulator version 5.5.3 [source] [async-threads:0] [hipe]
Eshell V5.5.3 (abort with ^G)
1>
=INFO REPORT==== 21-Mar-2007::15:06:04 ===
Yaws: Using config file ./yaws.conf
yaws:Add path "/opt/local/lib/yaws/ebin"
yaws:Add path "/opt/local/lib/yaws/examples/ebin"
yaws:Running with id=default
Running with debug checks turned on (slower server)
Logging to directory "/opt/local/var/log/yaws"
=INFO REPORT==== 21-Mar-2007::15:06:04 ===
Yaws: Listening to 0.0.0.0:4443 for servers
- https://Macintosh.local:4443 under /opt/local/tmp
=INFO REPORT==== 21-Mar-2007::15:06:04 ===
Yaws: Listening to 0.0.0.0:4080 for servers
- http://Macintosh.local:4080 under /opt/local/var/yaws/www
- http://localhost:4080 under /opt/local/tmp
-export([f1/0, f2/0, f3/1, ...]).
-compile(export_all).
-include_lib("xxx.hrl").
#!/usr/bin/env escript
main(_) ->
io:format("Hello world\n").
#!/usr/bin/env escript
-include_lib("kernel/include/file.hrl").
main([Dir]) ->
{ok, FileList} = (file:list_dir(Dir)),
f(Dir, FileList).
f(Dir, [H|T]) ->
File = filename:absname_join(Dir, H),
{ok, FileInfo} = file:read_file_info(File),
p(H, FileInfo),
f(Dir, T);
f(_, _) ->
ok.
p(File, #file_info{type = regular, size = Size}) ->
io:format("~s is file(size: ~b).~n", [File, Size]);
p(Dir, #file_info{type = directory}) ->
io:format("~s is directory.~n", [Dir]).
escript a.erl /
WINDOWS is directory.
usr is directory.
tmp is directory.
TEMP is directory.
System Volume Information is directory.
sqmnoopt01.sqm is file(size: 244).
sqmnoopt00.sqm is file(size: 244).
sqmdata01.sqm is file(size: 280).
sqmdata00.sqm is file(size: 268).
RECYCLER is directory.
Program Files is directory.
pagefile.sys is file(size: 1598029824).
ntldr is file(size: 260272).
NTDETECT.COM is file(size: 47564).
My Squeak is directory.
MSDOS.SYS is file(size: 0).
meadow is directory.
IO.SYS is file(size: 0).
home is directory.
hiberfil.sys is file(size: 1063088128).
Drivers is directory.
Documents and Settings is directory.
delus.bat is file(size: 171).
DAVINCI_CODE_3 is directory.
DAVINCI_CODE_1 is directory.
cygwin is directory.
CONFIG.SYS is file(size: 0).
bootfont.bin is file(size: 132398).
boot.ini is file(size: 199).
AVG7QT.DAT is file(size: 12442353).
AVG7DB_F.DAT is file(size: 19051770).
AUTOEXEC.BAT is file(size: 0).
apps is directory.
AliceSoft is directory.
$VAULT$.AVG is directory.
<server localhost>
port = 4480
listen = 0.0.0.0
docroot = /var/www/yaws-default
# ユーザ毎のウェブディレクトリを有効に
tilde_expand = true
</server>
# バーチャルホスト
<server erlang.localhost>
port = 4480
listen = 0.0.0.0
docroot = /home/ancient/public_html/erlang
</server>
code:add_pathz("/home/ancient/letter/erlang/distel/ebin").
export ERL_COMPILER_OPTIONS='[debug_info,{parse_transform,internal_exports}]'
svn checkout http://distel.googlecode.com/svn/trunk/ distel
./configure
make
code:add_pathz("/home/ancient/letter/erlang/distel/ebin").
;;;;Erlang
(setq inferior-erlang-machine-options
'("-smp" "auto"
"-mnesia" "dir" "\"/tmp/mnesia\""
"-sname" "emacs"
;;"-pa" "c:/home/ancient/letter/erlang/lib/oregexp-1.0/ebin"
;;"-pa" "c:/home/ancient/letter/erlang/eliconv-1.0/ebin"
))
;;;;Distel
(add-to-list 'load-path "/home/ancient/letter/erlang/distel/elisp")
(require 'distel)
(distel-setup)
(setq erl-nodename-cache
(make-symbol
(concat
"emacs@"
;; Mac OS X uses "name.local" instead of "name", this should work
;; pretty much anywhere without having to muck with NetInfo
;; ... but I only tested it on Mac OS X.
(car (split-string (shell-command-to-string "hostname"))))))
(define-key erlang-extended-mode-map "\C-c\C-i" 'erl-complete)
%%% Welcome to the Distel Interactive Erlang Shell.
%%
%% C-j evaluates an expression and prints the result in-line.
%% C-M-x evaluates a whole function definition.
1 + 2.
--> 3
hello() ->
io:format("Hello~n").
hello().Hello
--> ok
(emacs@localhost)1> yaws:start_embedded("/home/ancient/public_html").
=INFO REPORT==== 11-Apr-2007::21:36:48 ===
Yaws: Listening to 127.0.0.1:8000 for servers
- http://localhost:8000 under /home/ancient/public_html
ok
#!/usr/bin/env escript
main(_) ->
{ok, Ftp} = ftp:open("www.example.com"),
ftp:user(Ftp, "user", "password"),
ftp:cd(Ftp, "/public_html"),
lists:foreach(fun(File) ->
ftp:send(Ftp, File)
end,
["index.html","main.css"]),
ftp:close(Ftp).
set HTTP_PROXY=proxy.example.com:8080
cean:proxy_user("user", "password").
cean:install("tools").
;;;; Erlang
(add-path "~/local/opt/cean/erlang/lib/tools-2.5.4/emacs")
(setq erlang-root-dir "~/local/opt/cean/erlang/erts-5.5.4")
(setq exec-path (cons "~/local/opt/cean/erlang/erts-5.5.4/windows/bin" exec-path))
(require 'erlang-start)
[erlang]
Bindir=C:/home/ancient/local/opt/cean/erlang/erts-5.5.4/windows/bin
Progname=erl
Rootdir=C:/home/ancient/local/opt/cean/erlang
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>最初のページ</title>
</head>
<body>
<h1>最初のページ</h1>
<erl>
out(Arg) ->
{{Y, M, D}, {H, Mi, S}} = erlang:localtime(),
{html, f("今は~b年~b月~b日~b時~b分~b秒です。", [Y, M, D, H, Mi, S])}.
</erl>
</body>
</html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>EHTMLの例1</title>
</head>
<body>
<h1>EHTMLの例1</h1>
<erl>
out(Arg) ->
{{Y, M, D}, {H, Mi, S}} = erlang:localtime(),
{ehtml, [{pre, [], "テーブルです。"},
{table, [{border, 1}, {bgcolor, grey}],
[{tr, [],
lists:map(fun(X) -> {th, [], X} end,
["年","月","日","時","分","秒"])},
{tr, [],
lists:map(fun(X) -> {td, [], integer_to_list(X)} end,
[Y, M, D, H, Mi, S])}]}]}.
</erl>
</body>
</html>
(emacs@localhost)1> {_Module, Beam, _File} = code:get_object_code(base64),
(emacs@localhost)1> {ok,{_,[{abstract_code,{_,AC}}]}} = beam_lib:chunks(Beam, [abstract_code]),
(emacs@localhost)1> io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).
-file("./base64.erl", 1).
-module(base64).
-export([encode/1, decode/1, mime_decode/1,
encode_to_string/1, decode_to_string/1,
mime_decode_to_string/1]).
encode_to_string(Bin) when is_binary(Bin) ->
encode_to_string(binary_to_list(Bin));
encode_to_string(List) when is_list(List) ->
encode_l(List).
encode(Bin) when is_binary(Bin), size(Bin) > 24000 ->
{A, B} = split_binary(Bin, 24000),
L = encode_l(binary_to_list(A)),
list_to_binary([L, encode(B)]);
encode(Bin) when is_binary(Bin) ->
encode(binary_to_list(Bin));
encode(List) when is_list(List) ->
list_to_binary(encode_l(List)).
encode_l(List) -> encode(List, encode_tuple()).
encode([], _T) -> [];
encode([A], T) ->
[b64e(A bsr 2, T), b64e(A band 3 bsl 4, T), $=, $=];
encode([A, B], T) ->
[b64e(A bsr 2, T),
b64e(A band 3 bsl 4 bor (B bsr 4), T),
b64e(B band 15 bsl 2, T), $=];
encode([A, B, C | Ls], T) ->
BB = A bsl 16 bor (B bsl 8) bor C,
[b64e(BB bsr 18, T), b64e((BB bsr 12) band 63, T),
b64e((BB bsr 6) band 63, T), b64e(BB band 63, T)
| encode(Ls, T)].
decode(Bin) when is_binary(Bin), size(Bin) > 24000 ->
{A, B} = split_binary(Bin, 24000),
L = decode_l(binary_to_list(A)),
list_to_binary([L, decode(B)]);
decode(Bin) when is_binary(Bin) ->
decode(binary_to_list(Bin));
decode(List) when is_list(List) ->
list_to_binary(decode_l(List)).
mime_decode(Bin)
when is_binary(Bin), size(Bin) > 24000 ->
{A, B} = split_binary(Bin, 24000),
L = mime_decode_l(binary_to_list(A)),
list_to_binary([L, mime_decode(B)]);
mime_decode(Bin) when is_binary(Bin) ->
mime_decode(binary_to_list(Bin));
mime_decode(List) when is_list(List) ->
list_to_binary(mime_decode_l(List)).
decode_l(List) ->
L = strip_spaces(List, []),
decode(L, decode_tuple(), []).
mime_decode_l(List) ->
L = strip_illegal(List, []),
decode(L, decode_tuple(), []).
decode_to_string(Bin) when is_binary(Bin) ->
decode_to_string(binary_to_list(Bin));
decode_to_string(List) when is_list(List) ->
decode_l(List).
mime_decode_to_string(Bin) when is_binary(Bin) ->
mime_decode_to_string(binary_to_list(Bin));
mime_decode_to_string(List) when is_list(List) ->
mime_decode_l(List).
decode([], _T, A) -> A;
decode([$=, $=, C2, C1 | Cs], T, A) ->
Bits2x6 = b64d(C1, T) bsl 18 bor (b64d(C2, T) bsl 12),
Octet1 = Bits2x6 bsr 16,
decode(Cs, T, [Octet1 | A]);
decode([$=, C3, C2, C1 | Cs], T, A) ->
Bits3x6 = b64d(C1, T) bsl 18 bor (b64d(C2, T) bsl 12)
bor (b64d(C3, T) bsl 6),
Octet1 = Bits3x6 bsr 16,
Octet2 = (Bits3x6 bsr 8) band 255,
decode(Cs, T, [Octet1, Octet2 | A]);
decode([C4, C3, C2, C1 | Cs], T, A) ->
Bits4x6 = b64d(C1, T) bsl 18 bor (b64d(C2, T) bsl 12)
bor (b64d(C3, T) bsl 6)
bor b64d(C4, T),
Octet1 = Bits4x6 bsr 16,
Octet2 = (Bits4x6 bsr 8) band 255,
Octet3 = Bits4x6 band 255,
decode(Cs, T, [Octet1, Octet2, Octet3 | A]).
strip_spaces([], A) -> A;
strip_spaces([$=, C | _], A) when C =/= $= -> [$=, A];
strip_spaces([$\s | Cs], A) -> strip_spaces(Cs, A);
strip_spaces([$\t | Cs], A) -> strip_spaces(Cs, A);
strip_spaces([$\r | Cs], A) -> strip_spaces(Cs, A);
strip_spaces([$\n | Cs], A) -> strip_spaces(Cs, A);
strip_spaces([C | Cs], A) -> strip_spaces(Cs, [C | A]).
strip_illegal([], A) -> A;
strip_illegal([C | Cs], A) when C >= $A, C =< $Z ->
strip_illegal(Cs, [C | A]);
strip_illegal([C | Cs], A) when C >= $a, C =< $z ->
strip_illegal(Cs, [C | A]);
strip_illegal([C | Cs], A) when C >= $0, C =< $9 ->
strip_illegal(Cs, [C | A]);
strip_illegal([$=, C | _], A) when C =/= $= -> [$= | A];
strip_illegal([C | Cs], A)
when C =:= $+; C =:= $/; C =:= $= ->
strip_illegal(Cs, [C | A]);
strip_illegal([_ | Cs], A) -> strip_illegal(Cs, A).
encode_tuple() ->
{$A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, $L, $M, $N,
$O, $P, $Q, $R, $S, $T, $U, $V, $W, $X, $Y, $Z, $a, $b,
$c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p,
$q, $r, $s, $t, $u, $v, $w, $x, $y, $z, $0, $1, $2, $3,
$4, $5, $6, $7, $8, $9, $+, $/}.
decode_tuple() ->
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60,
61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1}.
b64e(X, T) -> element(X + 1, T).
b64d(X, T) -> b64d_ok(element(X, T)).
b64d_ok(N) when N >= 0 -> N.
ok
test_smerl() ->
M1 = smerl:new(foo),
{ok, M2} = smerl:add_func(M1, "bar() -> 1 + 1."),
smerl:compile(M2),
foo:bar(), % returns 2``
smerl:has_func(M2, bar, 0). % returns true
fun() ->
M0 = smerl:new(foo),
{ok, M1} = smerl:add_func(M0,
"hello(X) -> io:format(\"<~s>~n\", [X])."),
{ok, M2} = smerl:add_func(M1, "barbar(X, Y) -> X * Y.")
end().
smerl:get_module(foo).
smerl:to_src(element(2, smerl:for_file("/tmp/fib.erl"))).
Consider the following module:
-module(gen_keyvals).
-export([mod/3]).
mod(Mod, Function, Vals) when is_atom(Mod), is_atom(Function) ->
[{attribute, 1, module, Mod},
{attribute, 1, export, [{Function, 1}]},
gen_function(Function, Vals)].
gen_function(F, Vals) ->
{function, 1, F, 1,
[{clause, 1, [{atom, 1, K}], [],
[erl_parse:abstract(V)]} ||
{K,V} <- Vals]}.
An example:
Eshell V5.5.3.1 (abort with ^G)
1> c(gen_keyvals).
{ok,gen_keyvals}
2> gen_keyvals:mod(m,foo,[{a,1},{b,2},{c,3}]).
[{attribute,1,module,m},
{attribute,1,export,[{foo,1}]},
{function,1,
foo,
1,
[{clause,1,[{atom,1,a}],[],[{integer,0,1}]},
{clause,1,[{atom,1,b}],[],[{integer,0,2}]},
{clause,1,[{atom,1,c}],[],[{integer,0,3}]}]}]
3> compile:forms(v(2)).
{ok,m,
<<70,79,82,49,0,0,1,184,66,69,65,77,65,116,111,109,0,0,0,51,0,0,0,8,1,10
9,
...>>}
4> code:load_binary(m,"m.beam",element(3,v(3))).
{module,m}
5> m:foo(a).
1
6> m:foo(c).
3
If you want the generated code in a .erl file, this is
also easily accomplished:
9> [erl_pp:form(F) || F <- v(2)].
[[[[[[45,"module"]],[[40,[["m"],41]]]],".\n"]],
[[[["-export"],[[40,[[91,[[["foo",47,"1"]],93]],41]]]],".\n"]],
[[[[[[["foo",[[40,["a",41]]]]]," ->"],["\n ",["1",59]]],
[10,[[[["foo",[[40,["b",41]]]]]," ->"],["\n ",["2",59]]]],
[10,[[[["foo",[[40,["c",41]]]]]," ->"],["\n ",["3"]]]]],
".\n"]]]
10> io:format("~s~n", [v(9)]).
-module(m).
-export([foo/1]).
foo(a) ->
1;
foo(b) ->
2;
foo(c) ->
3.
1> [1|2].
[1|2]
2> tl([1|2]).
2
3> hd([1|2]).
1
{'*', [debug_info]}.
3> make:all().
Recompile: lisp_repl
Recompile: lisp_reader
Recompile: lisp_machine
Recompile: lisp_eval
Recompile: lisp_env
Recompile: lisp_bim
Recompile: lisp_bif
up_to_date
(emacs@localhost)75> fun erlang:tuple_to_list/1({1,2}).
[1,2]
(emacs@localhost)76> lists:map(fun erlang:size/1, [{1, 2}, {}]).
[2,0]
io:format("~p~n", [Term]).
erlang:display(Term).
(emacs@localhost)21> erlang:fun_info(fun erlang:display/1).
[{module,erlang},{name,display},{arity,1},{env,[]},{type,external}]
(emacs@localhost)22> fun() -> X = 1, Y = fun(Y) -> X + Y end, erlang:fun_info(Y) end().
[{pid,<0.59.0>},
{module,erl_eval},
{new_index,2},
{new_uniq,<<146,128,248,136,99,188,48,7,216,172,210,56,139,244,145,225>>},
{index,6},
{uniq,72228031},
{name,'-expr/5-fun-2-'},
{arity,1},
{env,[[{'X',1}],
none,
{eval,#Fun<shell.21.66499203>},
[{clause,1,[{var,1,'Y'}],[],[{op,1,'+',{var,1,'X'},{var,1,...}}]}]]},
{type,local}]