Crates.io | converge_test |
lib.rs | converge_test |
version | 0.0.4 |
source | src |
created_at | 2022-04-20 00:30:14.522343 |
updated_at | 2022-05-04 17:42:22.354867 |
description | Tests for the `converge::Converge` trait and the `converge_derive` proc-macro. |
homepage | |
repository | https://github.com/osynge/converge |
max_upload_size | |
id | 570694 |
size | 16,740 |
Layered configuration system for Rust applications using little code. By only converging configuration, flexibility of the configuration source and how it converges is under control of the user.
Applications which have layered configuration of command line arguments, environment and configuration file, are what users expect. This library allows these sources to be layered with minimal effort and code.
Both The Unix philosophy
and the idea of microservices
lead to writing lots
of applications. It is reasonable to expect these applications will take
configuration from the command line arguments, environment and often a
configuration file. As the applications mature the number of configuration
options tends to grow. A naive approach to managing this is repetitive and error
prone, and adding testing to this increases the repetition.
This library leaves the user free to decide configuration file format, command line parsing method, and has minimal dependencies. It works with structures holding the configuration items as fields. These structures must implement a trait with a single method that is commonly derivable for most structures.
This method works with immutable data structures, is very low in code, but with the cost of cloning the configuration during the layering process. This is a reasonable compromise as it usually happens only once in an applications lifecycle.
It is based on a trait Converge
with a single method
converge
this is in the crate converge
.
pub trait Converge<Rhs = Self> {
fn converge(self, default: Rhs) -> Self;
}
This trait can be derived using converge_derive
as shown below.
#[derive(Converge)]
pub struct Config {
pub config_file: Option<String>,
pub loglevel: Option<i8>,
pub xunit_local_globs: Option<Vec<String>>,
pub environment_sk: Option<String>,
pub environment_keys: Option<Vec<String>>,
pub project_sk: Option<String>,
pub project_identifier: Option<String>,
pub project_human_name: Option<String>,
pub run_identifier: Option<String>,
pub run_sk: Option<String>,
pub service_url: Option<String>,
}
These structures populated from can be nested and can then be coupled together to derive new instances with clear and simple prescience.
let config_commandline : Config = parse_commandline_to_config();
let config_file : Config = parse_file_to_config();
let config_env : Config = parse_env_to_config();
let cfg = config_commandline.converge(config_file).converge(config_env);
It is possible to have T typed fields that are not Optional values, but this not
usual as then converge
just with take the left hand side value.
The structure implementing the trait Converge
should contain a logical
grouping of fields to represent each setting you may wish to use as part of your
layered configuration.
Converge
structures#[derive(Converge)]
pub struct ConfigRabbitMqCredentials {
pub username: Option<String>,
pub password: Option<String>,
}
#[derive(Converge)]
pub struct ConfigRabbitMQ {
pub host: Option<String>,
pub port: Option<i32>,
#[converge(nest)]
pub credentials: Option<ConfigRabbitMqCredentials>,
}
When using Fields types that also implement Converge
you can mark fields as
also supporting Converge
with the #[converge(nest)]
attribute, this then
allows converge
to be used on this structure by converge
.
#[derive(Converge)]
pub struct ConfigRabbitMqCredentials {
pub username: Option<String>,
pub password: Option<String>,
}
#[derive(Converge)]
pub struct ConfigRabbitMQ {
pub host: Option<String>,
pub port: Option<i32>,
#[converge(strategy = converge::strategies::vec::replace_empty)]
pub credentials: Vec<ConfigRabbitMqCredentials>,
}
Fields may alternatively be marked with a custom strategy for a custom converge. Where the strategy is the path to a function in the form:
fn custom_function<T>(lhs: T, rhs: T) -> T
Where T
matches the type of the field. The converge
crate includes some
common generic strategies sorted in modules by container type.
This library is expected to be used in combination with other libraries to parse
configuration file formats, the command line, and the execution environment
variables. In practice the resultant structure presented by these libraries is
often closely bound to the input source. The Converge trait
requires
that each source provides a common data structure. By implementing the
From trait or alternatively the TryFrom trait for your common data format
Converge
can be applied to these data sources.
A non exhaustive list of data source libraries we can recommend to provide configuration data.
A non exhaustive list of possible alternatives.