Skip to content

Commit

Permalink
Merge pull request #13 from workanator/master
Browse files Browse the repository at this point in the history
Auto type env var injector
  • Loading branch information
filipegoncalves committed Nov 18, 2015
2 parents 426b1d9 + 8852ac2 commit 0d0de33
Show file tree
Hide file tree
Showing 2 changed files with 193 additions and 31 deletions.
28 changes: 23 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,21 @@
//!
//! * `$"SOME_ENV_VAR_NAME"::str` to inject the environment variables `SOME_ENV_VAR_NAME` as the string value.
//! No additiocal changes are made ot the value.
//! * `$"SOME_ENV_VAR_NAME"::bool` to inject the environment variables `SOME_ENV_VAR_NAME` as the boolean value.
//! * `$"SOME_ENV_VAR_NAME"::bool` to inject the environment variable `SOME_ENV_VAR_NAME` as the boolean value.
//! The value `true` or `yes` or `on` or `1` are converted into `true` otherwise into `false`.
//! * `$"SOME_ENV_VAR_NAME"::int` to inject the environment variables `SOME_ENV_VAR_NAME` as the integer value.
//! * `$"SOME_ENV_VAR_NAME"::int` to inject the environment variable `SOME_ENV_VAR_NAME` as the integer value.
//! The successfully parsed value is injected as `i32` or `i64`, depending on the format, otherwise `0i32` is injected.
//! * `$"SOME_ENV_VAR_NAME"::flt` to inject the environment variables `SOME_ENV_VAR_NAME` as the floating value.
//! * `$"SOME_ENV_VAR_NAME"::flt` to inject the environment variable `SOME_ENV_VAR_NAME` as the floating value.
//! The successfully parsed value is injected as `f32` or `f64`, depending on the format, otherwise `0f32` is injected.
//! * `$"SOME_ENV_VAR_NAME"::auto` or `$"SOME_ENV_VAR_NAME"` to inject the environment variable `SOME_ENV_VAR_NAME`
//! and resolve the type automatically. Rules of the type auto-resolution:
//! - If the value is *True* or *Yes* or *On* then the result type is `boolean True`;
//! - If the value is *False* or *No* or *Off* then the result type is `boolean False`;
//! - If the value is floating then the result type is `floating`;
//! - If the value is integer then the result type is `integer`;
//! - Otherwise the result is `string` value.
//!
//!
//! **Example**:
//!**Example**:
//!
//! ```ignore
//! #!/bin/sh
Expand Down Expand Up @@ -154,22 +160,34 @@
//! | integer64_scalar_value
//! | integer32_scalar_value
//! | str_scalar_value
//! | auto_env_scalar_value
//!
//! boolean_scalar_value -> [Tt][Rr][Uu][Ee]
//! | [Yy][Ee][Ss]
//! | [Oo][Nn]
//! | [Ff][Aa][Ll][Ss][Ee]
//! | [Nn][Oo]
//! | [Oo][Ff][Ff]
//! | $"ENV_VAR_NAME"::bool
//!
//! floating64_scalar_value -> [+-]?([0-9]+\.[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)?"L"
//! | $"ENV_VAR_NAME"::flt
//!
//! floating32_scalar_value -> [+-]?([0-9]+\.[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)?
//! | $"ENV_VAR_NAME"::flt
//!
//! integer32_scalar_value -> [+-]?[0-9]+
//! | $"ENV_VAR_NAME"::int
//!
//! integer64_scalar_value -> [+-]?[0-9]+"L"
//! | $"ENV_VAR_NAME"::int
//!
//! str_scalar_value -> __ str_literal __
//! | __ str_literal __ str_scalar_value
//! | $"ENV_VAR_NAME"::str
//!
//! auto_env_scalar_value -> $"ENV_VAR_NAME"::auto
//! | $"ENV_VAR_NAME"
//!
//! str_literal -> "\"" ([^\"\\]|(("\\r"|"\\n"|"\\t"|"\\\""|"\\\\")))* "\""
//!
Expand Down
196 changes: 170 additions & 26 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,8 @@ named!(scalar_value<&[u8], ScalarValue>,
boolean_scalar_value |
flt_scalar_value |
int_scalar_value |
str_scalar_value));
str_scalar_value |
auto_env_scalar_value));

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~ Array parser and auxiliary parsers ~~~
Expand Down Expand Up @@ -667,6 +668,48 @@ named!(flt_env_value<&[u8], ScalarValue>,
}
}));

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~ Auto type environment variable parser ~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
named!(auto_env_scalar_value<&[u8], ScalarValue>,
chain!(
tag!("$") ~
n: string_literal ~
opt!(chain!(
tag!(":") ~
tag!(":") ~
alt!(tag!("A") | tag!("a")) ~
alt!(tag!("U") | tag!("u")) ~
alt!(tag!("T") | tag!("t")) ~
alt!(tag!("O") | tag!("o")),
|| {} )),
|| {
use std::env;
// TODO(filipegoncalves) Handle error case
// NOTE(workanator) I think that is the proper implementation on the parser which
// should not generate any errors here. Contact me if you like
// to discuss that.
if let Ok(value) = env::var(&n) {
if let IResult::Done(_, output) = bool_true_value(value.as_bytes()) {
output
} else if let IResult::Done(_, output) = bool_false_value(value.as_bytes()) {
output
} else if let IResult::Done(_, output) = flt64_scalar_value(value.as_bytes()) {
output
} else if let IResult::Done(_, output) = flt32_scalar_value(value.as_bytes()) {
output
} else if let IResult::Done(_, output) = int64_scalar_value(value.as_bytes()) {
output
} else if let IResult::Done(_, output) = int32_scalar_value(value.as_bytes()) {
output
} else {
ScalarValue::Str(value)
}
} else {
ScalarValue::Str("".to_string())
}
} ));

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~ Parser to ignore useless stuff: comments, new lines, ... ~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -842,7 +885,7 @@ mod test {
use super::{escaped_seq, not_escaped_seq, string_literal, str_scalar_value};
use super::{eol, comment_one_line, comment_block, blanks};
use super::{flt_base_w_digits_bef_dot, flt_base_no_digits_bef_dot, flt_base, flt_exponent};
use super::{flt32_scalar_value, flt64_scalar_value, flt_scalar_value};
use super::{flt32_scalar_value, flt64_scalar_value, flt_scalar_value, auto_env_scalar_value};
use super::{int32_scalar_value, int64_scalar_value, int_scalar_value};
use super::{bool_true_value, bool_false_value, boolean_scalar_value, scalar_value};
use super::{boolean_array_elements, str_array_elements};
Expand Down Expand Up @@ -3537,17 +3580,11 @@ mod test {
}

#[test]
// TODO(filipegoncalves) Refactor this into separate tests.
fn env_scalar_values() {
fn env_bool_scalar_values() {
// Set up environment variables
use std::env;
env::set_var("TEST_BOOL", "Yes");
env::set_var("TEST_INT32", "-42");
env::set_var("TEST_INT64", "+42L");
env::set_var("TEST_FLT32", "3.1415");
env::set_var("TEST_FLT64", "-3.1415L");

// Test boolean
let input = &b"$\"TEST_BOOL\"::bool;\n"[..];
let res = boolean_scalar_value(input);
assert_eq!(res, Done(&b";\n"[..], ScalarValue::Boolean(true)));
Expand All @@ -3556,48 +3593,155 @@ mod test {
let res = boolean_scalar_value(input);
assert_eq!(res, Done(&b";\n"[..], ScalarValue::Boolean(false)));

// Test string
let input = &b"$\"TEST_BOOL\"::str;\n"[..];
let input = &b"$\"TEST_BOOL\"::auto;\n"[..];
let res = auto_env_scalar_value(input);
assert_eq!(res, Done(&b";\n"[..], ScalarValue::Boolean(true)));

env::set_var("TEST_BOOL", "False");
let input = &b"$\"TEST_BOOL\";\n"[..];
let res = auto_env_scalar_value(input);
assert_eq!(res, Done(&b";\n"[..], ScalarValue::Boolean(false)));
}

#[test]
fn env_str_scalar_values() {
// Set up environment variables
use std::env;
env::set_var("TEST_STR", "Env");

let input = &b"$\"TEST_STR\"::str;\n"[..];
let res = str_scalar_value(input);
assert_eq!(res, Done(&b";\n"[..], ScalarValue::Str("Yes".to_string())));
assert_eq!(res, Done(&b";\n"[..], ScalarValue::Str("Env".to_string())));

let input = &b"$\"TEST_BOOL_NOT_FOUND\"::str;\n"[..];
let input = &b"$\"TEST_STR_NOT_FOUND\"::str;\n"[..];
let res = str_scalar_value(input);
assert_eq!(res, Done(&b";\n"[..], ScalarValue::Str("".to_string())));

// Test integer
let input = &b"$\"TEST_STR\"::auto;\n"[..];
let res = auto_env_scalar_value(input);
assert_eq!(res, Done(&b";\n"[..], ScalarValue::Str("Env".to_string())));

let input = &b"$\"TEST_STR\";\n"[..];
let res = auto_env_scalar_value(input);
assert_eq!(res, Done(&b";\n"[..], ScalarValue::Str("Env".to_string())));
}

#[test]
fn env_int32_scalar_values() {
// Set up environment variables
use std::env;
env::set_var("TEST_INT32", "-42");

let input = &b"$\"TEST_INT32\"::int;\n"[..];
let res = int_scalar_value(input);
assert_eq!(res, Done(&b";\n"[..], ScalarValue::Integer32(-42i32)));

let input = &b"$\"TEST_INT32_NOT_FOUND\"::int;\n"[..];
let res = int_scalar_value(input);
assert_eq!(res, Done(&b";\n"[..], ScalarValue::Integer32(0i32)));

let input = &b"$\"TEST_INT32\"::auto;\n"[..];
let res = auto_env_scalar_value(input);
assert_eq!(res, Done(&b";\n"[..], ScalarValue::Integer32(-42i32)));

let input = &b"$\"TEST_INT32\";\n"[..];
let res = auto_env_scalar_value(input);
assert_eq!(res, Done(&b";\n"[..], ScalarValue::Integer32(-42i32)));
}

#[test]
fn env_int64_scalar_values() {
// Set up environment variables
use std::env;
env::set_var("TEST_INT64", "+42L");

let input = &b"$\"TEST_INT64\"::int;\n"[..];
let res = int_scalar_value(input);
assert_eq!(res, Done(&b";\n"[..], ScalarValue::Integer64(42i64)));

let input = &b"$\"TEST_INT_NOT_FOUND\"::int;\n"[..];
let res = int_scalar_value(input);
assert_eq!(res, Done(&b";\n"[..], ScalarValue::Integer32(0i32)));
let input = &b"$\"TEST_INT64\"::auto;\n"[..];
let res = auto_env_scalar_value(input);
assert_eq!(res, Done(&b";\n"[..], ScalarValue::Integer64(42i64)));

let input = &b"$\"TEST_INT64\";\n"[..];
let res = auto_env_scalar_value(input);
assert_eq!(res, Done(&b";\n"[..], ScalarValue::Integer64(42i64)));
}

#[test]
fn env_flt32_scalar_values() {
// Set up environment variables
use std::env;
env::set_var("TEST_FLT32", "3.1415");

// Test float
let input = &b"$\"TEST_FLT32\"::flt;\n"[..];
if let Done(_, ScalarValue::Floating32(value)) = flt_scalar_value(input) {
let res = flt_scalar_value(input);
if let Done(_, ScalarValue::Floating32(value)) = res {
assert!(value > 3.1414 && value < 3.1416);
} else {
panic!("Failed to read env f32: {:?}", res);
}

let input = &b"$\"TEST_FLT32_NOT_FOUND\"::flt;\n"[..];
let res = flt_scalar_value(input);
if let Done(_, ScalarValue::Floating32(value)) = res {
assert!(value > -0.0001 && value < 0.0001);
} else {
panic!("Failed to read fake env float: {:?}", res);
}

let input = &b"$\"TEST_FLT32\"::auto;\n"[..];
let res = auto_env_scalar_value(input);
if let Done(_, ScalarValue::Floating32(value)) = res {
assert!(value > 3.1414 && value < 3.1416);
} else {
panic!("Failed to read env f32: {:?}", res);
}

let input = &b"$\"TEST_FLT32\";\n"[..];
let res = auto_env_scalar_value(input);
if let Done(_, ScalarValue::Floating32(value)) = res {
assert!(value > 3.1414 && value < 3.1416);
} else {
panic!("Failed to read env f32");
panic!("Failed to read env f32: {:?}", res);
}
}

#[test]
fn env_flt64_scalar_values() {
// Set up environment variables
use std::env;
env::set_var("TEST_FLT64", "-3.1415L");

let input = &b"$\"TEST_FLT64\"::flt;\n"[..];
if let Done(_, ScalarValue::Floating64(value)) = flt_scalar_value(input) {
let res = flt_scalar_value(input);
if let Done(_, ScalarValue::Floating64(value)) = res {
assert!(value > -3.1416 && value < -3.1414);
} else {
panic!("Failed to read env f64");
panic!("Failed to read env f64: {:?}", res);
}

let input = &b"$\"TEST_FLT_NOT_FOUND\"::flt;\n"[..];
if let Done(_, ScalarValue::Floating32(value)) = flt_scalar_value(input) {
assert!(value > -0.0001 && value < 0.0001);
let input = &b"$\"TEST_FLT64\"::auto;\n"[..];
let res = auto_env_scalar_value(input);
if let Done(_, ScalarValue::Floating64(value)) = res {
assert!(value > -3.1416 && value < -3.1414);
} else {
panic!("Failed to read env f64: {:?}", res);
}

let input = &b"$\"TEST_FLT64\";\n"[..];
let res = auto_env_scalar_value(input);
if let Done(_, ScalarValue::Floating64(value)) = res {
assert!(value > -3.1416 && value < -3.1414);
} else {
panic!("Failed to read fake env float");
panic!("Failed to read env f64: {:?}", res);
}
}

#[test]
fn env_missing_auto_scalar_values() {
let input = &b"$\"TEST_NOT_FOUND\";\n"[..];
let res = auto_env_scalar_value(input);
assert_eq!(res, Done(&b";\n"[..], ScalarValue::Str("".to_string())));
}
}

0 comments on commit 0d0de33

Please sign in to comment.