-module(glenv). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([load/2]). -export_type([type/0, env_error/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " glenv is a library for type-sfe environment variable access.\n" "\n" ). -type type() :: bool | float | int | string. -type env_error() :: {missing_key_error, binary()} | {invalid_env_value_error, binary(), type()} | {definition_mismatch_error, list(gleam@dynamic@decode:decode_error())}. -file("src/glenv.gleam", 113). -spec do_parse({binary(), type()}, binary()) -> {ok, {binary(), gleam@dynamic:dynamic_()}} | {error, env_error()}. do_parse(Definition, Value) -> case Definition of {Key, bool} -> case glenv@internal@parse:bool(Key, Value) of {ok, Resolution} -> {ok, Resolution}; {error, _} -> {error, {invalid_env_value_error, Key, bool}} end; {Key@1, float} -> case glenv@internal@parse:float(Key@1, Value) of {ok, Resolution@1} -> {ok, Resolution@1}; {error, _} -> {error, {invalid_env_value_error, Key@1, float}} end; {Key@2, int} -> case glenv@internal@parse:int(Key@2, Value) of {ok, Resolution@2} -> {ok, Resolution@2}; {error, _} -> {error, {invalid_env_value_error, Key@2, int}} end; {Key@3, string} -> case glenv@internal@parse:string(Key@3, Value) of {ok, Resolution@3} -> {ok, Resolution@3}; {error, _} -> {error, {invalid_env_value_error, Key@3, string}} end end. -file("src/glenv.gleam", 100). -spec parse(list({binary(), type()})) -> {ok, list({binary(), gleam@dynamic:dynamic_()})} | {error, env_error()}. parse(Definitions) -> Env = envoy_ffi:all(), gleam@list:try_map( Definitions, fun(Definition) -> Normalized_definition = {string:uppercase( erlang:element(1, Definition) ), erlang:element(2, Definition)}, case gleam_stdlib:map_get( Env, erlang:element(1, Normalized_definition) ) of {ok, Value} -> do_parse(Normalized_definition, Value); {error, _} -> {error, {missing_key_error, erlang:element(1, Normalized_definition)}} end end ). -file("src/glenv.gleam", 81). ?DOC( " Load parses the environment variables and returns a Result containing the environment.\n" " Takes a decoder from the gleam/decode library and a list of definitions.\n" " \n" " ## Examples\n" "\n" " ```gleam\n" " type Env {\n" " Env(hello: String, foo: Float, count: Int, is_on: Bool)\n" " }\n" "\n" " let definitions = [\n" " #(\"HELLO\", glenv.String),\n" " #(\"FOO\", glenv.Float),\n" " #(\"COUNT\", glenv.Int),\n" " #(\"IS_ON\", glenv.Bool),\n" " ]\n" "\n" " let decoder =\n" " decode.into({\n" " use hello <- decode.parameter\n" " use foo <- decode.parameter\n" " use count <- decode.parameter\n" " use is_on <- decode.parameter\n" "\n" " Env(hello: hello, foo: foo, count: count, is_on: is_on)\n" " })\n" " |> decode.field(\"HELLO\", decode.string)\n" " |> decode.field(\"FOO\", decode.float)\n" " |> decode.field(\"COUNT\", decode.int)\n" " |> decode.field(\"IS_ON\", decode.bool)\n" "\n" " let assert Ok(env) = glenv.load(decoder, definitions)\n" "\n" " env.hello // \"world\"\n" " env.foo // 1.0\n" " env.count // 1\n" " env.is_on // True\n" " ```\n" ). -spec load(gleam@dynamic@decode:decoder(EYE), list({binary(), type()})) -> {ok, EYE} | {error, env_error()}. load(Decoder, Definitions) -> gleam@result:'try'( parse(Definitions), fun(Parsed_env) -> case begin _pipe = Parsed_env, _pipe@1 = maps:from_list(_pipe), _pipe@2 = gleam_stdlib:identity(_pipe@1), gleam@dynamic@decode:run(_pipe@2, Decoder) end of {ok, Env} -> {ok, Env}; {error, Err} -> {error, {definition_mismatch_error, Err}} end end ).