Initial commit
This commit is contained in:
commit
c460f11dce
7 changed files with 495 additions and 0 deletions
4
.env
Normal file
4
.env
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
DEBUG=1
|
||||||
|
TESTING=0
|
||||||
|
SECRET_KEY='hello:)'
|
||||||
|
DATABASE_URL='postgres:/'
|
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
/target
|
||||||
|
Cargo.lock
|
||||||
|
|
||||||
|
src/main.rs
|
||||||
|
.env*
|
17
Cargo.toml
Normal file
17
Cargo.toml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
[package]
|
||||||
|
name = "itconfig"
|
||||||
|
version = "0.1.1"
|
||||||
|
authors = ["Dmitriy Pleshevskiy <dmitriy@ideascup.me>"]
|
||||||
|
description = "Easy build a configs from environment variables and use it in globally."
|
||||||
|
categories = ["config", "web-programming"]
|
||||||
|
keywords = ["config", "env", "macro", "configuration", "environment"]
|
||||||
|
edition = "2018"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/icetemple/itconfig-rs"
|
||||||
|
homepage = "https://github.com/icetemple/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
|
||||||
|
|
||||||
|
[dependencies]
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 IceTemple
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
27
README.md
Normal file
27
README.md
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# itconfig
|
||||||
|
|
||||||
|
Simple configuration with macro for rust application.
|
||||||
|
|
||||||
|
We recommend you start with the [documentation].
|
||||||
|
|
||||||
|
|
||||||
|
## Example usage
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[macro_use] extern crate itconfig;
|
||||||
|
use dotenv::dotenv;
|
||||||
|
|
||||||
|
config! {
|
||||||
|
DATABASE_URL: bool,
|
||||||
|
HOST: String => "127.0.0.1",
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main () {
|
||||||
|
dotenv().ok();
|
||||||
|
cfg::init();
|
||||||
|
assert_eq(cfg::HOST(), String::from("127.0.0.1");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
[documentation]: https://docs.rs/itconfig
|
308
src/lib.rs
Normal file
308
src/lib.rs
Normal file
|
@ -0,0 +1,308 @@
|
||||||
|
//! # itconfig
|
||||||
|
//!
|
||||||
|
//! Simple configuration with macro for rust application.
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//! ## Example usage
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! #[macro_use] extern crate itconfig;
|
||||||
|
//! use dotenv::dotenv;
|
||||||
|
//!
|
||||||
|
//! config! {
|
||||||
|
//! DATABASE_URL: bool,
|
||||||
|
//! HOST: String => "127.0.0.1",
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! fn main () {
|
||||||
|
//! dotenv().ok();
|
||||||
|
//! cfg::init();
|
||||||
|
//! assert_eq(cfg::HOST(), String::from("127.0.0.1");
|
||||||
|
//! }
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! __impl_from_for_numbers {
|
||||||
|
(
|
||||||
|
$($ty:ty),+
|
||||||
|
) => {
|
||||||
|
$(
|
||||||
|
impl From<EnvValue> for $ty {
|
||||||
|
fn from(env: EnvValue) -> Self {
|
||||||
|
env.0.parse::<Self>().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub struct EnvValue(String);
|
||||||
|
|
||||||
|
impl EnvValue {
|
||||||
|
pub fn new(string: String) -> Self {
|
||||||
|
Self(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__impl_from_for_numbers![
|
||||||
|
i8, i16, i32, i64, i128, isize,
|
||||||
|
u8, u16, u32, u64, u128, usize,
|
||||||
|
f32, f64
|
||||||
|
];
|
||||||
|
|
||||||
|
impl From<EnvValue> for bool {
|
||||||
|
fn from(env: EnvValue) -> Self {
|
||||||
|
match env.0.to_lowercase().as_str() {
|
||||||
|
"true" | "1" | "t" | "on" => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for EnvValue {
|
||||||
|
fn from(val: String) -> Self {
|
||||||
|
Self(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<EnvValue> for String {
|
||||||
|
fn from(env: EnvValue) -> Self {
|
||||||
|
env.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Creates new public 'cfg' mod with function fo get each environment variable of mapping.
|
||||||
|
///
|
||||||
|
/// All variables are required and program will panic if some variables haven't value, but you
|
||||||
|
/// can add default value for specific variable.
|
||||||
|
///
|
||||||
|
/// Example usage
|
||||||
|
/// -------------
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use] extern crate itconfig;
|
||||||
|
/// config! {
|
||||||
|
/// DATABASE_URL: bool,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// # fn main () {
|
||||||
|
/// # use std::env;
|
||||||
|
/// # env::set_var("DATABASE_URL", "sqlite://");
|
||||||
|
/// #
|
||||||
|
/// # cfg::init();
|
||||||
|
/// # assert_eq(cfg::DATABASE_URL(), true);
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Config with default value
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[macro_use] extern crate itconfig;
|
||||||
|
/// config! {
|
||||||
|
/// DATABASE_URL: bool,
|
||||||
|
/// HOST: String => "127.0.0.1",
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// # fn main () {
|
||||||
|
/// # cfg::init();
|
||||||
|
/// # assert_eq(cfg::HOST(), String::from("127.0.0.1");
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// This module will also contain helper method:
|
||||||
|
///
|
||||||
|
/// `init`
|
||||||
|
/// ------
|
||||||
|
///
|
||||||
|
/// If you miss some required variables your application will panic at startup.
|
||||||
|
/// Run this at the main function for check all required variables without default value.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// #[macro_use] extern crate itconfig;
|
||||||
|
///
|
||||||
|
/// config! {
|
||||||
|
/// DATABASE_URL: bool,
|
||||||
|
/// HOST: String => "127.0.0.1",
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main () {
|
||||||
|
/// cfg::init();
|
||||||
|
/// assert_eq(cfg::HOST(), String::from("127.0.0.1");
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Also dotenv module is supported
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// #[macro_use] extern crate itconfig;
|
||||||
|
/// use dotenv::dotenv;
|
||||||
|
///
|
||||||
|
/// config! {
|
||||||
|
/// DATABASE_URL: bool,
|
||||||
|
/// HOST: String => "127.0.0.1",
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main () {
|
||||||
|
/// dotenv().ok();
|
||||||
|
/// cfg::init();
|
||||||
|
/// assert_eq(cfg::HOST(), String::from("127.0.0.1");
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! config {
|
||||||
|
($($tokens:tt)*) => {
|
||||||
|
__config_parse_variables!(
|
||||||
|
tokens = [$($tokens)*],
|
||||||
|
variables = [],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! __invalid_config_syntax {
|
||||||
|
() => {
|
||||||
|
compile_error!(
|
||||||
|
"Invalid `config!` syntax. Please see the `config!` macro docs for more info."
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! __config_parse_variables {
|
||||||
|
// Find general config of variable
|
||||||
|
(
|
||||||
|
tokens = [
|
||||||
|
$name:ident : $ty:ty => $default:expr,
|
||||||
|
$($rest:tt)*
|
||||||
|
],
|
||||||
|
$($args:tt)*
|
||||||
|
) => {
|
||||||
|
__config_parse_variables!(
|
||||||
|
current_variable = {
|
||||||
|
name = $name,
|
||||||
|
ty = $ty,
|
||||||
|
env_name = stringify!($name),
|
||||||
|
default = $default,
|
||||||
|
},
|
||||||
|
tokens = [$($rest)*],
|
||||||
|
$($args)*
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
tokens = [
|
||||||
|
$name:ident : $ty:ty,
|
||||||
|
$($rest:tt)*
|
||||||
|
],
|
||||||
|
$($args:tt)*
|
||||||
|
) => {
|
||||||
|
__config_parse_variables!(
|
||||||
|
current_variable = {
|
||||||
|
name = $name,
|
||||||
|
ty = $ty,
|
||||||
|
env_name = stringify!($name),
|
||||||
|
},
|
||||||
|
tokens = [$($rest)*],
|
||||||
|
$($args)*
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Done parsing variable
|
||||||
|
(
|
||||||
|
current_variable = {
|
||||||
|
$($current_variable:tt)*
|
||||||
|
},
|
||||||
|
tokens = $tokens:tt,
|
||||||
|
variables = [$($variables:tt,)*],
|
||||||
|
$($args:tt)*
|
||||||
|
) => {
|
||||||
|
__config_parse_variables!(
|
||||||
|
tokens = $tokens,
|
||||||
|
variables = [$($variables,)* { $($current_variable)* },],
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Done parsing all variables
|
||||||
|
(
|
||||||
|
tokens = [],
|
||||||
|
$($args:tt)*
|
||||||
|
) => {
|
||||||
|
__config_impl!($($args)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Invalid syntax
|
||||||
|
($($tokens:tt)*) => {
|
||||||
|
__invalid_config_syntax!();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! __config_impl {
|
||||||
|
(
|
||||||
|
variables = [$({
|
||||||
|
name = $name:ident,
|
||||||
|
$($variable:tt)*
|
||||||
|
},)+],
|
||||||
|
) => {
|
||||||
|
pub mod cfg {
|
||||||
|
#![allow(non_snake_case)]
|
||||||
|
use std::env;
|
||||||
|
use $crate::EnvValue;
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
$($name();)+
|
||||||
|
}
|
||||||
|
|
||||||
|
$(__config_variable! {
|
||||||
|
name = $name,
|
||||||
|
$($variable)*
|
||||||
|
})+
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! __config_variable {
|
||||||
|
// Add method with default value
|
||||||
|
(
|
||||||
|
name = $name:ident,
|
||||||
|
ty = $ty:ty,
|
||||||
|
env_name = $env_name:expr,
|
||||||
|
default = $default:expr,
|
||||||
|
) => {
|
||||||
|
pub fn $name() -> $ty {
|
||||||
|
env::var($env_name)
|
||||||
|
.map(|val| EnvValue::from(val).into())
|
||||||
|
.unwrap_or_else(|_| $default)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add method without default value
|
||||||
|
(
|
||||||
|
name = $name:ident,
|
||||||
|
ty = $ty:ty,
|
||||||
|
env_name = $env_name:expr,
|
||||||
|
) => {
|
||||||
|
pub fn $name() -> $ty {
|
||||||
|
env::var($env_name)
|
||||||
|
.map(|val| EnvValue::from(val).into())
|
||||||
|
.unwrap_or_else(|_| {
|
||||||
|
panic!(format!(r#"Cannot read "{}" environment variable"#, $env_name))
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
111
tests/config_macro.rs
Normal file
111
tests/config_macro.rs
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
use std::env;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate it_config;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn one_variable() {
|
||||||
|
config! {
|
||||||
|
DEBUG: bool => true,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(cfg::DEBUG(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn few_variables() {
|
||||||
|
config! {
|
||||||
|
FOO: bool => true,
|
||||||
|
BAR: bool => false,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(cfg::FOO(), true);
|
||||||
|
assert_eq!(cfg::BAR(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn different_types() {
|
||||||
|
config! {
|
||||||
|
NUMBER: i32 => 30,
|
||||||
|
BOOL: bool => true,
|
||||||
|
STRING: String => "string".to_string(),
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(cfg::NUMBER(), 30);
|
||||||
|
assert_eq!(cfg::BOOL(), true);
|
||||||
|
assert_eq!(cfg::STRING(), "string");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_bool_type_from_env() {
|
||||||
|
env::set_var("T_BOOL", "t");
|
||||||
|
env::set_var("TRUE_BOOL", "true");
|
||||||
|
env::set_var("NUM_BOOL", "1");
|
||||||
|
env::set_var("ON_BOOL", "on");
|
||||||
|
env::set_var("CAMEL_CASE", "True");
|
||||||
|
env::set_var("FALSE_BOOL", "false");
|
||||||
|
|
||||||
|
config! {
|
||||||
|
T_BOOL: bool,
|
||||||
|
TRUE_BOOL: bool,
|
||||||
|
NUM_BOOL: bool,
|
||||||
|
ON_BOOL: bool,
|
||||||
|
CAMEL_CASE: bool,
|
||||||
|
FALSE_BOOL: bool,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(cfg::T_BOOL(), true);
|
||||||
|
assert_eq!(cfg::TRUE_BOOL(), true);
|
||||||
|
assert_eq!(cfg::NUM_BOOL(), true);
|
||||||
|
assert_eq!(cfg::ON_BOOL(), true);
|
||||||
|
assert_eq!(cfg::CAMEL_CASE(), true);
|
||||||
|
assert_eq!(cfg::FALSE_BOOL(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_number_value_from_env() {
|
||||||
|
env::set_var("I8", "10");
|
||||||
|
env::set_var("I16", "10");
|
||||||
|
env::set_var("I32", "10");
|
||||||
|
env::set_var("I64", "10");
|
||||||
|
env::set_var("I128", "10");
|
||||||
|
env::set_var("ISIZE","10");
|
||||||
|
env::set_var("U8", "10");
|
||||||
|
env::set_var("U16", "10");
|
||||||
|
env::set_var("U32", "10");
|
||||||
|
env::set_var("U64", "10");
|
||||||
|
env::set_var("U128", "10");
|
||||||
|
env::set_var("USIZE","10");
|
||||||
|
env::set_var("F32", "10");
|
||||||
|
env::set_var("F64","10");
|
||||||
|
|
||||||
|
config! {
|
||||||
|
I8: i8,
|
||||||
|
I16: i16,
|
||||||
|
I32: i32,
|
||||||
|
I64: i64,
|
||||||
|
I128: i128,
|
||||||
|
ISIZE: isize,
|
||||||
|
U8: u8,
|
||||||
|
U16: u16,
|
||||||
|
U32: u32,
|
||||||
|
U64: u64,
|
||||||
|
U128: u128,
|
||||||
|
USIZE: usize,
|
||||||
|
F32: f32,
|
||||||
|
F64: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(cfg::I8(), 10);
|
||||||
|
assert_eq!(cfg::I16(), 10);
|
||||||
|
assert_eq!(cfg::I32(), 10);
|
||||||
|
assert_eq!(cfg::I64(), 10);
|
||||||
|
assert_eq!(cfg::ISIZE(), 10);
|
||||||
|
assert_eq!(cfg::U8(), 10);
|
||||||
|
assert_eq!(cfg::U16(), 10);
|
||||||
|
assert_eq!(cfg::U32(), 10);
|
||||||
|
assert_eq!(cfg::U64(), 10);
|
||||||
|
assert_eq!(cfg::USIZE(), 10);
|
||||||
|
assert_eq!(cfg::F32(), 10.0);
|
||||||
|
assert_eq!(cfg::F64(), 10.0);
|
||||||
|
}
|
Reference in a new issue