summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRyan Leckey <leckey.ryan@gmail.com>2017-01-26 00:09:41 -0800
committerRyan Leckey <leckey.ryan@gmail.com>2017-01-26 00:09:41 -0800
commita6fb2f92dc8d53660c1d2d066f146ef261052330 (patch)
treed66d90b8e563f0df6bee8563847ba9e67edfa9b7
parent7c696e6b457debb0faca4fdb0d55e3ed43773484 (diff)
Add some examples
-rw-r--r--examples/basic-file/Cargo.toml7
-rw-r--r--examples/basic-file/src/main.rs9
-rw-r--r--examples/basic/Cargo.toml7
-rw-r--r--examples/basic/src/main.rs31
-rw-r--r--src/file.rs143
-rw-r--r--src/lib.rs7
-rw-r--r--src/source.rs127
-rw-r--r--src/value.rs11
8 files changed, 206 insertions, 136 deletions
diff --git a/examples/basic-file/Cargo.toml b/examples/basic-file/Cargo.toml
new file mode 100644
index 0000000..ffef864
--- /dev/null
+++ b/examples/basic-file/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "basic-file"
+version = "0.1.0"
+authors = ["Ryan Leckey <leckey.ryan@gmail.com>"]
+
+[dependencies]
+config = { path = "../.." }
diff --git a/examples/basic-file/src/main.rs b/examples/basic-file/src/main.rs
new file mode 100644
index 0000000..ae394f9
--- /dev/null
+++ b/examples/basic-file/src/main.rs
@@ -0,0 +1,9 @@
+extern crate config;
+
+fn main() {
+ // Read configuration from $(cwd)/Cargo.toml
+ config::merge(config::File::with_name("Cargo")).unwrap();
+
+ println!("package.name = {:?}", config::get_str("package.name"));
+ println!("package.version = {:?}", config::get_str("package.version"));
+}
diff --git a/examples/basic/Cargo.toml b/examples/basic/Cargo.toml
new file mode 100644
index 0000000..2cb273b
--- /dev/null
+++ b/examples/basic/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "basic"
+version = "0.1.0"
+authors = ["Ryan Leckey <leckey.ryan@gmail.com>"]
+
+[dependencies]
+config = { path = "../.." }
diff --git a/examples/basic/src/main.rs b/examples/basic/src/main.rs
new file mode 100644
index 0000000..a0e40bf
--- /dev/null
+++ b/examples/basic/src/main.rs
@@ -0,0 +1,31 @@
+extern crate config;
+
+fn main() {
+ // Set defaults for `window.width` and `window.height`
+ config::set_default("window.title", "Basic");
+ config::set_default("window.width", 640);
+ config::set_default("window.height", 480);
+ config::set_default("debug", true);
+
+ // Note that you can retrieve the stored values as any type as long
+ // as there exists a reasonable conversion
+ println!("window.title : {:?}", config::get_str("window.title"));
+ println!("window.width : {:?}", config::get_str("window.width"));
+ println!("window.width : {:?}", config::get_int("window.width"));
+ println!("debug : {:?}", config::get_bool("debug"));
+ println!("debug : {:?}", config::get_str("debug"));
+ println!("debug : {:?}", config::get_int("debug"));
+
+ // Attempting to get a value as a type that cannot be reasonably
+ // converted to will return None
+ println!("window.title : {:?}", config::get_bool("window.title"));
+
+ // Instead of using a get_* function you can get the variant
+ // directly
+ println!("debug : {:?}", config::get("debug"));
+ println!("debug : {:?}",
+ config::get("debug").unwrap().as_int());
+
+ // Attempting to get a value that does not exist will return None
+ println!("not-found : {:?}", config::get("not-found"));
+}
diff --git a/src/file.rs b/src/file.rs
new file mode 100644
index 0000000..2ffc836
--- /dev/null
+++ b/src/file.rs
@@ -0,0 +1,143 @@
+use std::fs;
+use std::env;
+use std::error::Error;
+use std::io::Read;
+use std::collections::HashMap;
+
+use toml;
+
+use value::Value;
+use source::Source;
+
+#[derive(Default)]
+pub struct File {
+ /// Basename of configuration file
+ name: String,
+
+ /// Directory where configuration file is found
+ /// When not specified, the current working directory (CWD) is considered
+ path: Option<String>,
+
+ /// Namespace to restrict configuration from the file
+ namespace: Option<String>,
+
+ /// A required File will error if it cannot be found
+ required: bool,
+}
+
+impl File {
+ pub fn with_name(name: &str) -> File {
+ File {
+ name: name.into(),
+ required: true,
+
+ ..Default::default()
+ }
+ }
+
+ pub fn path(&mut self, path: &str) -> &mut File {
+ self.path = Some(path.into());
+ self
+ }
+
+ pub fn namespace(&mut self, namespace: &str) -> &mut File {
+ self.namespace = Some(namespace.into());
+ self
+ }
+
+ pub fn required(&mut self, required: bool) -> &mut File {
+ self.required = required;
+ self
+ }
+}
+
+fn toml_collect(content: &mut HashMap<String, Value>,
+ table: &toml::Table,
+ prefix: Option<String>) {
+ for (key, value) in table {
+ // Construct full key from prefix
+ let key = if let Some(ref prefix) = prefix {
+ prefix.clone() + "." + key
+ } else {
+ key.clone()
+ };
+
+ match *value {
+ // Recurse into nested table
+ toml::Value::Table(ref table) => toml_collect(content, table, Some(key)),
+
+ toml::Value::String(ref value) => {
+ content.insert(key, value.clone().into());
+ }
+
+ toml::Value::Integer(value) => {
+ content.insert(key, value.into());
+ }
+
+ toml::Value::Float(value) => {
+ content.insert(key, value.into());
+ }
+
+ toml::Value::Boolean(value) => {
+ content.insert(key, value.into());
+ }
+
+ _ => {
+ // Unhandled
+ }
+ }
+ }
+}
+
+impl Source for File {
+ fn build(&mut self) -> Result<HashMap<String, Value>, Box<Error>> {
+ let mut content = HashMap::new();
+
+ // Find file
+ // TODO: Use a nearest algorithm rather than strictly CWD
+ let cwd = match env::current_dir() {
+ Ok(cwd) => cwd,
+ Err(err) => {
+ if self.required {
+ return Err(From::from(err));
+ } else {
+ return Ok(content);
+ }
+ }
+ };
+
+ let filename = cwd.join(self.name.clone() + ".toml");
+
+ // Read contents from file
+ let mut file = match fs::File::open(filename) {
+ Ok(file) => file,
+ Err(err) => {
+ if self.required {
+ return Err(From::from(err));
+ } else {
+ return Ok(content);
+ }
+ }
+ };
+
+ let mut buffer = String::new();
+ let res = file.read_to_string(&mut buffer);
+ if res.is_err() {
+ if self.required {
+ return Err(From::from(res.err().unwrap()));
+ } else {
+ return Ok(content);
+ }
+ }
+
+ // Parse
+ let mut parser = toml::Parser::new(&buffer);
+ // TODO: Get a solution to make this return an Error-able
+ let document = parser.parse().unwrap();
+
+ // Iterate through document and fill content
+ toml_collect(&mut content, &document, None);
+
+ Ok(content)
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 0ae525b..426b526 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -5,6 +5,7 @@ extern crate toml;
mod value;
mod source;
+mod file;
mod config;
use std::error::Error;
@@ -12,7 +13,7 @@ use std::borrow::Cow;
use std::sync::{Once, ONCE_INIT};
pub use source::Source;
-pub use source::File;
+pub use file::File;
pub use value::Value;
@@ -25,9 +26,7 @@ static CONFIG_INIT: Once = ONCE_INIT;
// Get the global configuration instance
fn global() -> &'static mut Config {
unsafe {
- CONFIG_INIT.call_once(|| {
- CONFIG = Some(Default::default());
- });
+ CONFIG_INIT.call_once(|| { CONFIG = Some(Default::default()); });
CONFIG.as_mut().unwrap()
}
diff --git a/src/source.rs b/src/source.rs
index b608097..95785a6 100644
--- a/src/source.rs
+++ b/src/source.rs
@@ -1,135 +1,8 @@
-use std::fs;
-use std::env;
use std::error::Error;
-use std::io::Read;
use std::collections::HashMap;
-use toml;
-
use value::Value;
pub trait Source {
fn build(&mut self) -> Result<HashMap<String, Value>, Box<Error>>;
}
-
-#[derive(Default)]
-pub struct File {
- // Basename of configuration file
- name: String,
-
- // Namespace to restrict configuration from the file
- namespace: Option<String>,
-
- // A required File will error if it cannot be found
- required: bool,
-}
-
-impl File {
- pub fn with_name(name: &str) -> File {
- File {
- name: name.into(),
- required: true,
-
- ..Default::default()
- }
- }
-
- pub fn namespace(&mut self, namespace: &str) -> &mut File {
- self.namespace = Some(namespace.into());
- self
- }
-
- pub fn required(&mut self, required: bool) -> &mut File {
- self.required = required;
- self
- }
-}
-
-fn collect(content: &mut HashMap<String, Value>, table: &toml::Table, prefix: Option<String>) {
- for (key, value) in table {
- // Construct full key from prefix
- let key = if let Some(ref prefix) = prefix {
- prefix.clone() + "." + key
- } else {
- key.clone()
- };
-
- match *value {
- // Recurse into nested table
- toml::Value::Table(ref table) => collect(content, table, Some(key)),
-
- toml::Value::String(ref value) => {
- content.insert(key, value.clone().into());
- }
-
- toml::Value::Integer(value) => {
- content.insert(key, value.into());
- }
-
- toml::Value::Float(value) => {
- content.insert(key, value.into());
- }
-
- toml::Value::Boolean(value) => {
- content.insert(key, value.into());
- }
-
- _ => {
- // Unhandled
- }
- }
- }
-}
-
-impl Source for File {
- fn build(&mut self) -> Result<HashMap<String, Value>, Box<Error>> {
- let mut content = HashMap::new();
-
- // Find file
- // TODO: Use a nearest algorithm rather than strictly CWD
- let cwd = match env::current_dir() {
- Ok(cwd) => cwd,
- Err(err) => {
- if self.required {
- return Err(From::from(err));
- } else {
- return Ok(content);
- }
- }
- };
-
- let filename = cwd.join(self.name.clone() + ".toml");
-
- // Read contents from file
- let mut file = match fs::File::open(filename) {
- Ok(file) => file,
- Err(err) => {
- if self.required {
- return Err(From::from(err));
- } else {
- return Ok(content);
- }
- }
- };
-
- let mut buffer = String::new();
- let res = file.read_to_string(&mut buffer);
- if res.is_err() {
- if self.required {
- return Err(From::from(res.err().unwrap()));
- } else {
- return Ok(content);
- }
- }
-
- // Parse
- let mut parser = toml::Parser::new(&buffer);
- // TODO: Get a solution to make this return an Error-able
- let document = parser.parse().unwrap();
-
- // Iterate through document and fill content
- collect(&mut content, &document, None);
-
- Ok(content)
- }
-}
diff --git a/src/value.rs b/src/value.rs
index 192632b..52a2103 100644
--- a/src/value.rs
+++ b/src/value.rs
@@ -5,7 +5,7 @@ use std::borrow::Cow;
///
/// Has an underlying or native type that comes from the configuration source
/// but will be coerced into the requested type.
-#[derive(Clone)]
+#[derive(Debug, Clone)]
pub enum Value {
String(String),
Integer(i64),
@@ -35,10 +35,11 @@ impl Value {
if let Value::Boolean(value) = *self {
Some(value)
} else if let Value::String(ref value) = *self {
- Some(match value.to_lowercase().as_ref() {
- "1" | "true" | "on" | "yes" => true,
- _ => false,
- })
+ match value.to_lowercase().as_ref() {
+ "1" | "true" | "on" | "yes" => Some(true),
+ "0" | "false" | "off" | "no" => Some(false),
+ _ => None,
+ }
} else if let Value::Integer(value) = *self {
Some(value != 0)
} else if let Value::Float(value) = *self {