diff --git a/Cargo.lock b/Cargo.lock index e5e135a..664d82e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -194,6 +194,7 @@ dependencies = [ name = "itconfig" version = "1.1.1" dependencies = [ + "criterion", "itconfig-macro", "lazy_static", ] @@ -209,15 +210,6 @@ dependencies = [ "syn", ] -[[package]] -name = "itconfig_tests" -version = "0.1.0" -dependencies = [ - "criterion", - "itconfig", - "lazy_static", -] - [[package]] name = "itertools" version = "0.10.3" diff --git a/Cargo.toml b/Cargo.toml index c9ef965..42e7df4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,44 @@ [workspace] members = [ - "itconfig", "itconfig-macro", - "itconfig-tests", ] +[package] +name = "itconfig" +version = "1.1.1" +authors = ["Dmitriy Pleshevskiy "] +description = "Easy build a configs from environment variables and use it in globally." +categories = ["config", "web-programming"] +keywords = ["config", "env", "configuration", "environment", "macro"] +edition = "2018" +license = "MIT" +repository = "https://github.com/pleshevskiy/itconfig-rs" +homepage = "https://github.com/pleshevskiy/itconfig-rs" +documentation = "https://docs.rs/itconfig" +readme = "../README.md" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[features] +default = [] + +macro = ["itconfig-macro"] + +number = [] +bool = [] +vec = [] + +[dependencies] +itconfig-macro = { version = "1.1", path = "itconfig-macro", optional = true } + +[dev-dependencies] +lazy_static = "1.4.0" +criterion = "0.3.1" + +[badges] +maintenance = { status = "actively-developed" } + +# https://docs.rs/about +[package.metadata.docs.rs] +all-features = true + diff --git a/itconfig-tests/benches/main_benches.rs b/benches/main_benches.rs similarity index 100% rename from itconfig-tests/benches/main_benches.rs rename to benches/main_benches.rs diff --git a/itconfig-macro/Cargo.toml b/itconfig-macro/Cargo.toml index 45c81ba..4d88505 100644 --- a/itconfig-macro/Cargo.toml +++ b/itconfig-macro/Cargo.toml @@ -22,7 +22,7 @@ quote = "1.0.9" proc-macro2 = "1.0.24" [dev-dependencies] -itconfig = { path = "../itconfig" } +itconfig = { path = ".." } lazy_static = "1.4.0" [badges] diff --git a/itconfig-tests/Cargo.toml b/itconfig-tests/Cargo.toml deleted file mode 100644 index 7a72838..0000000 --- a/itconfig-tests/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "itconfig_tests" -version = "0.1.0" -authors = ["Dmitriy Pleshevskiy "] -edition = "2018" -license = "MIT" -publish = false - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -itconfig = { path = '../itconfig', features = ["macro"] } -criterion = "0.3.1" -lazy_static = "1.4.0" - -[features] -default = ["meta_namespace"] -meta_namespace = [] - -[[bench]] -name = "main_benches" -harness = false diff --git a/itconfig/Cargo.toml b/itconfig/Cargo.toml deleted file mode 100644 index 5a408eb..0000000 --- a/itconfig/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -[package] -name = "itconfig" -version = "1.1.1" -authors = ["Dmitriy Pleshevskiy "] -description = "Easy build a configs from environment variables and use it in globally." -categories = ["config", "web-programming"] -keywords = ["config", "env", "configuration", "environment", "macro"] -edition = "2018" -license = "MIT" -repository = "https://github.com/pleshevskiy/itconfig-rs" -homepage = "https://github.com/pleshevskiy/itconfig-rs" -documentation = "https://docs.rs/itconfig" -readme = "../README.md" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[features] -default = [] - -macro = ["itconfig-macro"] - -number = [] -bool = [] -vec = [] - -[dependencies] -itconfig-macro = { version = "1.1", path = "../itconfig-macro", optional = true } - -[dev-dependencies] -lazy_static = "1.4.0" - -[badges] -maintenance = { status = "actively-developed" } - -# https://docs.rs/about -[package.metadata.docs.rs] -all-features = true - diff --git a/itconfig/src/utils.rs b/itconfig/src/utils.rs deleted file mode 100644 index 6f33da4..0000000 --- a/itconfig/src/utils.rs +++ /dev/null @@ -1,116 +0,0 @@ -use crate::core::EString; -use crate::error::Error; -use std::convert::{TryFrom, TryInto}; -use std::env; - -pub fn get_env_or_set_default(env_name: &str, default: R) -> Result -where - R: TryFrom + std::fmt::Display, -{ - get_env::(env_name).or_else(|err| match err { - Error::NotPresent => { - let val = default.to_string(); - env::set_var(env_name, &val); - EString::from(val) - .try_into() - .map_err(|_| Error::Parse(default.to_string())) - } - _ => Err(err), - }) -} - -pub fn get_env(env_name: &str) -> Result -where - R: TryFrom, -{ - env::var(env_name) - .map_err(From::from) - .map(EString::from) - .and_then(|val| { - val.clone() - .try_into() - .map_err(|_| Error::Parse(val.to_string())) - }) -} - -#[cfg(test)] -mod tests { - use super::*; - #[cfg(feature = "vec")] - use crate::core::vec::{CommaVec, SepVec}; - - #[test] - fn should_return_variable() { - env::set_var("get_env_1", "hello"); - match get_env::<&str>("get_env_1") { - Ok(res) => assert_eq!(res, "hello"), - _ => unreachable!(), - }; - } - - #[test] - fn should_throw_no_present_error() { - match get_env::<&str>("get_env_2") { - Err(Error::NotPresent) => {} - _ => unreachable!(), - }; - } - - #[test] - fn should_throw_parse_error() { - env::set_var("get_env_3", "-10"); - match get_env::("get_env_3") { - Err(Error::Parse(orig)) => { - assert_eq!(orig, String::from("-10")) - } - _ => unreachable!(), - }; - } - - #[test] - fn should_set_default_if_var_is_no_present() { - let orig = 10; - match get_env_or_set_default("get_env_4", orig) { - Ok(res) => { - assert_eq!(res, orig); - assert_eq!(env::var("get_env_4").unwrap(), "10"); - } - _ => unreachable!(), - }; - } - - #[cfg(feature = "vec")] - #[test] - fn should_return_var_as_vector() { - env::set_var("get_env_5", "1,2,3,4,5"); - match get_env::>("get_env_5") { - Ok(res) => assert_eq!(*res, vec![1, 2, 3, 4, 5]), - _ => unreachable!(), - }; - } - - #[cfg(feature = "vec")] - #[test] - fn should_throw_parse_vec_error() { - env::set_var("get_env_6", "1,2,3,4,5"); - match get_env::>("get_env_6") { - Err(Error::Parse(orig)) => { - assert_eq!(orig, String::from("1,2,3,4,5")) - } - _ => unreachable!(), - }; - } - - #[cfg(feature = "vec")] - #[test] - fn should_set_default_vector_if_var_is_no_present() { - let orig = CommaVec::from(vec![1, 2, 3, 4]); - match get_env_or_set_default("get_env_7", orig.clone()) { - Ok(res) => { - assert_eq!(res, orig); - assert_eq!(env::var("get_env_7").unwrap(), "1,2,3,4"); - } - _ => unreachable!(), - }; - } -} diff --git a/itconfig/src/core.rs b/src/core.rs similarity index 100% rename from itconfig/src/core.rs rename to src/core.rs diff --git a/itconfig/src/core/prim.rs b/src/core/prim.rs similarity index 100% rename from itconfig/src/core/prim.rs rename to src/core/prim.rs diff --git a/itconfig/src/core/vec.rs b/src/core/vec.rs similarity index 82% rename from itconfig/src/core/vec.rs rename to src/core/vec.rs index 307440c..0857285 100644 --- a/itconfig/src/core/vec.rs +++ b/src/core/vec.rs @@ -1,4 +1,4 @@ -use crate::core::EnvString; +use crate::core::EString; use std::convert::TryFrom; use std::fmt::Write; @@ -42,16 +42,16 @@ where } } -impl TryFrom for SepVec +impl TryFrom for SepVec where - T: TryFrom + std::fmt::Display, + T: TryFrom + std::fmt::Display, { type Error = T::Error; - fn try_from(value: EnvString) -> Result { + fn try_from(value: EString) -> Result { let inner = value .split(SEP) - .map(EnvString::from) + .map(EString::from) .map(T::try_from) .collect::, _>>()?; Ok(Self(inner)) diff --git a/itconfig/src/error.rs b/src/error.rs similarity index 100% rename from itconfig/src/error.rs rename to src/error.rs diff --git a/itconfig/src/lib.rs b/src/lib.rs similarity index 100% rename from itconfig/src/lib.rs rename to src/lib.rs diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..fa1ed61 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,182 @@ +use crate::core::EString; +use crate::error::Error; +use std::convert::{TryFrom, TryInto}; +use std::env; + +pub fn get_env_or_set_default(env_name: &str, default: R) -> Result +where + R: TryFrom + std::fmt::Display, +{ + get_env::(env_name).or_else(|err| match err { + Error::NotPresent => { + let val = default.to_string(); + env::set_var(env_name, &val); + EString::from(val) + .try_into() + .map_err(|_| Error::Parse(default.to_string())) + } + _ => Err(err), + }) +} + +pub fn get_env(env_name: &str) -> Result +where + R: TryFrom, +{ + env::var(env_name) + .map_err(From::from) + .map(EString::from) + .and_then(|val| { + val.clone() + .try_into() + .map_err(|_| Error::Parse(val.to_string())) + }) +} + +#[cfg(test)] +mod tests { + use super::*; + + struct TestCase; + + impl std::fmt::Display for TestCase { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "get_env_{}", N) + } + } + + #[test] + fn should_return_variable() { + let en = TestCase::<1>.to_string(); + env::set_var(&en, "hello"); + match get_env::<&str>(&en) { + Ok(res) => assert_eq!(res, "hello"), + _ => unreachable!(), + }; + } + + #[test] + fn should_throw_no_present_error() { + let en = TestCase::<2>.to_string(); + match get_env::<&str>(&en) { + Err(Error::NotPresent) => {} + _ => unreachable!(), + }; + } + + #[test] + fn should_set_default_if_var_is_no_present() { + let en = TestCase::<3>.to_string(); + let orig = "hello"; + match get_env_or_set_default(&en, orig) { + Ok(res) => { + assert_eq!(res, orig); + assert_eq!(env::var(&en).unwrap(), orig); + } + _ => unreachable!(), + }; + } + + #[cfg(feature = "number")] + mod numbers { + use super::*; + + #[test] + fn should_throw_parse_error() { + let en = TestCase::<4>.to_string(); + env::set_var(&en, "-10"); + match get_env::(&en) { + Err(Error::Parse(orig)) => { + assert_eq!(orig, String::from("-10")) + } + _ => unreachable!(), + }; + } + + #[test] + fn should_set_default_num_if_var_is_no_present() { + let en = TestCase::<5>.to_string(); + let orig = 10; + match get_env_or_set_default(&en, orig) { + Ok(res) => { + assert_eq!(res, orig); + assert_eq!(env::var(&en).unwrap(), "10"); + } + _ => unreachable!(), + }; + } + } + + #[cfg(feature = "bool")] + mod boolean { + use super::*; + + #[test] + fn should_parse_bool_variable() { + let en = TestCase::<5>.to_string(); + + [ + ("y", true), + ("yes", true), + ("true", true), + ("t", true), + ("on", true), + ("false", false), + ("f", false), + ] + .iter() + .for_each(|(val, expected)| { + let mut en = en.clone(); + en.push_str(val.as_ref()); + + env::set_var(&en, val); + match get_env::(&en) { + Ok(res) => assert_eq!(res, *expected), + _ => unreachable!(), + }; + }) + } + } + + #[cfg(feature = "vec")] + mod vector { + use super::*; + use crate::core::vec::{CommaVec, SepVec}; + + #[test] + fn should_return_var_as_vector() { + let en = TestCase::<6>.to_string(); + + env::set_var(&en, "1,2,3,4,5"); + match get_env::>(&en) { + Ok(res) => assert_eq!(*res, vec![1, 2, 3, 4, 5]), + _ => unreachable!(), + }; + } + + #[test] + fn should_throw_parse_vec_error() { + let en = TestCase::<7>.to_string(); + env::set_var(&en, "1,2,3,4,5"); + match get_env::>(&en) { + Err(Error::Parse(orig)) => { + assert_eq!(orig, String::from("1,2,3,4,5")) + } + _ => unreachable!(), + }; + } + + #[test] + fn should_set_default_vector_if_var_is_no_present() { + let en = TestCase::<8>.to_string(); + let orig = CommaVec::from(vec![1, 2, 3, 4]); + match get_env_or_set_default(&en, orig.clone()) { + Ok(res) => { + assert_eq!(res, orig); + assert_eq!(env::var(&en).unwrap(), "1,2,3,4"); + } + _ => unreachable!(), + }; + } + } +} diff --git a/itconfig-tests/tests/config_macro.rs b/tests/config_macro.rs similarity index 100% rename from itconfig-tests/tests/config_macro.rs rename to tests/config_macro.rs