Merge pull request #8 from icetemple/nested-namespaces
Nested namespaces
This commit is contained in:
commit
9ba03de940
6 changed files with 179 additions and 63 deletions
36
README.md
36
README.md
|
@ -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
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "itconfig"
|
||||
version = "0.7.1"
|
||||
version = "0.8.0"
|
||||
authors = ["Dmitriy Pleshevskiy <dmitriy@ideascup.me>"]
|
||||
description = "Easy build a configs from environment variables and use it in globally."
|
||||
categories = ["config", "web-programming"]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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! {
|
||||
|
|
|
@ -10,3 +10,7 @@ publish = false
|
|||
|
||||
[dependencies]
|
||||
itconfig = { path = '../itconfig' }
|
||||
|
||||
[features]
|
||||
default = ["meta_namespace"]
|
||||
meta_namespace = []
|
||||
|
|
|
@ -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() {
|
||||
|
|
Reference in a new issue