diff --git a/conf.v b/conf.v index 3ebc194..c7a0e0d 100644 --- a/conf.v +++ b/conf.v @@ -4,16 +4,25 @@ import os import toml import datatypes { Set } +[params] +pub struct LoadConfig { + prefix string + file_suffix string = '_FILE' + default_path string + // Allows overwriting + env map[string]string = os.environ() +} + // get_env_var tries to read the contents of the given environment variable. It // looks for either `${env.prefix}${field_name.to_upper()}` or // `${env.prefix}${field_name.to_upper()}${env.file_suffix}`, returning the // contents of the file instead if the latter. If both or neither exist, the // function returns an error. -fn get_env_var(prefix string, field_name string, file_suffix string) !string { - env_var_name := '$prefix$field_name.to_upper()' - env_file_name := '$prefix$field_name.to_upper()$file_suffix' - env_var := os.getenv(env_var_name) - env_file := os.getenv(env_file_name) +fn (ld LoadConfig) get_env_var(field_name string) !string { + env_var_name := '$ld.prefix$field_name.to_upper()' + env_file_name := '$ld.prefix$field_name.to_upper()$ld.file_suffix' + env_var := ld.env[env_var_name] or { '' } + env_file := ld.env[env_file_name] or { '' } // If both are missing, we return an empty string if env_var == '' && env_file == '' { @@ -39,18 +48,11 @@ fn get_env_var(prefix string, field_name string, file_suffix string) !string { } } -[params] -pub struct LoadConfig { - prefix string - file_suffix string = '_FILE' - default_path string -} - // load attempts to create an object of type T from the given path to a toml // file & environment variables. For each field, it will select either a value // given from an environment variable, a value defined in the config file or a // configured default if present, in that order. -pub fn load(conf LoadConfig) !T { +pub fn load(ld LoadConfig) !T { mut res := T{} // This array allows us to determine later whether the variable is actually @@ -58,7 +60,7 @@ pub fn load(conf LoadConfig) !T { mut has_value := Set{} // Later, this could be read from an env var as well. - path := conf.default_path + path := ld.default_path if os.exists(path) { // We don't use reflect here because reflect also sets any fields not @@ -84,7 +86,7 @@ pub fn load(conf LoadConfig) !T { } $for field in T.fields { - env_value := get_env_var(conf.prefix, field.name, conf.file_suffix)! + env_value := ld.get_env_var(field.name)! // The value of an env var will always take precedence over the toml // file. @@ -117,12 +119,11 @@ pub fn load(conf LoadConfig) !T { } } - // If there's no value provided in any way, we notify the user with an - // error. + // If there's no value provided in any way, we notify the user with an + // error. if !has_value.exists(field.name) { return error("Missing config variable '$field.name' with no provided default. Either add it to the config file or provide it using an environment variable.") } } - return res } diff --git a/string_test.v b/string_test.v index c498b11..b91cff5 100644 --- a/string_test.v +++ b/string_test.v @@ -8,6 +8,14 @@ struct SingleConfDefault { some_string string = 'default' } +const env = { + 'SOME_STRING': 'env' +} + +const prefix_env = { + 'TEST_SOME_STRING': 'env' +} + fn test_string_present_no_default() { conf := load(default_path: 'test/string.toml')! assert conf == SingleConf{ @@ -15,11 +23,35 @@ fn test_string_present_no_default() { } } +fn test_string_present_no_default_env() { + conf := load(default_path: 'test/string.toml', env: .env)! + assert conf == SingleConf{ + some_string: 'env' + } + + conf2 := load(default_path: 'test/string.toml', env: .prefix_env, prefix: 'TEST_')! + assert conf2 == SingleConf{ + some_string: 'env' + } +} + fn test_string_absent_no_default() { conf := load(default_path: 'test/empty.toml') or { return } assert false } +fn test_string_absent_no_default_env() { + conf := load(default_path: 'test/string.toml', env: .env)! + assert conf == SingleConf{ + some_string: 'env' + } + + conf2 := load(default_path: 'test/string.toml', env: .prefix_env, prefix: 'TEST_')! + assert conf2 == SingleConf{ + some_string: 'env' + } +} + fn test_string_present_default() { conf := load(default_path: 'test/string.toml')! assert conf == SingleConfDefault{ @@ -27,9 +59,41 @@ fn test_string_present_default() { } } +fn test_string_present_default_env() { + conf := load(default_path: 'test/string.toml', env: .env)! + assert conf == SingleConfDefault{ + some_string: 'env' + } + + conf2 := load( + default_path: 'test/string.toml' + env: .prefix_env + prefix: 'TEST_' + )! + assert conf2 == SingleConfDefault{ + some_string: 'env' + } +} + fn test_string_absent_default() { conf := load(default_path: 'test/empty.toml')! assert conf == SingleConfDefault{ some_string: 'default' } } + +fn test_string_absent_default_env() { + conf := load(default_path: 'test/empty.toml', env: .env)! + assert conf == SingleConfDefault{ + some_string: 'env' + } + + conf2 := load( + default_path: 'test/empty.toml' + env: .prefix_env + prefix: 'TEST_' + )! + assert conf2 == SingleConfDefault{ + some_string: 'env' + } +}