parent
930e33a138
commit
bbbf355fc0
7 changed files with 148 additions and 155 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -11,6 +11,6 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "estring"
|
name = "estring"
|
||||||
version = "0.1.2"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72ea7e904ef7cb950eee02f9332b6a5c24c33bebeca6c027651b04f6c20658d9"
|
checksum = "515fc26a9876dfa25822d8cc040c6e4497ff9f5be96f101ee136d6ece160d2cc"
|
||||||
|
|
20
Cargo.toml
20
Cargo.toml
|
@ -5,12 +5,10 @@ authors = ["Dmitriy Pleshevskiy <dmitriy@ideascup.me>"]
|
||||||
description = "it helps you work with environment variables and convert it to any type using only type annotations"
|
description = "it helps you work with environment variables and convert it to any type using only type annotations"
|
||||||
categories = ["config"]
|
categories = ["config"]
|
||||||
keywords = ["env", "environment"]
|
keywords = ["env", "environment"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://github.com/pleshevskiy/enve"
|
repository = "https://github.com/pleshevskiy/enve"
|
||||||
|
rust-version = "1.59.0"
|
||||||
[package.metadata]
|
|
||||||
msrv = "1.51.0"
|
|
||||||
|
|
||||||
# https://docs.rs/about
|
# https://docs.rs/about
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
|
@ -20,17 +18,21 @@ all-features = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
number = ["estring/number"]
|
low-level = ["estring/low-level"]
|
||||||
bool = ["estring/bool"]
|
structs = ["estring/structs"]
|
||||||
vec = ["estring/vec"]
|
|
||||||
|
# deprecated
|
||||||
|
number = []
|
||||||
|
bool = []
|
||||||
|
vec = ["structs"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
estring = "0.1"
|
estring = "0.2"
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
maintenance = { status = "actively-developed" }
|
maintenance = { status = "actively-developed" }
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "calc"
|
name = "calc"
|
||||||
required-features = ["number", "vec"]
|
required-features = ["structs"]
|
||||||
|
|
||||||
|
|
255
src/core.rs
255
src/core.rs
|
@ -1,6 +1,5 @@
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use estring::EString;
|
use estring::{EString, ParseFragment, ToEString};
|
||||||
use std::convert::TryFrom;
|
|
||||||
|
|
||||||
/// Fetches the environment variable `key` from the current process. It set value `default`
|
/// Fetches the environment variable `key` from the current process. It set value `default`
|
||||||
/// if environment variable `key` ins'n set. Then this function tries to parse ``EString`` to
|
/// if environment variable `key` ins'n set. Then this function tries to parse ``EString`` to
|
||||||
|
@ -28,10 +27,10 @@ use std::convert::TryFrom;
|
||||||
#[allow(clippy::needless_pass_by_value)]
|
#[allow(clippy::needless_pass_by_value)]
|
||||||
pub fn get_or_set_default<R>(env_name: &str, default: R) -> Result<R, Error>
|
pub fn get_or_set_default<R>(env_name: &str, default: R) -> Result<R, Error>
|
||||||
where
|
where
|
||||||
R: TryFrom<EString> + std::fmt::Display,
|
R: ParseFragment + ToEString,
|
||||||
{
|
{
|
||||||
get::<R>(env_name).or_else(|err| match err {
|
get::<R>(env_name).or_else(|err| match err {
|
||||||
Error::NotPresent => sset(env_name, &default).parse().map_err(Error::from),
|
Error::NotPresent => sset(env_name, default).parse().map_err(Error::from),
|
||||||
_ => Err(err),
|
_ => Err(err),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -63,7 +62,7 @@ where
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get<R>(key: &str) -> Result<R, Error>
|
pub fn get<R>(key: &str) -> Result<R, Error>
|
||||||
where
|
where
|
||||||
R: TryFrom<EString>,
|
R: ParseFragment,
|
||||||
{
|
{
|
||||||
sget(key).and_then(|v| v.parse().map_err(Error::from))
|
sget(key).and_then(|v| v.parse().map_err(Error::from))
|
||||||
}
|
}
|
||||||
|
@ -108,18 +107,20 @@ pub fn sget(key: &str) -> Result<EString, Error> {
|
||||||
/// let estr = enve::sset("KEY", "10");
|
/// let estr = enve::sset("KEY", "10");
|
||||||
/// assert_eq!(estr.to_string(), String::from("10"));
|
/// assert_eq!(estr.to_string(), String::from("10"));
|
||||||
/// ```
|
/// ```
|
||||||
|
#[allow(clippy::needless_pass_by_value)]
|
||||||
pub fn sset<V>(key: &str, value: V) -> EString
|
pub fn sset<V>(key: &str, value: V) -> EString
|
||||||
where
|
where
|
||||||
V: std::fmt::Display,
|
V: ToEString,
|
||||||
{
|
{
|
||||||
let val = value.to_string();
|
let es = value.to_estring();
|
||||||
std::env::set_var(key, &val);
|
std::env::set_var(key, &*es);
|
||||||
val.into()
|
es
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::estr::{CommaVec, SemiVec, SepVec};
|
||||||
|
|
||||||
struct TestCase<const N: u8>;
|
struct TestCase<const N: u8>;
|
||||||
|
|
||||||
|
@ -171,150 +172,134 @@ mod tests {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "number")]
|
#[test]
|
||||||
mod numbers {
|
fn should_return_parsed_num() {
|
||||||
use super::*;
|
let en = TestCase::<4>.to_string();
|
||||||
|
std::env::set_var(&en, "-10");
|
||||||
#[test]
|
match get::<i32>(&en) {
|
||||||
fn should_return_parsed_num() {
|
Ok(res) => assert_eq!(res, -10),
|
||||||
let en = TestCase::<4>.to_string();
|
_ => unreachable!(),
|
||||||
std::env::set_var(&en, "-10");
|
};
|
||||||
match get::<i32>(&en) {
|
|
||||||
Ok(res) => assert_eq!(res, -10),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_throw_parse_error() {
|
|
||||||
let en = TestCase::<5>.to_string();
|
|
||||||
std::env::set_var(&en, "-10");
|
|
||||||
match get::<u32>(&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::<6>.to_string();
|
|
||||||
let orig = 10;
|
|
||||||
match get_or_set_default(&en, orig) {
|
|
||||||
Ok(res) => {
|
|
||||||
assert_eq!(res, orig);
|
|
||||||
assert_eq!(std::env::var(&en).unwrap(), "10");
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "bool")]
|
#[test]
|
||||||
mod boolean {
|
fn should_throw_parse_error() {
|
||||||
use super::*;
|
let en = TestCase::<5>.to_string();
|
||||||
|
std::env::set_var(&en, "-10");
|
||||||
#[test]
|
match get::<u32>(&en) {
|
||||||
fn should_parse_bool_variable() {
|
Err(Error::Parse(orig)) => {
|
||||||
let en = TestCase::<7>.to_string();
|
assert_eq!(orig, EString::from("-10"));
|
||||||
|
|
||||||
let test_cases = [
|
|
||||||
("1", true),
|
|
||||||
("y", true),
|
|
||||||
("yes", true),
|
|
||||||
("true", true),
|
|
||||||
("t", true),
|
|
||||||
("on", true),
|
|
||||||
("false", false),
|
|
||||||
("f", false),
|
|
||||||
("0", false),
|
|
||||||
];
|
|
||||||
for (val, expected) in &test_cases {
|
|
||||||
let mut en = en.clone();
|
|
||||||
en.push_str(val.as_ref());
|
|
||||||
|
|
||||||
std::env::set_var(&en, val);
|
|
||||||
match get::<bool>(&en) {
|
|
||||||
Ok(res) => assert_eq!(res, *expected),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "vec")]
|
#[test]
|
||||||
mod vector {
|
fn should_set_default_num_if_var_is_no_present() {
|
||||||
use super::*;
|
let en = TestCase::<6>.to_string();
|
||||||
use crate::estr::{CommaVec, SemiVec, SepVec};
|
let orig = 10;
|
||||||
|
match get_or_set_default(&en, orig) {
|
||||||
|
Ok(res) => {
|
||||||
|
assert_eq!(res, orig);
|
||||||
|
assert_eq!(std::env::var(&en).unwrap(), "10");
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_return_var_as_vector() {
|
fn should_parse_bool_variable() {
|
||||||
let en = TestCase::<8>.to_string();
|
let en = TestCase::<7>.to_string();
|
||||||
|
|
||||||
std::env::set_var(&en, "1,2,3,4,5");
|
let test_cases = [
|
||||||
match get::<CommaVec<i32>>(&en) {
|
("1", true),
|
||||||
Ok(res) => assert_eq!(*res, vec![1, 2, 3, 4, 5]),
|
("y", true),
|
||||||
|
("yes", true),
|
||||||
|
("true", true),
|
||||||
|
("t", true),
|
||||||
|
("on", true),
|
||||||
|
("false", false),
|
||||||
|
("f", false),
|
||||||
|
("0", false),
|
||||||
|
];
|
||||||
|
for (val, expected) in test_cases {
|
||||||
|
let mut en = en.clone();
|
||||||
|
en.push_str(val.as_ref());
|
||||||
|
|
||||||
|
std::env::set_var(&en, val);
|
||||||
|
match get::<bool>(&en) {
|
||||||
|
Ok(res) => assert_eq!(res, expected),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_trim_identations_before_parsing() {
|
fn should_return_var_as_vector() {
|
||||||
let en = TestCase::<9>.to_string();
|
let en = TestCase::<8>.to_string();
|
||||||
|
|
||||||
let input = "
|
std::env::set_var(&en, "1,2,3,4,5");
|
||||||
|
match get::<CommaVec<i32>>(&en) {
|
||||||
|
Ok(res) => assert_eq!(*res, vec![1, 2, 3, 4, 5]),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_trim_identations_before_parsing() {
|
||||||
|
let en = TestCase::<9>.to_string();
|
||||||
|
|
||||||
|
let input = "
|
||||||
1 , 2, 3,
|
1 , 2, 3,
|
||||||
4,5";
|
4,5";
|
||||||
|
|
||||||
std::env::set_var(&en, input);
|
std::env::set_var(&en, input);
|
||||||
match get::<CommaVec<i32>>(&en) {
|
match get::<CommaVec<i32>>(&en) {
|
||||||
Ok(res) => assert_eq!(*res, vec![1, 2, 3, 4, 5]),
|
Ok(res) => assert_eq!(*res, vec![1, 2, 3, 4, 5]),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_return_vector_of_vectors() {
|
fn should_return_vector_of_vectors() {
|
||||||
let en = TestCase::<10>.to_string();
|
let en = TestCase::<10>.to_string();
|
||||||
|
|
||||||
std::env::set_var(&en, "1,2; 3,4,5; 6,7");
|
std::env::set_var(&en, "1,2; 3,4,5; 6,7");
|
||||||
match get::<SemiVec<CommaVec<i32>>>(&en) {
|
match get::<SemiVec<CommaVec<i32>>>(&en) {
|
||||||
Ok(res) => assert_eq!(
|
Ok(res) => assert_eq!(
|
||||||
res,
|
res,
|
||||||
SemiVec::from(vec![
|
SemiVec::from(vec![
|
||||||
CommaVec::from(vec![1, 2]),
|
CommaVec::from(vec![1, 2]),
|
||||||
CommaVec::from(vec![3, 4, 5]),
|
CommaVec::from(vec![3, 4, 5]),
|
||||||
CommaVec::from(vec![6, 7])
|
CommaVec::from(vec![6, 7])
|
||||||
])
|
])
|
||||||
),
|
),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_throw_parse_vec_error() {
|
fn should_throw_parse_vec_error() {
|
||||||
let en = TestCase::<11>.to_string();
|
let en = TestCase::<11>.to_string();
|
||||||
std::env::set_var(&en, "1,2,3,4,5");
|
std::env::set_var(&en, "1,2,3,4,5");
|
||||||
match get::<SepVec<i32, '+'>>(&en) {
|
match get::<SepVec<i32, '+'>>(&en) {
|
||||||
Err(Error::Parse(orig)) => {
|
Err(Error::Parse(orig)) => {
|
||||||
assert_eq!(orig, String::from("1,2,3,4,5"));
|
assert_eq!(orig, EString::from("1,2,3,4,5"));
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_set_default_vector_if_var_is_no_present() {
|
fn should_set_default_vector_if_var_is_no_present() {
|
||||||
let en = TestCase::<12>.to_string();
|
let en = TestCase::<12>.to_string();
|
||||||
let orig = CommaVec::from(vec![1, 2, 3, 4]);
|
let orig = CommaVec::from(vec![1, 2, 3, 4]);
|
||||||
match get_or_set_default(&en, orig.clone()) {
|
match get_or_set_default(&en, orig.clone()) {
|
||||||
Ok(res) => {
|
Ok(res) => {
|
||||||
assert_eq!(res, orig);
|
assert_eq!(res, orig);
|
||||||
assert_eq!(std::env::var(&en).unwrap(), "1,2,3,4");
|
assert_eq!(std::env::var(&en).unwrap(), "1,2,3,4");
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
10
src/error.rs
10
src/error.rs
|
@ -3,6 +3,8 @@ use std::error;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use estring::EString;
|
||||||
|
|
||||||
/// The error type for operations interacting with environment variables
|
/// The error type for operations interacting with environment variables
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -10,7 +12,7 @@ pub enum Error {
|
||||||
NotPresent,
|
NotPresent,
|
||||||
|
|
||||||
/// Failed to parse the specified environment variable.
|
/// Failed to parse the specified environment variable.
|
||||||
Parse(String),
|
Parse(EString),
|
||||||
|
|
||||||
/// The specified environment variable was found, but it did not contain
|
/// The specified environment variable was found, but it did not contain
|
||||||
/// valid unicode data. The found data is returned as a payload of this
|
/// valid unicode data. The found data is returned as a payload of this
|
||||||
|
@ -45,8 +47,8 @@ impl From<VarError> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<estring::ParseError> for Error {
|
impl From<estring::Error> for Error {
|
||||||
fn from(err: estring::ParseError) -> Self {
|
fn from(err: estring::Error) -> Self {
|
||||||
Error::Parse(err.clone())
|
Error::Parse(err.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
src/estr.rs
12
src/estr.rs
|
@ -1,6 +1,8 @@
|
||||||
#[cfg(feature = "vec")]
|
#[cfg(feature = "structs")]
|
||||||
mod vec;
|
mod structs;
|
||||||
#[cfg(feature = "vec")]
|
#[cfg(feature = "structs")]
|
||||||
pub use vec::{CommaVec, SemiVec};
|
pub use structs::{CommaVec, SemiVec};
|
||||||
|
|
||||||
pub use estring::core::*;
|
pub use estring::core::EString;
|
||||||
|
pub use estring::low::*;
|
||||||
|
pub use estring::structs::*;
|
||||||
|
|
|
@ -62,3 +62,5 @@ mod estr;
|
||||||
pub use crate::core::{get, get_or_set_default, sget, sset};
|
pub use crate::core::{get, get_or_set_default, sget, sset};
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
pub use estr::*;
|
pub use estr::*;
|
||||||
|
|
||||||
|
pub use estring;
|
||||||
|
|
Reference in a new issue