mirror of
https://github.com/darwincereska/envkit.git
synced 2026-06-11 10:23:23 -05:00
feat: updated bool parsing and added tests
This commit is contained in:
Generated
+1
-1
@@ -4,4 +4,4 @@ version = 4
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "envkit"
|
name = "envkit"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
|
|||||||
+2
-1
@@ -1,9 +1,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "envkit"
|
name = "envkit"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
authors = ["Darwin Cereska <discorddurr@gmail.com>"]
|
authors = ["Darwin Cereska <discorddurr@gmail.com>"]
|
||||||
description = "A dead-simple env loader"
|
description = "A dead-simple env loader"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://github.com/darwincereska/envkit"
|
repository = "https://github.com/darwincereska/envkit"
|
||||||
|
categories = ["environment", "configuration", "loader"]
|
||||||
@@ -1,10 +1,15 @@
|
|||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
/// Errors that can occur when parsing environment variables.
|
||||||
pub enum EnvError {
|
pub enum EnvError {
|
||||||
|
/// An environment variable was found, but its value was invalid.
|
||||||
Invalid { key: String, value: String, message: String },
|
Invalid { key: String, value: String, message: String },
|
||||||
|
|
||||||
|
/// An environment variable was expected, but it was not found.
|
||||||
MissingVar(String),
|
MissingVar(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnvError {
|
impl EnvError {
|
||||||
|
/// Creates a new `EnvError::Invalid` with the given key, value, and message.
|
||||||
pub fn invalid<K, V, M>(key: K, value: V, message: M) -> Self
|
pub fn invalid<K, V, M>(key: K, value: V, message: M) -> Self
|
||||||
where
|
where
|
||||||
K: Into<String>,
|
K: Into<String>,
|
||||||
@@ -18,6 +23,7 @@ impl EnvError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new `EnvError::MissingVar` with the given key.
|
||||||
pub fn missing<T>(key: T) -> Self
|
pub fn missing<T>(key: T) -> Self
|
||||||
where T: Into<String> {
|
where T: Into<String> {
|
||||||
Self::MissingVar(key.into())
|
Self::MissingVar(key.into())
|
||||||
|
|||||||
+16
-6
@@ -8,64 +8,74 @@ pub trait FromEnv: Sized {
|
|||||||
fn from_env(value: &str) -> Result<Self, EnvError>;
|
fn from_env(value: &str) -> Result<Self, EnvError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds support for loading booleans from environment variables.
|
||||||
impl FromEnv for bool {
|
impl FromEnv for bool {
|
||||||
fn from_env(value: &str) -> Result<bool, EnvError> {
|
fn from_env(value: &str) -> Result<bool, EnvError> {
|
||||||
match parser::parse_bool(value) {
|
match parser::parse_bool(value) {
|
||||||
Ok(value) => Ok(value),
|
Ok(value) => Ok(value),
|
||||||
Err(e) => Err(e)
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds support for loading numbers from environment variables.
|
||||||
impl<T: Number> FromEnv for T {
|
impl<T: Number> FromEnv for T {
|
||||||
fn from_env(value: &str) -> Result<Self, EnvError> {
|
fn from_env(value: &str) -> Result<Self, EnvError> {
|
||||||
match parser::parse_number(value) {
|
match parser::parse_number(value) {
|
||||||
Ok(value) => Ok(value),
|
Ok(value) => Ok(value),
|
||||||
Err(e) => Err(e)
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds support for loading strings from environment variables.
|
||||||
impl FromEnv for String {
|
impl FromEnv for String {
|
||||||
fn from_env(value: &str) -> Result<String, EnvError> {
|
fn from_env(value: &str) -> Result<String, EnvError> {
|
||||||
Ok(value.to_string())
|
Ok(value.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A loader for environment variables.
|
||||||
pub struct EnvLoader;
|
pub struct EnvLoader;
|
||||||
|
|
||||||
impl EnvLoader {
|
impl EnvLoader {
|
||||||
|
/// Creates a new `EnvLoader` with the given prefix.
|
||||||
pub fn with_prefix<P: Into<String>>(&self, prefix: P) -> PrefixedEnvLoader {
|
pub fn with_prefix<P: Into<String>>(&self, prefix: P) -> PrefixedEnvLoader {
|
||||||
PrefixedEnvLoader {
|
PrefixedEnvLoader {
|
||||||
prefix: prefix.into(),
|
prefix: prefix.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the value of the environment variable with the given key.
|
||||||
pub fn get<T: FromEnv>(&self, key: &str) -> Result<T, EnvError> {
|
pub fn get<T: FromEnv>(&self, key: &str) -> Result<T, EnvError> {
|
||||||
let raw = std::env::var(key).map_err(|_| EnvError::missing(key))?;
|
let raw = std::env::var(key).map_err(|_| EnvError::missing(key))?;
|
||||||
FromEnv::from_env(&raw)
|
FromEnv::from_env(&raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the value of the environment variable with the given key, or returns the default value if the variable is not set.
|
||||||
pub fn get_or<T: FromEnv>(&self, key: &str, default: T) -> T {
|
pub fn get_or<T: FromEnv>(&self, key: &str, default: T) -> T {
|
||||||
match self.get(key) {
|
match self.get(key) {
|
||||||
Ok(value) => value,
|
Ok(value) => value,
|
||||||
Err(_) => default
|
Err(_) => default,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the value of the environment variable with the given key, or returns `None` if the variable is not set.
|
||||||
pub fn get_opt<T: FromEnv>(&self, key: &str) -> Option<T> {
|
pub fn get_opt<T: FromEnv>(&self, key: &str) -> Option<T> {
|
||||||
match self.get(key) {
|
match self.get(key) {
|
||||||
Ok(value) => Some(value),
|
Ok(value) => Some(value),
|
||||||
Err(_) => None
|
Err(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A loader for environment variables with a prefix.
|
||||||
pub struct PrefixedEnvLoader {
|
pub struct PrefixedEnvLoader {
|
||||||
prefix: String,
|
prefix: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrefixedEnvLoader {
|
impl PrefixedEnvLoader {
|
||||||
|
/// Returns the key with the prefix prepended.
|
||||||
fn key(&self, key: &str) -> String {
|
fn key(&self, key: &str) -> String {
|
||||||
format!("{}{}", self.prefix, key)
|
format!("{}{}", self.prefix, key)
|
||||||
}
|
}
|
||||||
@@ -77,14 +87,14 @@ impl PrefixedEnvLoader {
|
|||||||
pub fn get_or<T: FromEnv>(&self, key: &str, default: T) -> T {
|
pub fn get_or<T: FromEnv>(&self, key: &str, default: T) -> T {
|
||||||
match self.get(key) {
|
match self.get(key) {
|
||||||
Ok(value) => value,
|
Ok(value) => value,
|
||||||
Err(_) => default
|
Err(_) => default,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_opt<T: FromEnv>(&self, key: &str) -> Option<T> {
|
pub fn get_opt<T: FromEnv>(&self, key: &str) -> Option<T> {
|
||||||
match self.get(key) {
|
match self.get(key) {
|
||||||
Ok(value) => Some(value),
|
Ok(value) => Some(value),
|
||||||
Err(_) => None
|
Err(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use std::any::type_name;
|
|||||||
use crate::error::EnvError;
|
use crate::error::EnvError;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
/// A trait for types that can be parsed from a string as a number.
|
||||||
pub trait Number: FromStr<Err: Display> {}
|
pub trait Number: FromStr<Err: Display> {}
|
||||||
|
|
||||||
impl Number for i8 {}
|
impl Number for i8 {}
|
||||||
@@ -20,11 +21,14 @@ impl Number for usize {}
|
|||||||
impl Number for f32 {}
|
impl Number for f32 {}
|
||||||
impl Number for f64 {}
|
impl Number for f64 {}
|
||||||
|
|
||||||
|
/// Parses a string as a boolean value.
|
||||||
pub fn parse_bool(value: &str) -> Result<bool, EnvError> {
|
pub fn parse_bool(value: &str) -> Result<bool, EnvError> {
|
||||||
if value.to_lowercase() == "t" { return Ok(true) }
|
if value.to_lowercase() == "t" { return Ok(true) }
|
||||||
if value.to_lowercase() == "f" { return Ok(false) }
|
if value.to_lowercase() == "f" { return Ok(false) }
|
||||||
if value == "1" { return Ok(true) }
|
if value == "1" { return Ok(true) }
|
||||||
if value == "0" { return Ok(false) }
|
if value == "0" { return Ok(false) }
|
||||||
|
if value == "yes" { return Ok(true) }
|
||||||
|
if value == "no" { return Ok(false) }
|
||||||
|
|
||||||
match value.parse::<bool>() {
|
match value.parse::<bool>() {
|
||||||
Ok(value) => Ok(value),
|
Ok(value) => Ok(value),
|
||||||
@@ -32,6 +36,7 @@ pub fn parse_bool(value: &str) -> Result<bool, EnvError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses a string as a number of the specified type.
|
||||||
pub fn parse_number<T: Number>(value: &str) -> Result<T, EnvError> {
|
pub fn parse_number<T: Number>(value: &str) -> Result<T, EnvError> {
|
||||||
match value.parse::<T>() {
|
match value.parse::<T>() {
|
||||||
Ok(value) => Ok(value),
|
Ok(value) => Ok(value),
|
||||||
|
|||||||
@@ -3,11 +3,13 @@ mod test_errors {
|
|||||||
use envkit::error::EnvError;
|
use envkit::error::EnvError;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
/// Tests for the `missing` function.
|
||||||
fn test_missing_var() {
|
fn test_missing_var() {
|
||||||
assert_eq!(EnvError::missing("missing test"), EnvError::MissingVar("missing test".to_string()));
|
assert_eq!(EnvError::missing("missing test"), EnvError::MissingVar("missing test".to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
/// Tests for the `invalid` function.
|
||||||
fn test_invalid() {
|
fn test_invalid() {
|
||||||
assert_eq!(EnvError::invalid("key", "value", "message"), EnvError::Invalid {
|
assert_eq!(EnvError::invalid("key", "value", "message"), EnvError::Invalid {
|
||||||
key: "key".to_string(),
|
key: "key".to_string(),
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod test_main {
|
||||||
|
use envkit::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
/// Tests that `get` successfully retrieves an existing environment variable.
|
||||||
|
fn test_get() {
|
||||||
|
let env = EnvLoader;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
std::env::set_var("TEST_VAR", "test_value");
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(env.get::<String>("TEST_VAR"), Ok("test_value".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
/// Tests that `get_or` returns the default value when the environment variable is missing.
|
||||||
|
fn test_get_or() {
|
||||||
|
let env = EnvLoader;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
std::env::remove_var("MISSING_VAR");
|
||||||
|
std::env::set_var("TEST_VAR", "test_value");
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(env.get_or::<String>("MISSING_VAR", "default".to_string()), "default".to_string());
|
||||||
|
assert_eq!(env.get_or::<String>("TEST_VAR", "default".to_string()), "test_value".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
/// Tests that `get_opt` returns `Some` when the environment variable exists.
|
||||||
|
fn test_get_opt() {
|
||||||
|
let env = EnvLoader;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
std::env::set_var("OPTIONAL_VAR", "optional_value");
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(env.get_opt::<String>("OPTIONAL_VAR"), Some("optional_value".to_string()));
|
||||||
|
assert_eq!(env.get_opt::<bool>("DEV"), None);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ mod test_parser {
|
|||||||
use envkit::parser::parse_number;
|
use envkit::parser::parse_number;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
/// Tests for the `parse_bool` function.
|
||||||
fn test_parse_bool() {
|
fn test_parse_bool() {
|
||||||
assert_eq!(parse_bool("true"), Ok(true));
|
assert_eq!(parse_bool("true"), Ok(true));
|
||||||
assert_eq!(parse_bool("false"), Ok(false));
|
assert_eq!(parse_bool("false"), Ok(false));
|
||||||
@@ -11,9 +12,12 @@ mod test_parser {
|
|||||||
assert_eq!(parse_bool("0"), Ok(false));
|
assert_eq!(parse_bool("0"), Ok(false));
|
||||||
assert_eq!(parse_bool("t"), Ok(true));
|
assert_eq!(parse_bool("t"), Ok(true));
|
||||||
assert_eq!(parse_bool("f"), Ok(false));
|
assert_eq!(parse_bool("f"), Ok(false));
|
||||||
|
assert_eq!(parse_bool("yes"), Ok(true));
|
||||||
|
assert_eq!(parse_bool("no"), Ok(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
/// Tests for the `parse_number` function.
|
||||||
fn test_parse_number() {
|
fn test_parse_number() {
|
||||||
assert_eq!(parse_number::<i8>("42"), Ok(42_i8));
|
assert_eq!(parse_number::<i8>("42"), Ok(42_i8));
|
||||||
assert_eq!(parse_number::<i16>("42"), Ok(42_i16));
|
assert_eq!(parse_number::<i16>("42"), Ok(42_i16));
|
||||||
|
|||||||
Reference in New Issue
Block a user