summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsaber.wu <saber.wu@trantect.com>2018-06-14 17:09:43 +0800
committersaber.wu <saber.wu@trantect.com>2018-06-15 11:13:53 +0800
commitba6014543dfb4040921bb4809c6b293cfdf33c84 (patch)
tree523708c74eb31e5c861c7e474f092fafbd416879
parente8fa9fee96185ddd18ebcef8a925c75459111edb (diff)
support ini
-rw-r--r--Cargo.toml5
-rw-r--r--README.md4
-rw-r--r--src/file/format/ini.rs32
-rw-r--r--src/file/format/mod.rs13
-rw-r--r--src/lib.rs3
-rw-r--r--tests/Settings-invalid.ini2
-rw-r--r--tests/Settings.ini9
-rw-r--r--tests/datetime.rs17
-rw-r--r--tests/file_ini.rs60
-rw-r--r--tests/file_json.rs2
10 files changed, 144 insertions, 3 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 8ee4d4c..8a33e4d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,10 +14,12 @@ license = "MIT/Apache-2.0"
travis-ci = { repository = "mehcode/config-rs" }
[features]
-default = ["toml", "json", "yaml", "hjson"]
+default = ["toml", "json", "yaml", "hjson","ini"]
json = ["serde_json"]
yaml = ["yaml-rust"]
hjson = ["serde-hjson"]
+ini = []
+
[dependencies]
lazy_static = "1.0"
@@ -28,6 +30,7 @@ toml = { version = "^0.4.1", optional = true }
serde_json = { version = "^1.0.2", optional = true }
yaml-rust = { version = "^0.4", optional = true }
serde-hjson = { version = "^0.8.1", optional = true }
+rust-ini = "0.12.1"
[dev-dependencies]
serde_derive = "^1.0.8"
diff --git a/README.md b/README.md
index ea2d4b0..b77daa9 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@
- Set defaults
- Set explicit values (to programmatically override)
- - Read from [JSON], [TOML], [YAML] and [HJSON] files
+ - Read from [JSON], [TOML], [YAML], [HJSON], [INI] files
- Read from environment
- Loosely typed — Configuration values may be read in any supported type, as long as there exists a reasonable conversion
- Access nested fields using a formatted path — Uses a subset of JSONPath; currently supports the child ( `redis.port` ) and subscript operators ( `databases[0].name` )
@@ -19,6 +19,7 @@
[TOML]: https://github.com/toml-lang/toml
[YAML]: https://github.com/chyh1990/yaml-rust
[HJSON]: https://github.com/hjson/hjson-rust
+[INI]: https://github.com/zonyitoo/rust-ini
## Usage
@@ -27,6 +28,7 @@
config = "0.8"
```
+ - `ini` - Adds support for reading INI files
- `json` - Adds support for reading JSON files
- `hjson` - Adds support for reading HJSON files
- `yaml` - Adds support for reading YAML files
diff --git a/src/file/format/ini.rs b/src/file/format/ini.rs
new file mode 100644
index 0000000..b7c0f71
--- /dev/null
+++ b/src/file/format/ini.rs
@@ -0,0 +1,32 @@
+use source::Source;
+use std::collections::HashMap;
+use std::error::Error;
+use value::{Value, ValueKind};
+use ini::Ini;
+
+pub fn parse(
+ uri: Option<&String>,
+ text: &str,
+) -> Result<HashMap<String, Value>, Box<Error + Send + Sync>> {
+ let mut map: HashMap<String, Value> = HashMap::new();
+ let i = Ini::load_from_str(text)?;
+ for (sec, prop) in i.iter() {
+ match *sec {
+ Some(ref sec) => {
+ let mut sec_map: HashMap<String, Value> = HashMap::new();
+ for (k, v) in prop.iter() {
+ sec_map.insert(k.to_lowercase().clone(),
+ Value::new(uri, ValueKind::String(v.clone())));
+ }
+ map.insert(sec.to_lowercase().clone(), Value::new(uri, ValueKind::Table(sec_map)));
+ }
+ None => {
+ for (k, v) in prop.iter() {
+ map.insert(k.to_lowercase().clone(),
+ Value::new(uri, ValueKind::String(v.clone())));
+ }
+ }
+ }
+ }
+ Ok(map)
+}
diff --git a/src/file/format/mod.rs b/src/file/format/mod.rs
index 5dfdfde..65e2914 100644
--- a/src/file/format/mod.rs
+++ b/src/file/format/mod.rs
@@ -19,6 +19,9 @@ mod yaml;
#[cfg(feature = "hjson")]
mod hjson;
+#[cfg(feature = "ini")]
+mod ini;
+
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum FileFormat {
/// TOML (parsed with toml)
@@ -36,6 +39,10 @@ pub enum FileFormat {
/// HJSON (parsed with serde_hjson)
#[cfg(feature = "hjson")]
Hjson,
+ /// INI (parsed with serde_hjson)
+ #[cfg(feature = "ini")]
+ Ini,
+
}
lazy_static! {
@@ -56,6 +63,9 @@ lazy_static! {
#[cfg(feature = "hjson")]
formats.insert(FileFormat::Hjson, vec!["hjson"]);
+ #[cfg(feature = "ini")]
+ formats.insert(FileFormat::Ini, vec!["ini"]);
+
formats
};
}
@@ -90,6 +100,9 @@ impl FileFormat {
#[cfg(feature = "hjson")]
FileFormat::Hjson => hjson::parse(uri, text),
+
+ #[cfg(feature = "ini")]
+ FileFormat::Ini => ini::parse(uri, text),
}
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 6178375..ad205d0 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -43,6 +43,9 @@ extern crate yaml_rust;
#[cfg(feature = "hjson")]
extern crate serde_hjson;
+#[cfg(feature = "ini")]
+extern crate ini;
+
mod error;
mod value;
mod de;
diff --git a/tests/Settings-invalid.ini b/tests/Settings-invalid.ini
new file mode 100644
index 0000000..f2b8d9b
--- /dev/null
+++ b/tests/Settings-invalid.ini
@@ -0,0 +1,2 @@
+ok : true,
+error
diff --git a/tests/Settings.ini b/tests/Settings.ini
new file mode 100644
index 0000000..16badd4
--- /dev/null
+++ b/tests/Settings.ini
@@ -0,0 +1,9 @@
+debug = true
+production = false
+[place]
+name = Torre di Pisa
+longitude = 43.7224985
+latitude = 10.3970522
+favorite = false
+reviews = 3866
+rating = 4.5
diff --git a/tests/datetime.rs b/tests/datetime.rs
index 89a34a1..26b395d 100644
--- a/tests/datetime.rs
+++ b/tests/datetime.rs
@@ -38,6 +38,13 @@ fn make() -> Config {
FileFormat::Hjson,
))
.unwrap()
+ .merge(File::from_str(
+ r#"
+ ini_datetime = 2017-05-10T02:14:53Z
+ "#,
+ FileFormat::Ini,
+ ))
+ .unwrap()
.clone()
}
@@ -64,6 +71,11 @@ fn test_datetime_string() {
let date: String = s.get("hjson_datetime").unwrap();
assert_eq!(&date, "2017-05-10T02:14:53Z");
+
+ // INI
+ let date: String = s.get("ini_datetime").unwrap();
+
+ assert_eq!(&date, "2017-05-10T02:14:53Z");
}
#[test]
@@ -89,4 +101,9 @@ fn test_datetime() {
let date: DateTime<Utc> = s.get("hjson_datetime").unwrap();
assert_eq!(date, Utc.ymd(2017, 5, 10).and_hms(2, 14, 53));
+
+ // INI
+ let date: DateTime<Utc> = s.get("ini_datetime").unwrap();
+
+ assert_eq!(date, Utc.ymd(2017, 5, 10).and_hms(2, 14, 53));
}
diff --git a/tests/file_ini.rs b/tests/file_ini.rs
new file mode 100644
index 0000000..4c0030a
--- /dev/null
+++ b/tests/file_ini.rs
@@ -0,0 +1,60 @@
+extern crate config;
+extern crate serde;
+extern crate float_cmp;
+
+#[macro_use]
+extern crate serde_derive;
+
+use config::*;
+
+#[derive(Debug, Deserialize, PartialEq)]
+struct Place {
+ name: String,
+ longitude: f64,
+ latitude: f64,
+ favorite: bool,
+ reviews: u64,
+ rating: Option<f32>,
+}
+
+#[derive(Debug, Deserialize, PartialEq)]
+struct Settings {
+ debug: f64,
+ place: Place,
+}
+
+fn make() -> Config {
+ let mut c = Config::default();
+ c.merge(File::new("tests/Settings", FileFormat::Ini))
+ .unwrap();
+ c
+}
+
+#[test]
+fn test_file() {
+ let c = make();
+ let s: Settings = c.try_into().unwrap();
+ assert_eq!(s, Settings {
+ debug: 1.0,
+ place: Place {
+ name: String::from("Torre di Pisa"),
+ longitude: 43.7224985,
+ latitude: 10.3970522,
+ favorite: false,
+ reviews: 3866,
+ rating: Some(4.5),
+ },
+ });
+}
+
+#[test]
+fn test_error_parse() {
+ let mut c = Config::default();
+ let res = c.merge(File::new("tests/Settings-invalid", FileFormat::Ini));
+
+ assert!(res.is_err());
+ assert_eq!(
+ res.unwrap_err().to_string(),
+ r#"2:0 Expecting "[Some('='), Some(':')]" but found EOF. in tests/Settings-invalid.ini"#
+ );
+}
diff --git a/tests/file_json.rs b/tests/file_json.rs
index 1d35cae..8bffe23 100644
--- a/tests/file_json.rs
+++ b/tests/file_json.rs
@@ -72,4 +72,4 @@ fn test_error_parse() {
res.unwrap_err().to_string(),
"expected `:` at line 4 column 1 in tests/Settings-invalid.json".to_string()
);
-}
+} \ No newline at end of file