Hatena::Grouperlang

檜山正幸のErlang未確認情報 RSSフィード

 | 

2009-01-20 (火)

helloをちゃんと作る (13) 構成パラメータによるカスタマイズ

| 11:08

「helloをちゃんと作る (12)」で述べたように、環境変数=構成パラメータによりアプリケーションの挙動を変えることができる。

だが、アプリケーションリソースファイルのenv項目を書き換えるという手段は、ソースファイルやヘッダファイルを書き換えてリコンパイルするよりはチョットだけ楽という程度。次の方法を紹介する。

  1. 構成ファイル(configuration file)に構成パラメータ群を書いて渡す。
  2. erl起動オプションに許されるアプリケーションオプションを使う。

実験の準備

実験のために、構成パラメータを増やしておく。

%% hello_impl.erl  -*- coding: utf-8 -*-

%% @doc Helloアプリケーションの実装モジュール.
-module(hello_impl).
-export([hello/0, hello/1]).

%% @doc デフォルトの相手に対して挨拶をする.
%% @spec () -> ok
hello() ->
  Whom = 
    case application:get_env(whom) of
      {ok, Val} -> 
        Val;
      _ ->
        "world"
    end,
  hello(Whom).

%% @doc 引数で指定された相手に対して挨拶をする.
%% @spec (string()) -> ok
hello(Whom) when is_list(Whom) -> 
  Greeting = 
    case application:get_env(greeting) of
      {ok, Val} -> 
        Val;
      _ ->
        "Hello"
    end,
  io:fwrite("~s, ~s.~n", [Greeting, Whom]).

最初の時点でのアプリケーションリソースファイルは:

%% -*- coding: utf-8 -*-

{application, hello, % アプリケーション名はアトムである点に注意
  % 以下に記述項目のリスト
  [
   {description,  "hello application"},
   {id,           "hell-1.0"}, % idはシステムが使うわけではないので何でもよい
   {vsn,          "1.0"}, % ドットでつないだ数値を使うのが無難
   {modules,      % helloアプリケーションを構成するすべてのモジュール名を列挙
     [hello_impl, hello_server, hello_sup, hello_api, hello_app, hello]},
   {registered,   % helloアプリケーションで登録する名前を列挙
     [hello_server, hello_sup]},
   {applications, [kernel, stdlib]},
   {mod,          {hello_app, none}}
  ]
}.

envを書いてない。この設定で hello_api:hello().とすると、プログラムコード中に埋め込まれた値、"Hello", "world"が使われる。

なお、対話的な実験が面倒なら、次のコマンドを使うとよい。

OS-Shell> erl -s hello -s hello_api hello -s init stop

アプリケーションリソースファイル

アプリケーションリソースファイルに次の1行を加える。

   {env, [{whom, "universe"}]},

構成パラメータwhomの値が"universe"に設定されるので、Hello, universe. が表示される。

構成ファイル

次のような構成ファイル(configuration file)を作る。書式は http://www.erlang.org/doc/man/config.html に書いてある。拡張子は .config にする(そうしないと不吉)。

%% -*- coding: utf-8 -*-
%%
[
 {hello,
    [{greeting, "Good morning"}]
 }
].

このファイルをhello.cinfigとして、erlコマンドの -config オプションにファイル名を指定する。

erl -config hello.config <その他の引数

.config拡張子は省略可能で、省略するのが習慣らしい。

この例では、Good morning, universe. が表示される。アプリケーションリソースファイルより構成ファイルが優先されるので、次のようにアプリケーションリソースファイルをオーバライドできる。

%% -*- coding: utf-8 -*-
%%
[
 {hello,
    [{whom, "Japan"}]
 }
].

コマンドラインオプション

http://www.erlang.org/doc/man/erl.html より:

-Application Par Val

Sets the application configuration parameter Par to the value Val for the application Application, see app(4) and application(3).

これによると、-hello whom Tokyo とすれば、Hello, Tokyo. と表示しそうである。しかし、実際は:

OS-Shell>erl -config hello -hello whom Tokyo  \
  -s hello -s hello_api hello -s init stop

とするとクラッシュする。-hello whom の後には文字列が必要。OSコマンドライン上にErlangタームを表現する形式で書かなくてはいけないので、文字列なら引用符が要る。そのまま引用符を書くとOSシェルが食べてしまい、ERTSにmainに渡らない。引用符をERTSまで届ける書き方はOSシェルによりけりだが、例えば次のようだろう。

  • -hello whom \"Tokyo\"
  • -hello whom '"Tokyo"'

コマンドラインオプションはconfigファイルよりさらに優先される。

その他、細かいこと

erl -config hello -hello whom \"Tokyo\"として対話的にERTSを起動する。起動直後に application:get_env(hello, whom). としてもundefinedになる。-configや-helloオプションを指定しても、当該アプリケーションを起動しない限り、構成パラメータを読むことはできない。より正確に言うと、application:load(hello) のタイミングで構成パラメータをセットアップするようだ。このとき、included_applicationsも構成パラメータに自動的にセットされる(詳細はよくわからんが)。

application:set_env/{3,4}で実行時に動的に構成パラメータをセットできるが、変更時に通知(イベント)が飛ぶようなメカニズムはないので、不注意に使うと危険だ。また、application:loadは1度しかできないので、いったん読んでしまったアプリケーション仕様データを読み直すことはできない。つまり、構成パラメータは静的な性格が強い、実行中は定数とが考えたほうがよいだろう。

なお、init:get_argument(hello) としても-helloオプションの値(生のまま)が取れる。initが保持している値はアプリケーションコントローラとは独立なので、helloをスタートさせなくてもパラメータを取れる。この方法は、アプリケーションコントローラに登録しない野良アプリケーションで利用できる。

 |