parent
930e33a138
commit
eba9dfe96b
7 changed files with 148 additions and 155 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -11,6 +11,6 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "estring"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
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"
|
||||
categories = ["config"]
|
||||
keywords = ["env", "environment"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/pleshevskiy/enve"
|
||||
|
||||
[package.metadata]
|
||||
msrv = "1.51.0"
|
||||
rust-version = "1.59.0"
|
||||
|
||||
# https://docs.rs/about
|
||||
[package.metadata.docs.rs]
|
||||
|
@ -20,17 +18,21 @@ all-features = true
|
|||
|
||||
[features]
|
||||
default = []
|
||||
number = ["estring/number"]
|
||||
bool = ["estring/bool"]
|
||||
vec = ["estring/vec"]
|
||||
low-level = ["estring/low-level"]
|
||||
structs = ["estring/structs"]
|
||||
|
||||
# deprecated
|
||||
number = []
|
||||
bool = []
|
||||
vec = ["structs"]
|
||||
|
||||
[dependencies]
|
||||
estring = "0.1"
|
||||
estring = "0.2"
|
||||
|
||||
[badges]
|
||||
maintenance = { status = "actively-developed" }
|
||||
|
||||
[[example]]
|
||||
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 estring::EString;
|
||||
use std::convert::TryFrom;
|
||||
use estring::{EString, ParseFragment, ToEString};
|
||||
|
||||
/// 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
|
||||
|
@ -28,10 +27,10 @@ use std::convert::TryFrom;
|
|||
#[allow(clippy::needless_pass_by_value)]
|
||||
pub fn get_or_set_default<R>(env_name: &str, default: R) -> Result<R, Error>
|
||||
where
|
||||
R: TryFrom<EString> + std::fmt::Display,
|
||||
R: ParseFragment + ToEString,
|
||||
{
|
||||
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),
|
||||
})
|
||||
}
|
||||
|
@ -63,7 +62,7 @@ where
|
|||
/// ```
|
||||
pub fn get<R>(key: &str) -> Result<R, Error>
|
||||
where
|
||||
R: TryFrom<EString>,
|
||||
R: ParseFragment,
|
||||
{
|
||||
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");
|
||||
/// assert_eq!(estr.to_string(), String::from("10"));
|
||||
/// ```
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
pub fn sset<V>(key: &str, value: V) -> EString
|
||||
where
|
||||
V: std::fmt::Display,
|
||||
V: ToEString,
|
||||
{
|
||||
let val = value.to_string();
|
||||
std::env::set_var(key, &val);
|
||||
val.into()
|
||||
let es = value.to_estring();
|
||||
std::env::set_var(key, &*es);
|
||||
es
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::estr::{CommaVec, SemiVec, SepVec};
|
||||
|
||||
struct TestCase<const N: u8>;
|
||||
|
||||
|
@ -171,150 +172,134 @@ mod tests {
|
|||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "number")]
|
||||
mod numbers {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn should_return_parsed_num() {
|
||||
let en = TestCase::<4>.to_string();
|
||||
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!(),
|
||||
};
|
||||
}
|
||||
#[test]
|
||||
fn should_return_parsed_num() {
|
||||
let en = TestCase::<4>.to_string();
|
||||
std::env::set_var(&en, "-10");
|
||||
match get::<i32>(&en) {
|
||||
Ok(res) => assert_eq!(res, -10),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "bool")]
|
||||
mod boolean {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn should_parse_bool_variable() {
|
||||
let en = TestCase::<7>.to_string();
|
||||
|
||||
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!(),
|
||||
};
|
||||
#[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, EString::from("-10"));
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "vec")]
|
||||
mod vector {
|
||||
use super::*;
|
||||
use crate::estr::{CommaVec, SemiVec, SepVec};
|
||||
#[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!(),
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_var_as_vector() {
|
||||
let en = TestCase::<8>.to_string();
|
||||
#[test]
|
||||
fn should_parse_bool_variable() {
|
||||
let en = TestCase::<7>.to_string();
|
||||
|
||||
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]),
|
||||
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!(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_trim_identations_before_parsing() {
|
||||
let en = TestCase::<9>.to_string();
|
||||
#[test]
|
||||
fn should_return_var_as_vector() {
|
||||
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,
|
||||
4,5";
|
||||
|
||||
std::env::set_var(&en, input);
|
||||
match get::<CommaVec<i32>>(&en) {
|
||||
Ok(res) => assert_eq!(*res, vec![1, 2, 3, 4, 5]),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
std::env::set_var(&en, input);
|
||||
match get::<CommaVec<i32>>(&en) {
|
||||
Ok(res) => assert_eq!(*res, vec![1, 2, 3, 4, 5]),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_vector_of_vectors() {
|
||||
let en = TestCase::<10>.to_string();
|
||||
#[test]
|
||||
fn should_return_vector_of_vectors() {
|
||||
let en = TestCase::<10>.to_string();
|
||||
|
||||
std::env::set_var(&en, "1,2; 3,4,5; 6,7");
|
||||
match get::<SemiVec<CommaVec<i32>>>(&en) {
|
||||
Ok(res) => assert_eq!(
|
||||
res,
|
||||
SemiVec::from(vec![
|
||||
CommaVec::from(vec![1, 2]),
|
||||
CommaVec::from(vec![3, 4, 5]),
|
||||
CommaVec::from(vec![6, 7])
|
||||
])
|
||||
),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
std::env::set_var(&en, "1,2; 3,4,5; 6,7");
|
||||
match get::<SemiVec<CommaVec<i32>>>(&en) {
|
||||
Ok(res) => assert_eq!(
|
||||
res,
|
||||
SemiVec::from(vec![
|
||||
CommaVec::from(vec![1, 2]),
|
||||
CommaVec::from(vec![3, 4, 5]),
|
||||
CommaVec::from(vec![6, 7])
|
||||
])
|
||||
),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_throw_parse_vec_error() {
|
||||
let en = TestCase::<11>.to_string();
|
||||
std::env::set_var(&en, "1,2,3,4,5");
|
||||
match get::<SepVec<i32, '+'>>(&en) {
|
||||
Err(Error::Parse(orig)) => {
|
||||
assert_eq!(orig, String::from("1,2,3,4,5"));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
#[test]
|
||||
fn should_throw_parse_vec_error() {
|
||||
let en = TestCase::<11>.to_string();
|
||||
std::env::set_var(&en, "1,2,3,4,5");
|
||||
match get::<SepVec<i32, '+'>>(&en) {
|
||||
Err(Error::Parse(orig)) => {
|
||||
assert_eq!(orig, EString::from("1,2,3,4,5"));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_set_default_vector_if_var_is_no_present() {
|
||||
let en = TestCase::<12>.to_string();
|
||||
let orig = CommaVec::from(vec![1, 2, 3, 4]);
|
||||
match get_or_set_default(&en, orig.clone()) {
|
||||
Ok(res) => {
|
||||
assert_eq!(res, orig);
|
||||
assert_eq!(std::env::var(&en).unwrap(), "1,2,3,4");
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
#[test]
|
||||
fn should_set_default_vector_if_var_is_no_present() {
|
||||
let en = TestCase::<12>.to_string();
|
||||
let orig = CommaVec::from(vec![1, 2, 3, 4]);
|
||||
match get_or_set_default(&en, orig.clone()) {
|
||||
Ok(res) => {
|
||||
assert_eq!(res, orig);
|
||||
assert_eq!(std::env::var(&en).unwrap(), "1,2,3,4");
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
10
src/error.rs
10
src/error.rs
|
@ -3,6 +3,8 @@ use std::error;
|
|||
use std::ffi::OsString;
|
||||
use std::fmt;
|
||||
|
||||
use estring::EString;
|
||||
|
||||
/// The error type for operations interacting with environment variables
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
|
@ -10,7 +12,7 @@ pub enum Error {
|
|||
NotPresent,
|
||||
|
||||
/// Failed to parse the specified environment variable.
|
||||
Parse(String),
|
||||
Parse(EString),
|
||||
|
||||
/// The specified environment variable was found, but it did not contain
|
||||
/// 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 {
|
||||
fn from(err: estring::ParseError) -> Self {
|
||||
Error::Parse(err.clone())
|
||||
impl From<estring::Error> for Error {
|
||||
fn from(err: estring::Error) -> Self {
|
||||
Error::Parse(err.0)
|
||||
}
|
||||
}
|
||||
|
|
12
src/estr.rs
12
src/estr.rs
|
@ -1,6 +1,8 @@
|
|||
#[cfg(feature = "vec")]
|
||||
mod vec;
|
||||
#[cfg(feature = "vec")]
|
||||
pub use vec::{CommaVec, SemiVec};
|
||||
#[cfg(feature = "structs")]
|
||||
mod structs;
|
||||
#[cfg(feature = "structs")]
|
||||
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 error::Error;
|
||||
pub use estr::*;
|
||||
|
||||
pub use estring;
|
||||
|
|
Reference in a new issue