Disclaimer: I'm interpreting your 'runtime config' more as arguments; if that's not the case, this answer may not be very useful.
A Module is similar to a Class.
Unfortunately, not similar enough for this common O-O approach to work; Elixir/Erlang modules have no "life" in them, and are just flat logic. What you are effectively trying to do is store state in the Module itself; in a functional language, state must be kept in variables, because the Module is shared across all callers from all processes- another process might need to store different state!
However, this is a common programming problem, and there is an idiomatic way to solve it in Elixir: a GenServer.
If you aren't familiar with OTP, you owe it to yourself to learn it: it'll change the way you think about programming, it'll help you write better (read: more reliable) software, and it'll make you happy. Really.
I would store the config in the GenServer's state; If you create an internal struct to represent it, you can pass it around easily and set defaults; all the things we want in a pleasing API.
A sample implementation:
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