Skip to content

Commit

Permalink
Merge pull request #11 from dariocurr/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
dariocurr committed Sep 3, 2023
2 parents 33e1ec7 + 76d695a commit 627f2a8
Show file tree
Hide file tree
Showing 9 changed files with 265 additions and 80 deletions.
12 changes: 6 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v3.5.3
- uses: actions/checkout@v3.6.0
with:
ref: ${{ github.ref_name }}

Expand Down Expand Up @@ -59,7 +59,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v3.5.3
- uses: actions/checkout@v3.6.0

- name: Create Github release
uses: softprops/action-gh-release@v1
Expand All @@ -77,7 +77,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v3.5.3
- uses: actions/checkout@v3.6.0

- name: Cache Rust
uses: actions/cache@v3.3.1
Expand Down Expand Up @@ -109,13 +109,13 @@ jobs:

- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v2.0.3
uses: actions/deploy-pages@v2.0.4

update-branches:
needs: release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.5.3
- uses: actions/checkout@v3.6.0

- name: Merge ${{ github.base_ref }} -> develop
uses: devmasx/merge-branch@v1.4.0
Expand All @@ -125,7 +125,7 @@ jobs:
github_token: ${{ github.token }}
type: now

- uses: actions/checkout@v3.5.3
- uses: actions/checkout@v3.6.0
with:
ref: develop

Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v3.5.3
- uses: actions/checkout@v3.6.0

- name: Cache Rust
uses: actions/cache@v3.3.1
Expand All @@ -54,7 +54,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v3.5.3
- uses: actions/checkout@v3.6.0

- name: Cache Rust
uses: actions/cache@v3.3.1
Expand Down Expand Up @@ -89,7 +89,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v3.5.3
- uses: actions/checkout@v3.6.0

- name: Check formatting
run: cargo fmt --check
Expand All @@ -103,7 +103,7 @@ jobs:
os: [ubuntu-latest]
timeout-minutes: 15
steps:
- uses: actions/checkout@v3.5.3
- uses: actions/checkout@v3.6.0

- name: Cache Rust
uses: actions/cache@v3.3.1
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ keywords = [
license = "MIT OR Apache-2.0"
readme = "README.md"
repository = "https://github.com/dariocurr/env-settings"
version = "0.1.2"
version = "0.1.3"
27 changes: 18 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ When you add the `EnvSettings` derive to a `struct`, two methods are added to it

```sh
export name=paolo
export age=42
export favourite_number=42
```

```rs
Expand All @@ -41,25 +41,25 @@ use env_settings_derive::EnvSettings;
struct MyStruct {
name: String,

age: u8,
favourite_number: u8,
}

fn main() {
let my_struct = MyStruct::from_env().unwrap();
assert_eq!(my_struct.name, "paolo".to_string());
assert_eq!(my_struct.age, 42);
assert_eq!(my_struct.favourite_number, 42);

let name = "luca";
let my_struct = MyStruct::new(Some(name.to_string()), None).unwrap();
assert_eq!(my_struct.name, name);
assert_eq!(my_struct.age, 42);
assert_eq!(my_struct.favourite_number, 42);
}
```

### Advanced

```sh
echo "MY_STRUCT_AGE=42\n" > .env
echo "MY_STRUCT_FAVOURITE_NUMBER=42\n" > .env
export MY_BIRTH_DATE=01/01/1970
```

Expand All @@ -72,23 +72,32 @@ struct MyStruct {
#[env_settings(default = "paolo")]
name: String,

age: u8,
favourite_number: u8,

#[env_settings(variable = "MY_BIRTH_DATE")]
birth_date: String,

birth_place: Option<String>
}

fn main() {
let my_struct = MyStruct::from_env().unwrap();
assert_eq!(my_struct.name, "paolo".to_string());
assert_eq!(my_struct.age, 42);
assert_eq!(my_struct.favourite_number, 42);
assert_eq!(my_struct.birth_date, "01/01/1970");
assert_eq!(my_struct.birth_place, None);

let name = "luca";
let my_struct = MyStruct::new(Some(name.to_string()), None, None).unwrap();
let my_struct = MyStruct::new(
Some(name.to_string()),
None,
None,
Some("london".to_string())
).unwrap();
assert_eq!(my_struct.name, name);
assert_eq!(my_struct.age, 42);
assert_eq!(my_struct.favourite_number, 42);
assert_eq!(my_struct.birth_date, "01/01/1970");
assert_eq!(my_struct.birth_place, Some("london".to_string()));
}
```

Expand Down
117 changes: 74 additions & 43 deletions env-settings-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,14 @@ pub fn env_settings_derive(input: TokenStream) -> TokenStream {
/// Implement the logic of the derive macro
fn implement(input: &utils::EnvSettingsInput) -> TokenStream {
let struct_name = &input.name;

let mut new_args = Vec::new();
let mut new_impls = Vec::new();
let mut from_env_impls = Vec::new();

let mut env_variables_impls = quote! {};
let mut file_path_impls = quote! {};

if let Some(file_path) = &input.params.file_path {
if input.params.delay {
file_path_impls = quote! {
Expand All @@ -42,7 +45,9 @@ fn implement(input: &utils::EnvSettingsInput) -> TokenStream {
env_settings_utils::load_env_file_path(file_path).unwrap();
}
}

let case_insensitive = input.params.case_insensitive;

let env_variables = if input.params.delay {
env_variables_impls = quote! {
let env_variables = env_settings_utils::get_env_variables(#case_insensitive);
Expand All @@ -51,11 +56,14 @@ fn implement(input: &utils::EnvSettingsInput) -> TokenStream {
} else {
env_settings_utils::get_env_variables(case_insensitive)
};

let prefix = input.params.prefix.clone().unwrap_or(String::default());

for EnvSettingsField {
name,
type_,
default,
is_optional,
variable,
} in &input.fields
{
Expand All @@ -64,85 +72,107 @@ fn implement(input: &utils::EnvSettingsInput) -> TokenStream {
env_variable = env_variable.to_lowercase();
}
let name_string = name.to_string();
let type_string = type_.to_string();
let type_string = type_
.iter()
.map(|segment| segment.ident.to_string())
.collect::<Vec<String>>()
.join("::");

// the variable involded must be named `value`
let optional_value_impl = if *is_optional {
quote! { Some(value) }
} else {
quote! { value }
};

// the variable involded must be named `value_to_parse`
let convert_err_impl = quote! {
return Err(env_settings_utils::EnvSettingsError::Convert(
#name_string,
value_to_parse.to_owned(),
#type_string,
))
};

let default_impl = match default {
Some(default_value) => quote! {
match #default_value.parse::<#type_>() {
Ok(default_value) => default_value,
Err(_) => return Err(env_settings_utils::EnvSettingsError::Convert(
#name_string,
#default_value.to_owned(),
#type_string,
))
Some(value_to_parse) => {
quote! {
match #value_to_parse.parse::<#type_>() {
Ok(value) => #optional_value_impl,
Err(_) => {
let value_to_parse = #value_to_parse.to_owned();
#convert_err_impl
}
}
}
},
}
None => {
quote! {
return Err(env_settings_utils::EnvSettingsError::NotExists(#env_variable))
if *is_optional {
quote! { None }
} else {
quote! { return Err(env_settings_utils::EnvSettingsError::NotExists(#env_variable)) }
}
}
};

// the variable involded must be named `value_to_parse`
let parse_impl = quote! {
match value_to_parse.parse::<#type_>() {
Ok(value) => #optional_value_impl,
Err(_) => #convert_err_impl
}
};

// the variable involded must be named `env_variables`
let env_value_impl = if input.params.delay {
quote! {
match env_variables.get(#env_variable) {
Some(env_value) => match env_value.parse::<#type_>() {
Ok(env_value) => env_value,
Err(_) => return Err(env_settings_utils::EnvSettingsError::Convert(
#name_string,
env_value.to_owned(),
#type_string,
)),
},
Some(value_to_parse) => #parse_impl,
None => #default_impl,
}
}
} else {
match env_variables.get(&env_variable) {
Some(env_value) => {
quote! {
match #env_value.parse::<#type_>() {
Ok(env_value) => env_value,
Err(_) => return Err(env_settings_utils::EnvSettingsError::Convert(
#name_string,
#env_value.to_owned(),
#type_string,
))
}
Some(value_to_parse) => quote! {
{
let value_to_parse = #value_to_parse.to_owned();
#parse_impl
}
}
},

None => quote! { #default_impl },
}
};
from_env_impls.push(quote! {
#name: #env_value_impl
});

new_impls.push(quote! {
#name: match #name {
Some(field_value) => field_value,
Some(value) => #optional_value_impl,
None => #env_value_impl
}
});
new_args.push(quote!(
#name: Option<#type_>
));
new_args.push(quote! { #name: Option<#type_> });
from_env_impls.push(quote! { #name: #env_value_impl });
}

let pre_impls = quote! {
#file_path_impls
#env_variables_impls
};

let gen = quote! {

impl #struct_name {

fn new(#(#new_args),*) -> env_settings_utils::EnvSettingsResult<Self> {
#file_path_impls
#env_variables_impls

#pre_impls
let instance = Self {
#(#new_impls),*
};
Ok(instance)
}

fn from_env() -> env_settings_utils::EnvSettingsResult<Self> {
#file_path_impls
#env_variables_impls
#pre_impls
let instance = Self {
#(#from_env_impls),*
};
Expand All @@ -152,5 +182,6 @@ fn implement(input: &utils::EnvSettingsInput) -> TokenStream {
}

};

gen.into()
}
Loading

0 comments on commit 627f2a8

Please sign in to comment.