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

View file

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

View file

@ -25,22 +25,36 @@
//! POSTGRES_DB => "test",
//! ),
//!
//! NAMESPACE {
//! #[env_name = "MY_CUSTOM_NAME"]
//! FOO: bool,
//! APP {
//! ARTICLE {
//! 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 () {
//! // dotenv().ok();
//! env::set_var("MY_CUSTOM_NAME", "t");
//! env::set_var("FEATURE_NEW_MENU", "t");
//!
//! cfg::init();
//! 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::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()
/// ```
///
/// 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
/// ----
///
@ -343,6 +392,7 @@ macro_rules! __itconfig_parse_module {
module = {
env_prefix = "",
name = $name,
meta = [],
},
}
};
@ -360,6 +410,7 @@ macro_rules! __itconfig_parse_variables {
// Find namespace
(
tokens = [
$(#$meta:tt)*
$ns_name:ident { $($ns_tokens:tt)* }
$($rest:tt)*
],
@ -368,9 +419,11 @@ macro_rules! __itconfig_parse_variables {
__itconfig_parse_variables! {
tokens = [$($ns_tokens)*],
variables = [],
namespaces = [],
module = {
env_prefix = concat!(stringify!($ns_name), "_"),
name = $ns_name,
meta = [$(#$meta)*],
},
callback = {
tokens = [$($rest)*],
@ -526,9 +579,8 @@ macro_rules! __itconfig_parse_variables {
(
tokens = [],
variables = $ns_variables:tt,
module = {
$($current_namespace:tt)*
},
namespaces = $ns_namespaces:tt,
module = $ns_module:tt,
callback = {
tokens = $tokens:tt,
variables = $variables:tt,
@ -543,7 +595,8 @@ macro_rules! __itconfig_parse_variables {
$($namespaces,)*
{
variables = $ns_variables,
$($current_namespace)*
namespaces = $ns_namespaces,
module = $ns_module,
},
],
$($args)*
@ -555,7 +608,7 @@ macro_rules! __itconfig_parse_variables {
tokens = [],
$($args:tt)*
) => {
__itconfig_impl!($($args)*);
__itconfig_impl_namespace!($($args)*);
};
// Invalid syntax
@ -567,7 +620,7 @@ macro_rules! __itconfig_parse_variables {
#[macro_export]
#[doc(hidden)]
macro_rules! __itconfig_impl {
macro_rules! __itconfig_impl_namespace {
(
variables = [$({
meta = $var_meta:tt,
@ -576,44 +629,42 @@ macro_rules! __itconfig_impl {
$($variable:tt)*
},)*],
namespaces = [$({
variables = [$({
meta = $ns_var_meta:tt,
concat = $ns_var_concat:tt,
name = $ns_var_name:ident,
$($ns_variables:tt)*
},)*],
variables = $ns_variable:tt,
namespaces = $ns_namespaces:tt,
module = {
env_prefix = $ns_env_prefix:expr,
name = $ns_name:ident,
name = $ns_mod_name:ident,
meta = [$(#$ns_meta:tt)*],
},
},)*],
module = {
env_prefix = $env_prefix:expr,
name = $mod_name:ident,
meta = [$(#$meta:tt)*],
},
) => {
$(#$meta)*
pub mod $mod_name {
#![allow(non_snake_case)]
use std::env;
use itconfig::EnvValue;
$(
pub mod $ns_name {
use std::env;
use itconfig::EnvValue;
$(__itconfig_variable! {
meta = $ns_var_meta,
concat = $ns_var_concat,
name = $ns_var_name,
$(__itconfig_impl_namespace! {
variables = $ns_variable,
namespaces = $ns_namespaces,
module = {
env_prefix = $ns_env_prefix,
$($ns_variables)*
name = $ns_mod_name,
meta = [$(#$ns_meta)*],
},
})*
}
)*
pub fn init() {
$($var_name();)*
$($($ns_name::$ns_var_name();)*)*
$(
$(#$ns_meta)*
$ns_mod_name::init();
)*
}
$(__itconfig_variable! {

View file

@ -10,3 +10,7 @@ publish = false
[dependencies]
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);
}
#[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]
fn configuration_variables_and_namespace_in_lowercase() {