ENV
ENV is a hash-like accessor for environment variables.
Example
Assuming the following example is invoked with the HOST=localhost and
PORT=5000 environment variables:
p ENV["HOST"] # => "localhost"
p ENV["PORT"].to_i # => 5000
p ENV.fetch("TLS_PORT", "443").to_i # => 443
NOTE: All keys and values are strings. You must take care to cast other types at runtime, e.g. integer port numbers.
Safety
Modifying the environment in single-threaded programs is safe. Modifying the environment is also always safe on Windows.
Modifying the environment in multi-threaded programs on other targets is always unsafe, and can cause a mere read to segfault! At best, memory will be leaked every time the environment is modified.
The problem is that POSIX systems don't guarantee a thread safe implementation
of the getenv, setenv and putenv libc functions. Any thread that gets an
environment variable while another thread sets an environment variable may
segfault. The Crystal runtime implementation of ENV itself is protected by a
readers-writer lock, but we can't protect against external libraries,
including libc calls made by the stdlib, to call getenv internally without
holding the read lock while a crystal fiber with the write lock calls
setenv.
The only safe solution is to consider ENV to be immutable, and to never call
ENV.[]=, ENV.delete or ENV.clear in your programs. If you really need
to, you must make sure that no other thread has been started (beware of
libraries that may start threads without your knowledge).
NOTE: Passing environment variables to a child process should use the env
arg of Process.run and Process.new.