简而言之,我有一个脚本,它读取.yaml文件以在运行时获取一些配置信息,例如要联系的URL,要使用的共享密钥,是否使用调试模式等.
使用该配置的模块有一个启动函数,该函数稍后调用一个循环,并且还调用一个logdebug函数来写入诊断信息,但只有在设置了调试模式的情况下.令我恼火的是,每当我打电话给我时,我必须将配置传递给每个功能.如果我可以调用start函数并设置一些可用于模块中所有其他函数的变量,那将会容易得多.可以这样做吗?我似乎无法找到有关如何做到这一点的任何事情.
有没有像我在这里做的那样设置运行时配置的首选方法?也许我过于复杂了?
编辑:更多细节,我将此作为一个可执行文件分发Escript.Build,我不想让最终用户编辑文件,然后重建文件.这就是为什么我希望最终用户(可能不是超级技术人员)能够编辑.yaml文件.
免责声明:我将你的'运行时配置'更多地解释为参数; 如果不是这样的话,这个答案可能不是很有用.
A Module类似于a Class.
不幸的是,这种常见的面向对象工作方法不够相似; Elixir/Erlang模块没有"生命",只是扁平的逻辑.你有效地尝试做的是在模块本身存储状态; 在函数式语言中,状态必须保存在变量中,因为模块在所有进程的所有调用者之间共享 - 另一个进程可能需要存储不同的状态!
然而,这是一个常见的编程问题,并且有一种惯用的方法可以在Elixir中解决它:a GenServer.
如果您不熟悉OTP,那么您应该自己学习它:它会改变您对编程的看法,它会帮助您编写更好的(读取:更可靠)软件,它会让您快乐.真.
我会将配置存储在GenServer的状态中; 如果你创建一个内部结构来表示它,你可以轻松传递它并设置默认值; 我们想要的所有东西都在令人愉悦的API中.
示例实现:
defmodule WebRequestor do
use GenServer
### API ###
# these functions execute in the CALLER's process
def start_link() do
GenServer.start_link(__MODULE__, [], [name: __MODULE__])
end
def start do
# could use .call if you need synch, but then you'd want to look at
# delayed reply genserver calls, which is an advanced usage
GenServer.cast(__MODULE__, :start)
end
#could add other methods for enabling debug, setting secrets, etc.
def update_url(new_url) do
GenServer.call(__MODULE__, {:update_url, new_url})
end
defmodule State do
@doc false
defstruct [
url: "http://api.my.default",
secret: "mybadpassword",
debug: false,
status: :ready, # or whatever else you might need
]
end
### GenServer Callbacks ###
# These functions execute in the SERVER's process
def init([]) do
config = read_my_config_file
{:ok, config}
end
def handle_cast(:start, %{status: :ready} = state) do
if config.debug, do: IO.puts "Starting"
make_request(state.url)
{:noreply, %{state|status :running}}
end
def handle_cast(:state, state) do
#already running, so don't start again.
{:noreply, state}
end
def handle_call({:update_url, new_url}, _from, state) do
{:reply, :ok, %{state|url: new_url}}
end
### Internal Calls ###
defp make_request(config) do
# whatever you do here...
end
defp read_my_config_file do
# config reading...
%State{}
end
end
Run Code Online (Sandbox Code Playgroud)