コミケ告知

サークル活動の詳細は circle タグの記事へ。
2016年3月24日木曜日

Elixirでattributeを用いたコンパイル時分岐

C/C++でいう#ifdef DEBUG 的なことを、moduleのattributeを使って行おうとしたところ、dialyzerさんに文句を言われてしまいました。if (@flag)のような記述が展開され、if(true) とか if(false) とかになって、欠陥のあるパターンマッチ記述として検出されるわけですね。
そこで、ただコンパイルの前にtrue/falseが判定されるだけのマクロを書いて対処しました。

上記のソースコードをdialyzerにかけた結果はこうなります。(dialyxir使用)
% mix dialyzer
Starting Dialyzer
dialyzer --no_check_plt --plt C:\Users\moccos/.dialyxir_core_18_1.2.3.plt (オプション略)
  Proceeding with analysis...
hoge.ex:8: The pattern 'false' can never match the type 'true'
 done in 0m1.31s
done (warnings were emitted)

# 最初に書いたバージョンに間違いがあったので、2016/03/28に修正しました。
# Elixir1.3系で動かなかったので2016/06/24に再度修正
2016年3月5日土曜日

Cowboyの使い始めではまったところメモ (privとは何ぞや)

ElixirでWebサーバーといえばPhoenixですが、既存のElixirアプリケーションにちょっとWebサーバーの機能を足すだけの場合にはちょっと大規模すぎたので、PhoenixよりもコンパクトなCowboyを使うことにしました。Phoenixのサーバーコア部分はCowboyなので、比してコンパクトという表現は実はちょっとおかしいですね。

ソースコードのexamples以下には、いくつもサンプルプロジェクトがあり、それをそのまま動かすのも、参考にして動かすのも簡単です。ドキュメントもErlangなのに十分にあり、必要なハンドラを定義して差し込むだけで動きの把握もしやすく、素晴らしいライブラリですね。

ただしひとつだけ罠があり、それはサンプルで用いられるファイル読み出し指定が priv_dir や priv_file であることです。例えばstatic_worldのサンプルでは…

Dispatch = cowboy_router:compile([
 {'_', [
  {"/", cowboy_static, {priv_file, static_world, "index.html"}},
  {"/[...]", cowboy_static, {priv_dir, static_world, "", 以下略
 ]}
]),
Elixirで書くとこんな感じ:
dispatch = :cowboy_router.compile([
  {:_, [
      {"/", :cowboy_static, {:priv_file, :static_world, "index.html"}},
      {"/[...]", :cowboy_static, {:priv_dir, :static_world, ""}, 以下略}
  ]}
])

これをiexで走らせると動いて安心していたのですが、escriptにしたりアプリケーションとしてリリースしようとしたりすると全然動かない。index.htmlなどのファイルが見つからないときの挙動をする…。 どこに置いてもindex.htmlなどのファイルをアプリケーションが見つけてくれない。
同様にpriv方面ではまっている英語の記事があり、そちらではそのまま力技で解決していましたが、そんなに頑張らなくても、単にprivディレクトリを使う指定をやめればOKでした。

dispatch = :cowboy_router.compile([
  {:_, [
      {"/", :cowboy_static, {:file, "web/index.html"}},
      {"/static/[...]", :cowboy_static, {:dir, "web/static"}}
  ]}
])

実コードから引っ張ってきたので若干パス指定が違いますが、要点は:priv_fileではなく:file、:priv_dirではなく:dirを使うこと。アプリケーションからの相対位置で無事読めました。privディレクトリがErlang的に特別なものらしいのです。ぐぐるとほとんど情報がないなかに、ユーザーズガイド邦訳から以下の説明が見つかります。

アプリケーション固有のファイルの格納に使用されます。例えば、Cの実行ファイルがここに置かれます。code:priv_dir/1関数を使用すると、このディレクトリにアクセスすることができます。

単にprivという名前のディレクトリではないことはわかりました。Cの実行ファイルを格納するようなところに、Webのリソースを置くのはなんか違うんじゃないかなという感覚があるのですが…

# 2016/04/20追記
公式のMix.Tasks.Escript.Buildの項目に
Note: escripts do not support projects and dependencies that need to store or read artifacts from the priv directory.

とありました。