feat: add nested namespaces

This commit is contained in:
Dmitriy Pleshevskiy 2020-01-10 23:42:41 +03:00
parent f4ee1fe9e6
commit 1a5154d261
5 changed files with 178 additions and 62 deletions

View file

@ -26,7 +26,9 @@ use std::env;
//use dotenv::dotenv; //use dotenv::dotenv;
config! { config! {
DEBUG: bool => true, DEBUG: bool => false,
#[env_name = "APP_HOST"]
HOST: String => "127.0.0.1", HOST: String => "127.0.0.1",
DATABASE_URL < ( DATABASE_URL < (
@ -40,26 +42,36 @@ config! {
POSTGRES_DB => "test", POSTGRES_DB => "test",
), ),
NAMESPACE { APP {
#[env_name = "MY_CUSTOM_NAME"] ARTICLE {
FOO: bool, PER_PAGE: u32 => 15,
}
BAR: i32 => 10, #[cfg(feature = "companies")]
COMPANY {
#[env_name = "INSTITUTIONS_PER_PAGE"]
PER_PAGE: u32 => 15,
}
}
#[cfg(feature = "feature")] FEATURE {
#[env_name = "POSTGRES_CONNECTION_STRING"] NEW_MENU: bool => false,
DATABASE_URL: String
COMPANY {
PROFILE: bool => false,
}
} }
} }
fn main () { fn main () {
// dotenv().ok(); // dotenv().ok();
env::set_var("MY_CUSTOM_NAME", "t"); env::set_var("FEATURE_NEW_MENU", "t");
cfg::init(); cfg::init();
assert_eq!(cfg::HOST(), String::from("127.0.0.1")); assert_eq!(cfg::HOST(), String::from("127.0.0.1"));
assert_eq!(cfg::DATABASE_URL(), String::from("postgres://user:pass@localhost:5432/test")); assert_eq!(cfg::DATABASE_URL(), String::from("postgres://user:pass@localhost:5432/test"));
assert_eq!(cfg::NAMESPACE::FOO(), true); assert_eq!(cfg::APP:ARTICLE:PER_PAGE(), 15);
assert_eq!(cfg::FEATURE::NEW_MENU(), true);
} }
``` ```
@ -77,10 +89,12 @@ cargo test
* [x] Support feature config and other meta directives * [x] Support feature config and other meta directives
* [x] Add default value to env if env is not found * [x] Add default value to env if env is not found
* [x] Concat env variables to one variable * [x] Concat env variables to one variable
* [ ] Add nested namespaces * [x] Add nested namespaces
* [x] Support meta for namespaces
* [ ] Support array type * [ ] Support array type
* [ ] Support hashmap type * [ ] Support hashmap type
* [ ] Support custom env type * [ ] Support custom env type
* [ ] Common configuration for namespace variables
## License ## License

View file

@ -13,7 +13,9 @@ use std::env;
//use dotenv::dotenv; //use dotenv::dotenv;
config! { config! {
DEBUG: bool => true, DEBUG: bool => false,
#[env_name = "APP_HOST"]
HOST: String => "127.0.0.1", HOST: String => "127.0.0.1",
DATABASE_URL < ( DATABASE_URL < (
@ -27,26 +29,36 @@ config! {
POSTGRES_DB => "test", POSTGRES_DB => "test",
), ),
NAMESPACE { APP {
#[env_name = "MY_CUSTOM_NAME"] ARTICLE {
FOO: bool, PER_PAGE: u32 => 15,
}
BAR: i32 => 10, #[cfg(feature = "companies")]
COMPANY {
#[env_name = "INSTITUTIONS_PER_PAGE"]
PER_PAGE: u32 => 15,
}
}
#[cfg(feature = "feature")] FEATURE {
#[env_name = "POSTGRES_CONNECTION_STRING"] NEW_MENU: bool => false,
DATABASE_URL: String
COMPANY {
PROFILE: bool => false,
}
} }
} }
fn main () { fn main () {
// dotenv().ok(); // dotenv().ok();
env::set_var("MY_CUSTOM_NAME", "t"); env::set_var("FEATURE_NEW_MENU", "t");
cfg::init(); cfg::init();
assert_eq!(cfg::HOST(), String::from("127.0.0.1")); assert_eq!(cfg::HOST(), String::from("127.0.0.1"));
assert_eq!(cfg::DATABASE_URL(), String::from("postgres://user:pass@localhost:5432/test")); assert_eq!(cfg::DATABASE_URL(), String::from("postgres://user:pass@localhost:5432/test"));
assert_eq!(cfg::NAMESPACE::FOO(), true); assert_eq!(cfg::APP:ARTICLE:PER_PAGE(), 15);
assert_eq!(cfg::FEATURE::NEW_MENU(), true);
} }
``` ```
@ -58,10 +70,12 @@ fn main () {
* [x] Support feature config and other meta directives * [x] Support feature config and other meta directives
* [x] Add default value to env if env is not found * [x] Add default value to env if env is not found
* [x] Concat env variables to one variable * [x] Concat env variables to one variable
* [ ] Add nested namespaces * [x] Add nested namespaces
* [x] Support meta for namespaces
* [ ] Support array type * [ ] Support array type
* [ ] Support hashmap type * [ ] Support hashmap type
* [ ] Support custom env type * [ ] Support custom env type
* [ ] Common configuration for namespace variables
## License ## License

View file

@ -25,22 +25,36 @@
//! POSTGRES_DB => "test", //! POSTGRES_DB => "test",
//! ), //! ),
//! //!
//! NAMESPACE { //! APP {
//! #[env_name = "MY_CUSTOM_NAME"] //! ARTICLE {
//! FOO: bool, //! PER_PAGE: u32 => 15,
//! }
//! //!
//! BAR: i32 => 10, //! #[cfg(feature = "companies")]
//! COMPANY {
//! #[env_name = "INSTITUTIONS_PER_PAGE"]
//! PER_PAGE: u32 => 15,
//! }
//! }
//!
//! FEATURE {
//! NEW_MENU: bool => false,
//!
//! COMPANY {
//! PROFILE: bool => false,
//! }
//! } //! }
//! } //! }
//! //!
//! fn main () { //! fn main () {
//! // dotenv().ok(); //! // dotenv().ok();
//! env::set_var("MY_CUSTOM_NAME", "t"); //! env::set_var("FEATURE_NEW_MENU", "t");
//! //!
//! cfg::init(); //! cfg::init();
//! assert_eq!(cfg::HOST(), String::from("127.0.0.1")); //! assert_eq!(cfg::HOST(), String::from("127.0.0.1"));
//! assert_eq!(cfg::DATABASE_URL(), String::from("postgres://user:pass@localhost:5432/test")); //! assert_eq!(cfg::DATABASE_URL(), String::from("postgres://user:pass@localhost:5432/test"));
//! assert_eq!(cfg::NAMESPACE::FOO(), true); //! assert_eq!(cfg::APP::ARTICLE::PER_PAGE(), 15);
//! assert_eq!(cfg::FEATURE::NEW_MENU(), true);
//! } //! }
//! ``` //! ```
@ -165,6 +179,41 @@ impl From<EnvValue> for String {
/// # cfg::init() /// # cfg::init()
/// ``` /// ```
/// ///
/// Now you can use nested structure in namespaces without limits :)
///
/// ```rust
/// # #[macro_use] extern crate itconfig;
/// config! {
/// FIRST {
/// SECOND {
/// THIRD {
/// FOO: bool => true,
/// }
/// }
/// }
/// }
/// # cfg::init();
/// ```
///
/// Namespaces supports custom meta
///
/// ```rust
/// # #[macro_use] extern crate itconfig;
/// config! {
/// #[cfg(feature = "first")]
/// FIRST {
/// #[cfg(feature = "second")]
/// SECOND {
/// #[cfg(feature = "third")]
/// THIRD {
/// FOO: bool => true,
/// }
/// }
/// }
/// }
/// # cfg::init();
/// ```
///
/// Meta /// Meta
/// ---- /// ----
/// ///
@ -343,6 +392,7 @@ macro_rules! __itconfig_parse_module {
module = { module = {
env_prefix = "", env_prefix = "",
name = $name, name = $name,
meta = [],
}, },
} }
}; };
@ -360,6 +410,7 @@ macro_rules! __itconfig_parse_variables {
// Find namespace // Find namespace
( (
tokens = [ tokens = [
$(#$meta:tt)*
$ns_name:ident { $($ns_tokens:tt)* } $ns_name:ident { $($ns_tokens:tt)* }
$($rest:tt)* $($rest:tt)*
], ],
@ -368,9 +419,11 @@ macro_rules! __itconfig_parse_variables {
__itconfig_parse_variables! { __itconfig_parse_variables! {
tokens = [$($ns_tokens)*], tokens = [$($ns_tokens)*],
variables = [], variables = [],
namespaces = [],
module = { module = {
env_prefix = concat!(stringify!($ns_name), "_"), env_prefix = concat!(stringify!($ns_name), "_"),
name = $ns_name, name = $ns_name,
meta = [$(#$meta)*],
}, },
callback = { callback = {
tokens = [$($rest)*], tokens = [$($rest)*],
@ -526,9 +579,8 @@ macro_rules! __itconfig_parse_variables {
( (
tokens = [], tokens = [],
variables = $ns_variables:tt, variables = $ns_variables:tt,
module = { namespaces = $ns_namespaces:tt,
$($current_namespace:tt)* module = $ns_module:tt,
},
callback = { callback = {
tokens = $tokens:tt, tokens = $tokens:tt,
variables = $variables:tt, variables = $variables:tt,
@ -543,7 +595,8 @@ macro_rules! __itconfig_parse_variables {
$($namespaces,)* $($namespaces,)*
{ {
variables = $ns_variables, variables = $ns_variables,
$($current_namespace)* namespaces = $ns_namespaces,
module = $ns_module,
}, },
], ],
$($args)* $($args)*
@ -555,7 +608,7 @@ macro_rules! __itconfig_parse_variables {
tokens = [], tokens = [],
$($args:tt)* $($args:tt)*
) => { ) => {
__itconfig_impl!($($args)*); __itconfig_impl_namespace!($($args)*);
}; };
// Invalid syntax // Invalid syntax
@ -567,7 +620,7 @@ macro_rules! __itconfig_parse_variables {
#[macro_export] #[macro_export]
#[doc(hidden)] #[doc(hidden)]
macro_rules! __itconfig_impl { macro_rules! __itconfig_impl_namespace {
( (
variables = [$({ variables = [$({
meta = $var_meta:tt, meta = $var_meta:tt,
@ -576,44 +629,42 @@ macro_rules! __itconfig_impl {
$($variable:tt)* $($variable:tt)*
},)*], },)*],
namespaces = [$({ namespaces = [$({
variables = [$({ variables = $ns_variable:tt,
meta = $ns_var_meta:tt, namespaces = $ns_namespaces:tt,
concat = $ns_var_concat:tt, module = {
name = $ns_var_name:ident,
$($ns_variables:tt)*
},)*],
env_prefix = $ns_env_prefix:expr, env_prefix = $ns_env_prefix:expr,
name = $ns_name:ident, name = $ns_mod_name:ident,
meta = [$(#$ns_meta:tt)*],
},
},)*], },)*],
module = { module = {
env_prefix = $env_prefix:expr, env_prefix = $env_prefix:expr,
name = $mod_name:ident, name = $mod_name:ident,
meta = [$(#$meta:tt)*],
}, },
) => { ) => {
$(#$meta)*
pub mod $mod_name { pub mod $mod_name {
#![allow(non_snake_case)] #![allow(non_snake_case)]
use std::env; use std::env;
use itconfig::EnvValue; use itconfig::EnvValue;
$( $(__itconfig_impl_namespace! {
pub mod $ns_name { variables = $ns_variable,
use std::env; namespaces = $ns_namespaces,
use itconfig::EnvValue; module = {
$(__itconfig_variable! {
meta = $ns_var_meta,
concat = $ns_var_concat,
name = $ns_var_name,
env_prefix = $ns_env_prefix, env_prefix = $ns_env_prefix,
$($ns_variables)* name = $ns_mod_name,
meta = [$(#$ns_meta)*],
},
})* })*
}
)*
pub fn init() { pub fn init() {
$($var_name();)* $($var_name();)*
$(
$($($ns_name::$ns_var_name();)*)* $(#$ns_meta)*
$ns_mod_name::init();
)*
} }
$(__itconfig_variable! { $(__itconfig_variable! {

View file

@ -10,3 +10,7 @@ publish = false
[dependencies] [dependencies]
itconfig = { path = '../itconfig' } itconfig = { path = '../itconfig' }
[features]
default = ["meta_namespace"]
meta_namespace = []

View file

@ -179,6 +179,39 @@ fn configuration_with_namespace() {
assert_eq!(cfg::DB::HOST(), true); assert_eq!(cfg::DB::HOST(), true);
} }
#[test]
fn configuration_with_nested_namespaces() {
config! {
FIRST {
SECOND {
THIRD {
FOO: u32 => 50,
}
}
}
}
cfg::init();
assert_eq!(cfg::FIRST::SECOND::THIRD::FOO(), 50);
}
#[cfg(feature = "meta_namespace")]
#[test]
fn configuration_namespaces_with_custom_meta() {
config! {
FIRST {
#[cfg(feature = "meta_namespace")]
SECOND {
THIRD {
FOO: u32 => 50,
}
}
}
}
cfg::init();
assert_eq!(cfg::FIRST::SECOND::THIRD::FOO(), 50);
}
#[test] #[test]
fn configuration_variables_and_namespace_in_lowercase() { fn configuration_variables_and_namespace_in_lowercase() {