Skip to content

Commit

Permalink
Merge #21
Browse files Browse the repository at this point in the history
21: Chore/prepare for release r=TheNeikos a=TheNeikos



Co-authored-by: Marcel Müller <[email protected]>
  • Loading branch information
bors[bot] and TheNeikos authored Mar 27, 2023
2 parents 347416d + 5fa0898 commit 8815e8f
Show file tree
Hide file tree
Showing 9 changed files with 42 additions and 219 deletions.
4 changes: 0 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@
The 0.3.0 version makes the following API changes:

- `Config` is the new entrypoint to `envious`, with all interactions happening via method calls.
- Existing functions are now wrappers around `Config` and will persist until `0.4.0` at which point they will be removed. This is indicated by deprecation warnings on the functions.

The 0.2.0 version adds the following features:

- Case sensitivity is now configurable, see `Config::case_sensitive`
- NB: The default is case insensitive, which is a change from the original behaviour.
- The separator is now configurable, using the same default as `0.2.0`, see `Config::with_separator`
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ struct Config {
staircase_orientation: StaircaseOrientation,
}
let config: Config = envious::Config::new().from_env().expect("Could not deserialize from env");
let config: Config = envious::Config::default().build_from_env().expect("Could not deserialize from env");
```

With the following environment variables:
Expand All @@ -52,7 +52,7 @@ To use `envious` simply add it to your `Cargo.toml` with:
cargo add envious
```

and deserialize from your environment with [`Config::new`] and then [`Config::from_env`]!
and deserialize from your environment with [`Config::default`] and then [`Config::build_from_env`]!

⚠️ **Current Shortcomings**

Expand Down
34 changes: 22 additions & 12 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{error, error::EnvDeserializationError, Parser, Value};
/// Used to configure the behaviour of the environment variable deserialization.
///
/// For information on default behaviours see [`Self::new`].
/// For details on usage see [`Self::from_env`] and [`Self::from_iter`].
/// For details on usage see [`Self::build_from_env`] and [`Self::build_from_iter`].
#[derive(Debug, Clone)]
#[must_use]
pub struct Config<'a> {
Expand All @@ -17,13 +17,14 @@ pub struct Config<'a> {
}

impl Default for Config<'static> {
/// See [`Config::new`] for details on the default
fn default() -> Self {
Self::new()
}
}

impl<'a> Config<'a> {
/// Create a new instance of [`Config`] with basic values. i.e.
/// Create a new instance of [`Config`] with the following configuration:
/// - No prefix
/// - Case insensitive
/// - A separator of "__" (double underscore)
Expand All @@ -39,10 +40,19 @@ impl<'a> Config<'a> {
///
/// Defaults to `__` (double underscore)
///
/// E.g. with an environment variable named `env_variable`, and the default separator,
/// a field with the name `env_variable` is looked for, whereas with a custom separator of
/// `_`, a field with the name `env` is looked for, where that field is a struct which in turn has a field
/// `variable`.
/// ## Example
///
/// Per default (i.e. `__` seperator) an env variable named `foo_bar` would be interpreted as
/// the field with the same name `foo_bar`.
///
/// If you change the seperator to `_`, then in that case it would be interpreted as the
/// following structure:
///
/// ```text
/// foo: {
/// bar: <value>
/// }
/// ```
pub fn with_separator<S>(&mut self, separator: S) -> &mut Self
where
S: Into<Cow<'a, str>>,
Expand All @@ -55,7 +65,7 @@ impl<'a> Config<'a> {
///
/// Environments variables without the prefix are discarded.
///
/// Defaults to no prefix being set. The default can be returned to via [`Self::without_prefix`].
/// Defaults to no prefix being set. You can switch back to the default via [`Self::without_prefix`].
pub fn with_prefix<S>(&mut self, prefix: S) -> &mut Self
where
S: Into<Cow<'a, str>>,
Expand Down Expand Up @@ -116,12 +126,12 @@ impl<'a> Config<'a> {
///# std::env::set_var(key, val);
///# }
///#
/// let config: Config = envious::Config::new().from_env().unwrap();
/// let config: Config = envious::Config::default().from_env().unwrap();
///# }
/// ```
pub fn from_env<T: DeserializeOwned>(&self) -> Result<T, error::EnvDeserializationError> {
pub fn build_from_env<T: DeserializeOwned>(&self) -> Result<T, error::EnvDeserializationError> {
let env_values = std::env::vars();
self.from_iter(env_values)
self.build_from_iter(env_values)
}

/// Parse a given `T: Deserialize` from anything that can be turned into an iterator of key value tuples.
Expand Down Expand Up @@ -154,9 +164,9 @@ impl<'a> Config<'a> {
/// ("staircase_orientation", "Left"),
/// ];
///
/// let config: Config = envious::Config::new().from_iter(vars).unwrap();
/// let config: Config = envious::Config::default().build_from_iter(vars).unwrap();
/// ```
pub fn from_iter<T, K, V, I>(&self, iter: I) -> Result<T, error::EnvDeserializationError>
pub fn build_from_iter<T, K, V, I>(&self, iter: I) -> Result<T, error::EnvDeserializationError>
where
T: DeserializeOwned,
K: Into<String>,
Expand Down
195 changes: 5 additions & 190 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#![doc = include_str!("../README.md")]
#![deny(missing_docs)]

use serde::de::DeserializeOwned;
use value::Value;

mod config;
Expand All @@ -11,190 +10,6 @@ mod value;
pub use config::Config;
use value::Parser;

/// Whether to use and strip a prefix, and if so which one
#[derive(Debug, Copy, Clone)]
#[deprecated(
since = "0.3.0",
note = "please use `Config` and its `with_prefix` method instead"
)]
pub enum Prefix<'a> {
/// No prefix, nothing will be stripped
None,
/// The given prefix will be stripped
///
/// ## Example
///
/// ```rust,no_run
/// use serde::{Deserialize, Serialize};
///
/// #[derive(Serialize, Deserialize, Debug)]
/// enum Material {
/// Wood,
/// Plastic,
/// }
///
/// #[derive(Serialize, Deserialize, Debug)]
/// struct Door {
/// material: Material,
/// }
///
/// #[derive(Serialize, Deserialize, Debug)]
/// struct UpstairsConfig {
/// doors: Vec<Door>,
/// }
///
/// #[derive(Serialize, Deserialize, Debug)]
/// struct Config {
/// upstairs: UpstairsConfig,
/// }
///
///# #[test]
///# fn parse_from_env() {
///# let vars = [
///# ("ENVIOUS_upstairs__doors__0__material", "Wood"),
///# ("ENVIOUS_upstairs__doors__1__material", "Plastic"),
///# ("ENORMUS_upstairs__doors__2__material", "Plastic"),
///# ];
///#
///# for (key, val) in vars {
///# std::env::set_var(key, val);
///# }
///
/// let config: Config = envious::from_env(envious::Prefix::Some("ENVIOUS_")).expect("Could not read from environment");
///# }
///
/// ```
Some(&'a str),
}

#[allow(deprecated)]
impl<'a> From<Option<&'a str>> for Prefix<'a> {
/// Allows to easily convert from a `Option` to a `Prefix`
///
/// For easily readability it should primarily used as `Prefix::from`
///
/// ```rust,no_run
/// # use serde::{Deserialize, Serialize};
/// # #[derive(Serialize, Deserialize, Debug)]
/// # struct Config {
/// # foobar: f32
/// # }
/// let maybe_prefix = Some("ENVIOUS_");
/// let value: Config = envious::from_env(envious::Prefix::from(maybe_prefix)).expect("Could not read from environment");
/// ```
fn from(value: Option<&'a str>) -> Self {
value.map_or(Prefix::None, Prefix::Some)
}
}

/// Parse a given `T: Deserialize` from environment variables.
///
/// You can control whether a given prefix should be stripped or not with [`Prefix`].
///
/// ## Example
///
/// ```rust
///
///# use serde::{Deserialize, Serialize};
///#
/// #[derive(Serialize, Deserialize, Debug)]
/// enum StaircaseOrientation {
/// Left,
/// Right,
/// }
///
/// #[derive(Serialize, Deserialize, Debug)]
/// struct Config {
/// target_temp: f32,
/// automate_doors: bool,
///
/// staircase_orientation: StaircaseOrientation,
/// }
///#
///# #[test]
///# fn parse_from_env() {
///# let vars = [
///# ("target_temp", "25.0"),
///# ("automate_doors", "true"),
///# ("staircase_orientation", "Left"),
///# ];
///#
///# for (key, val) in vars {
///# std::env::set_var(key, val);
///# }
///#
/// let config: Config = envious::from_env(envious::Prefix::None).expect("Could not read from environment");
///# }
/// ```
#[deprecated(
since = "0.3.0",
note = "please use `Config` and its `from_env` method instead"
)]
#[allow(deprecated)]
pub fn from_env<T: DeserializeOwned>(
prefix: Prefix<'_>,
) -> Result<T, error::EnvDeserializationError> {
let mut config = Config::new();

if let Prefix::Some(prefix) = prefix {
config.with_prefix(prefix);
}

config.from_env()
}

/// Parse a given `T: Deserialize` from anything that can be turned into an iterator.
///
/// You can control whether a given prefix should be stripped or not with [`Prefix`].
///
/// This function is useful for static deployments or for testing
///
/// ## Example
///
/// ```rust
///
///# use serde::{Deserialize, Serialize};
///#
/// #[derive(Serialize, Deserialize, Debug)]
/// enum StaircaseOrientation {
/// Left,
/// Right,
/// }
///
/// #[derive(Serialize, Deserialize, Debug)]
/// struct Config {
/// target_temp: f32,
/// automate_doors: bool,
///
/// staircase_orientation: StaircaseOrientation,
/// }
///
/// let vars = [
/// (String::from("target_temp"), String::from("25.0")),
/// (String::from("automate_doors"), String::from("true")),
/// (String::from("staircase_orientation"), String::from("Left")),
/// ];
///
/// let config: Config = envious::from_iter(vars, envious::Prefix::None).expect("Could not read from environment");
/// ```
#[deprecated(
since = "0.3.0",
note = "please use `Config` and its `from_iter` method instead"
)]
#[allow(deprecated)]
pub fn from_iter<T: DeserializeOwned, I: IntoIterator<Item = (String, String)>>(
iter: I,
prefix: Prefix<'_>,
) -> Result<T, error::EnvDeserializationError> {
let mut config = Config::new();

if let Prefix::Some(prefix) = prefix {
config.with_prefix(prefix);
}

config.from_iter(iter)
}

#[cfg(test)]
mod test {
use std::borrow::Cow;
Expand All @@ -213,7 +28,7 @@ mod test {
let expected = Simple { allowed: true };

let actual: Simple = Config::new()
.from_iter([(String::from("allowed"), "true")].into_iter())
.build_from_iter([(String::from("allowed"), "true")].into_iter())
.unwrap();

assert_eq!(actual, expected);
Expand Down Expand Up @@ -247,7 +62,7 @@ mod test {
};

let actual: Nested = Config::new()
.from_iter(
.build_from_iter(
[
("temp", "15"),
("inner__smoothness", "32.0"),
Expand All @@ -273,7 +88,7 @@ mod test {
};

let actual: Simple = Config::new()
.from_iter([("ALLOWED-SIMPLY", String::from("true"))].into_iter())
.build_from_iter([("ALLOWED-SIMPLY", String::from("true"))].into_iter())
.unwrap();

assert_eq!(actual, expected);
Expand All @@ -295,7 +110,7 @@ mod test {
let expected = SimpleEnum { simple: Simple::No };

let actual: SimpleEnum = Config::new()
.from_iter([("simple", Cow::Borrowed("No"))].into_iter())
.build_from_iter([("simple", Cow::Borrowed("No"))].into_iter())
.unwrap();

assert_eq!(actual, expected);
Expand All @@ -322,7 +137,7 @@ mod test {
};

let actual: ComplexEnum = Config::new()
.from_iter(
.build_from_iter(
[
("complex__Access__password", "hunter2"),
("complex__Access__foo", "42.0"),
Expand Down
Loading

0 comments on commit 8815e8f

Please sign in to comment.