8 个不稳定版本 (3 个破坏性更新)
0.4.0 | 2020年6月1日 |
---|---|
0.3.1 | 2020年3月3日 |
0.2.3 | 2020年3月2日 |
0.1.0 | 2020年2月29日 |
#877 in 配置
每月23次下载
用于 glitchup
69KB
842 行
cfgmap
这个crate包含一个新的数据结构,它作为一个包装器围绕着一个HashMap
。它提供了一个自己的数据枚举(CfgValue)
,并包含多个辅助函数,可以轻松地在哈希表中导航。
其主要目的是用于配置,同时也支持验证。本质上,一个CfgMap
将代表一个应用程序的配置。到目前为止,配置的替代方案是直接使用数据格式库,或者使用一个结构体,例如JSON或TOML,将其序列化。
这可以非常令人满意,特别是对于基本的配置,但在某些情况下可能会显得有些繁琐。例如,如果你计划在某些选项未设置时使用默认选项,需要验证多个嵌套对象等。
如果你想使用这个crate提供的最常见功能,你可以这样做
use cfgmap::prelude::*;
这将包括CfgMap
,所有CfgValue
,所有公共宏,所有Conditions
,以及Checkable
特性。
特性
这个crate是可定制的,可以根据你的需求提供多个特性
from_toml
:允许从TOML
值创建哈希表,还包含额外的Datetime
CfgValue
。from_json
:允许从JSON
值创建哈希表,还包含额外的Null
CfgValue
。generator
:为CfgValue
提供了额外的生成数字(整数或浮点数)的方法。
教程(类似)
创建一个新的CfgMap
非常简单,有多种方法
use cfgmap::CfgMap;
let map1 = CfgMap::new();
let mut map2 = CfgMap::new();
map2.default = "default".into();
CfgMap
允许对默认值进行一些功能设置。对于上面的 map1
,default
从未被设置,因此值将从根目录检索。然而,对于 map2
,假设所有默认值都位于 default
中。
路径语法
CfgMap
还支持其键的特定 path
语法。
cfgmap.get("hello/there/pal");
这有助于轻松访问嵌套项。上面的行本质上等于
map.get("hello")
.and_then(|a| a.as_map())
.and_then(|a| a.get("there"))
.and_then(|a| a.as_map())
.and_then(|a| a.get("pal"));
注意,如果 hello
或 there
不是 CfgMap
,整个表达式的求值结果将为 None
。此键还可以包含数组索引。例如,对于 a/0/c
,它将检查 a
是一个 Map
还是 List
。如果是前者,它将尝试找到具有值 0
的键。如果是后者,它将尝试索引列表。
条件
现在,如果你想检查某个值求值的结果是什么?如果你想要使用任何值,你很快就会遇到这个问题。这个库提供了对 Conditions
的广泛支持!
use cfgmap::{Condition::*, Checkable};
let is_number = cfgmap.get("hello/there/pal").check_that(IsInt | IsFloat);
上面的行将检查 hello/there/pal
位置的值是否为 CfgValue::Int
或 CfgValue::Float
。更多条件列在这里。如果你希望添加更多条件,请随时提出问题或提交 PR!所有这些都有助于帮助验证特定值。
默认值
默认值也可以非常容易地使用:
map.get_option("http_settings", "ip_address");
假设 map
在其默认值 default
下初始化。上面的行将与以下行等效
map.get("http_settings/ip_address").or(map.get("default/ip_address"));
您还可以使用 update_option
更新选项,就像使用 add
一样。它的工作方式相似,但在找不到选项时不会添加新的选项,只会更新现有的选项。
HashMap 方法
由于 CfgMap
为 HashMap<String, CfgValue>
实现了 Deref
和 DerefMut
,因此所有 HashMap
方法都可用。例如,您可以对其调用 .iter()
,尽管这没有直接实现。
完整示例
use cfgmap::{CfgMap, CfgValue::*, Condition::*, Checkable};
let toml = toml::toml! {
[package]
name = "cfgmap"
version = "0.1.0"
authors = ["Andrea Jenkins <[email protected]>"]
[lib]
name = "cfgmap"
path = "src/cfgmap.rs"
[dependencies]
serde_json = { version = "1.0.48", optional = true }
toml = { version = "0.5.6", optional = true }
[other]
date = 2020-02-29
float = 1.2
int = 3
internal.more = "hello"
[[person]]
name = "a"
[[person]]
name = "b"
};
let cmap = CfgMap::from_toml(toml);
assert!(cmap.get("package/name").check_that(IsExactlyStr("cfgmap".into())));
assert!(cmap.get("package/version").check_that(IsExactlyStr("0.1.0".into())));
assert!(cmap.get("package/authors").check_that(IsExactlyList(vec![Str("Andrea Jenkins <[email protected]>".into())])));
assert!(cmap.get("lib/name").check_that(IsExactlyStr("cfgmap".into())));
assert!(cmap.get("lib/path").check_that(IsExactlyStr("src/cfgmap.rs".into())));
assert!(cmap.get("dependencies/serde_json/version").check_that(IsExactlyStr("1.0.48".into())));
assert!(cmap.get("dependencies/serde_json/optional").check_that(IsTrue));
assert!(cmap.get("dependencies/toml/version").check_that(IsExactlyStr("0.5.6".into())));
assert!(cmap.get("dependencies/toml/optional").check_that(IsTrue));
assert!(cmap.get("other/date").check_that(IsDatetime));
assert!(cmap.get("other/float").check_that(IsExactlyFloat(1.2)));
assert!(cmap.get("other/int").check_that(IsExactlyInt(3)));
assert!(cmap.get("other/internal/more").check_that(IsExactlyStr("hello".into())));
assert!(cmap.get("person").check_that(IsListWith(Box::new(IsMap))));
assert!(cmap.get("person/0/name").check_that(IsExactlyStr("a".into())));
assert!(cmap.get("person/1/name").check_that(IsExactlyStr("b".into())));
依赖关系
~0–430KB