Skip to content

Commit

Permalink
Merge pull request #34 from greyblake/default-env-name
Browse files Browse the repository at this point in the history
Default env name
  • Loading branch information
greyblake committed Oct 14, 2020
2 parents 98f700f + 2db3346 commit 6ba0dde
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 36 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#### Unreleased
* [breaking] Nested config fields now needs to be marked with #[envconfig(nested = true)]
* Environment variable can be automatically derived from a field name (e.g. `db_host` will be tried to loaded from `DB_HOST` env var)

#### v0.9.1 - 2019-10-09
* Get rid of thiserror dependency

Expand Down
2 changes: 1 addition & 1 deletion envconfig/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ impl fmt::Display for Error {

impl StdError for Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
return None;
None
}
}
18 changes: 8 additions & 10 deletions envconfig/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,16 @@
//! pub http_port: u16,
//! }
//!
//! fn main() {
//! // We assume that those environment variables are set somewhere outside
//! env::set_var("DB_HOST", "localhost");
//! env::set_var("DB_PORT", "5432");
//! // We assume that those environment variables are set somewhere outside
//! env::set_var("DB_HOST", "localhost");
//! env::set_var("DB_PORT", "5432");
//!
//! // Initialize config from environment variables
//! let config = Config::init().unwrap();
//! // Initialize config from environment variables
//! let config = Config::init().unwrap();
//!
//! assert_eq!(config.db_host, "localhost");
//! assert_eq!(config.db_port, Some(5432));
//! assert_eq!(config.http_port, 8080);
//! }
//! assert_eq!(config.db_host, "localhost");
//! assert_eq!(config.db_port, Some(5432));
//! assert_eq!(config.http_port, 8080);
//! ```
//!
//! The library uses `std::str::FromStr` trait to convert environment variables into custom
Expand Down
61 changes: 37 additions & 24 deletions envconfig_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,46 @@ fn gen_field_assign(field: &Field) -> proc_macro2::TokenStream {
let attr = fetch_envconfig_attr_from_field(field);

if let Some(attr) = attr {
// if #[envconfig(...)] is there
let list = fetch_list_from_attr(field, attr);
let from_value = find_item_in_list_or_panic(field, &list, "from");

// If nested attribute is present
let nested_value_opt = find_item_in_list(field, &list, "nested");
if nested_value_opt.is_some() {
return gen_field_assign_for_struct_type(field);
}

let opt_default = find_item_in_list(field, &list, "default");

let field_type = &field.ty;
let from_opt = find_item_in_list(field, &list, "from");
let env_var = match from_opt {
Some(v) => quote! { #v },
None => field_to_env_var(field),
};

if to_s(field_type).starts_with("Option ") {
gen_field_assign_for_optional_type(field, from_value, opt_default)
} else {
gen_field_assign_for_non_optional_type(field, from_value, opt_default)
}
geen(field, env_var, opt_default)
} else {
// if #[envconfig(...)] is not present
let env_var = field_to_env_var(field);
geen(field, env_var, None)
}
}

fn field_to_env_var(field: &Field) -> proc_macro2::TokenStream {
let field_name = field.clone().ident.unwrap().to_string().to_uppercase();
quote! { #field_name }
}

fn geen(
field: &Field,
from: proc_macro2::TokenStream,
opt_default: Option<&Lit>,
) -> proc_macro2::TokenStream {
let field_type = &field.ty;
if to_s(field_type).starts_with("Option ") {
gen_field_assign_for_optional_type(field, from, opt_default)
} else {
gen_field_assign_for_struct_type(field)
gen_field_assign_for_non_optional_type(field, from, opt_default)
}
}

Expand All @@ -90,7 +117,7 @@ fn gen_field_assign_for_struct_type(field: &Field) -> proc_macro2::TokenStream {

fn gen_field_assign_for_optional_type(
field: &Field,
from: &Lit,
from: proc_macro2::TokenStream,
opt_default: Option<&Lit>,
) -> proc_macro2::TokenStream {
let ident = &field.ident;
Expand All @@ -106,7 +133,7 @@ fn gen_field_assign_for_optional_type(

fn gen_field_assign_for_non_optional_type(
field: &Field,
from: &Lit,
from: proc_macro2::TokenStream,
opt_default: Option<&Lit>,
) -> proc_macro2::TokenStream {
let ident = &field.ident;
Expand Down Expand Up @@ -148,20 +175,6 @@ fn fetch_list_from_attr(field: &Field, attr: &Attribute) -> Punctuated<NestedMet
}
}

fn find_item_in_list_or_panic<'l, 'n>(
field: &Field,
list: &'l Punctuated<NestedMeta, Comma>,
item_name: &'n str,
) -> &'l Lit {
find_item_in_list(field, list, item_name).unwrap_or_else(|| {
panic!(
"`envconfig` attribute on field `{}` must contain `{}` item",
field_name(field),
item_name
)
})
}

fn find_item_in_list<'l, 'n>(
field: &Field,
list: &'l Punctuated<NestedMeta, Comma>,
Expand Down
1 change: 0 additions & 1 deletion test_suite/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use envconfig::Envconfig;

#[derive(Envconfig)]
pub struct Config {
#[envconfig(from = "PORT")]
pub port: u16,

#[envconfig(from = "HOST")]
Expand Down
36 changes: 36 additions & 0 deletions test_suite/tests/default_env_var.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
extern crate envconfig;

use envconfig::{Envconfig, Error};
use std::env;

#[derive(Envconfig)]
pub struct Config {
pub db_host: String,
pub db_port: Option<u16>,
}

fn setup() {
env::remove_var("DB_HOST");
env::remove_var("DB_PORT");
}

#[test]
fn test_derives_env_variable_names_automatically() {
setup();

env::set_var("DB_HOST", "db.example.com");
env::set_var("DB_PORT", "5050");

let config = Config::init_from_env().unwrap();
assert_eq!(config.db_host, "db.example.com");
assert_eq!(config.db_port, Some(5050));
}

#[test]
fn test_var_is_missing() {
setup();

let err = Config::init_from_env().err().unwrap();
let expected_err = Error::EnvVarMissing { name: "DB_HOST" };
assert_eq!(err, expected_err);
}
4 changes: 4 additions & 0 deletions test_suite/tests/nesting.rs → test_suite/tests/nested.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@ pub struct DBConfig {

#[derive(Envconfig)]
pub struct Config {
#[envconfig(nested = true)]
pub db: DBConfig,
}

#[derive(Envconfig)]
pub struct ConfigDouble {
#[envconfig(nested = true)]
pub db1: DBConfig,

#[envconfig(nested = true)]
pub db2: DBConfig,
}

Expand Down

0 comments on commit 6ba0dde

Please sign in to comment.