Mixプロジェクトに同梱したファイルを参照する
ある新しいライブラリに以下の問題があってムムッと思ってプルリクした。
例えばlib/data/people.yml
を置くとする。lib/my_app/module.ex
でこのファイルを読みたい。
# ダメな例 "lib/data/people.yml" |> File.open # 良い例 "../lib/data/people.yml" |> Path.expand(__DIR__) |> File.open
上の例がなんでマズイかというと、ライブラリとして利用されたときに"../lib/data/people.yml"の"lib"が指しているのは、
another_project ├mix.exs ├config ├lib ← これであって │ ├another_project.ex │ └another_project ├deps │ └my_app │ └lib ← これではない │ └data │ └people.yml └test
のだ。
なので後者のように、1回フルパスに展開してから使ったほうがよい。単体でテストしても気付きにくいかも。もっと良い方法があるかもしれない。
別ファイルに分けるほど大きなデータとかを使うことがなかったので初遭遇問題だった。 ただ文字列を返すだけの関数をつくったことはあったが、Elixir.String.Unicodeみたいにコンパイル時にファイルを読んで関数定義しちゃうのがパフォーマンス的にも良さそう。
はー、麻婆ナントカ食べたい。
追記
どうやらApplicaiton.app_dir :my_app
で"/abs/path/to/_build/dev/lib/my_app"
が取れるっぽ。ソースからの相対パスだと、ディレクトリ構成変えたとき面倒だし、同じものを読みたいのにソースファイル毎に異なる指定になる。なので良い子はApplication.app_dir/1
を使おう。
そして相変わらず麻婆ナントカ食べたい。