%%% BEGIN openflax/conf.erl %%% %%% %%% openflax - Open Source web server for Erlang/OTP %%% Copyright (c)2004 Cat's Eye Technologies. All rights reserved. %%% %%% Redistribution and use in source and binary forms, with or without %%% modification, are permitted provided that the following conditions %%% are met: %%% %%% Redistributions of source code must retain the above copyright %%% notice, this list of conditions and the following disclaimer. %%% %%% Redistributions in binary form must reproduce the above copyright %%% notice, this list of conditions and the following disclaimer in %%% the documentation and/or other materials provided with the %%% distribution. %%% %%% Neither the name of Cat's Eye Technologies nor the names of its %%% contributors may be used to endorse or promote products derived %%% from this software without specific prior written permission. %%% %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND %%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, %%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF %%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE %%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE %%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, %%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, %%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, %%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON %%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, %%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY %%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE %%% POSSIBILITY OF SUCH DAMAGE. %% @doc OpenFlax configuration datatype module. %% %%

This module defines an abstract data type conf() %% which represents a set of configuration settings.

%% %%

conf()s are immutable. You must create a %% new conf() from an existing one; you cannot change %% it.

%% %% @end -module(openflax.conf). -vsn('$Id: conf.erl 31 2004-04-23 07:00:11Z catseye $'). -author('catseye@catseye.mb.ca'). -copyright('Copyright (c)2004 Cat`s Eye Technologies. All rights reserved.'). -export([new/0, new/1]). -export([get_string/2, get_value/2, put_value/3, delete_value/2]). -export([dump/1, map/2, fold/3, merge/2, merge/3]). -export([load/1]). % module imports -import(erlang). -import(lists). -import(dict). -include_lib("kernel/include/file.hrl"). %% @spec new() -> conf() %% @doc Creates a new conf(). new() -> new([]). %% @spec new([{key(), value()}]) -> conf() %% key() = atom() %% value() = term() %% @doc Creates a new conf() from a list of key-value pairs. new(List) -> dict:from_list(List). %% @spec get_string(key(), conf()) -> string() %% @doc Retrieves a string from a conf(). The returned value %% is always converted to a flattened string. get_string(Key, Conf) -> case dict:find(Key, Conf) of {ok, Value} -> lists:flatten(openflax.string:from_term(Value)); error -> "" end. %% @spec get_value(key(), conf()) -> {ok, term()} | error %% @doc Retrieves a value from a conf(). get_value(cfg_openflax_version, _) -> {ok, openflax.app:version()}; get_value(Key, Conf) -> dict:find(Key, Conf). %% @spec put_value(key(), value(), conf()) -> conf() %% @doc Updates a value in a conf(). Returns a new %% conf() with the specified key representing a new value. put_value(Key, Value, Conf) -> dict:store(Key, Value, Conf). %% @spec delete_value(key(), conf()) -> conf() %% @doc Deletes a value from a conf(). %% Returns a new conf(). delete_value(Key, Conf) -> dict:erase(Key, Conf). %% @spec dump(conf()) -> [{key(), value()}] %% @doc Retrieves all values from a conf() as a list of %% key-value pairs. dump(Conf) -> dict:to_list(Conf). %% @spec map(fun(), conf()) -> conf() %% @doc Creates a new conf() by applying a fun/2 (Key, Value) %% to each key-value pair in the conf(). The return value of the %% fun is a new value to use for the key in the new conf(). map(Fun, Conf) -> dict:map(Fun, Conf). %% @spec fold(fun(), term(), conf()) -> term() %% @doc Creates a new term by applying a fun/3 (Key, Value, Acc) %% to each key-value pair in the conf(). The return value of %% the fun is a new accumulator. fold(Fun, Acc, Conf) -> dict:fold(Fun, Acc, Conf). %% @spec merge(A::conf(), B::conf()) -> conf() %% @doc Creates a new conf() by merging two conf()s. %% Mostly equivalent to merge(fun(K, V1, V2) -> V2 end, A, B), %% except that cumulative settings are not wholly overridden, but rather, %% accumulated. merge(ConfA, ConfB) -> merge(fun (cfg_openflax_dispatch, V1, V2) -> % cumulative, so merge lists V1 ++ V2; (cfg_openflax_watchers, V1, V2) -> % cumulative, so merge lists V1 ++ V2; (_, _V1, V2) -> % otherwise, override V2 end, ConfA, ConfB). %% @spec merge(fun(), A::conf(), B::conf()) -> conf() %% @doc Creates a new conf() by merging two conf()s %% and applying a fun/3 (Key, ValueA, ValueB) when there %% are colliding keys. The return value of the fun is %% the value which will be used in the new conf(). merge(Fun, ConfA, ConfB) -> dict:merge(Fun, ConfA, ConfB). %% @spec load(ConfigModuleNames::[modulename()]) -> dict() %% modulename() = atom() %% @doc The configuration settings are loaded from the named config modules. %% They are returned in a 'master dictionary' where the keys %% are atoms (section names) and the values are conf()s. load(ConfigModuleNames) -> lists:foldl(fun(ConfigModuleName, Dict) -> ConfigModule = case ConfigModuleName of S when is_list(S) -> list_to_atom(S); S -> S end, lists:foldl(fun({Section, ConfList}, Acc) -> case dict:find(Section, Acc) of {ok, ExtantConf} -> dict:store(Section, merge(ExtantConf, new(ConfList)), Acc); error -> dict:store(Section, new(ConfList), Acc) end end, Dict, ConfigModule:conf()) end, dict:new(), ConfigModuleNames). %%% END of openflax/conf.erl %%%