1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
//! This module implements configuration related stuff.

use std::fmt;
use std::env;
use std::io::Read;
use std::fs::File;
use std::path::Path;
use std::collections::BTreeMap;
use rustc_serialize::json::{Object, Json};


/// The pencil `Config` type, We provide ways to fill it from JSON files:
///
/// ```rust,no_run
/// let mut app = pencil::Pencil::new("/demo");
/// app.config.from_jsonfile("yourconfig.json")
/// ```
///
/// You can also load configurations from an environment variable
/// pointing to a file:
///
/// ```rust,no_run
/// let mut app = pencil::Pencil::new("/demo");
/// app.config.from_envvar("YOURAPPLICATION_SETTINGS")
/// ```
///
/// In this case, you have to set this environment variable to the file
/// you want to use.  On Linux and OS X you can use the export statement:
///
/// ```bash
/// export YOURAPPLICATION_SETTINGS="/path/to/config/file"
/// ```
#[derive(Clone)]
pub struct Config {
    config: Object,
}

impl Default for Config {
    fn default() -> Config {
        Config::new()
    }
}

impl Config {
    /// Create a `Config` object.
    pub fn new() -> Config {
        let json_object: Object = BTreeMap::new();
        Config {
            config: json_object,
        }
    }

    /// Set a value for the key.
    pub fn set(&mut self, key: &str, value: Json) {
        self.config.insert(key.to_string(), value);
    }

    /// Returns a reference to the value corresponding to the key.
    pub fn get(&self, key: &str) -> Option<&Json> {
        self.config.get(&key.to_string())
    }

    /// Get a boolean configuration value.  If the key doesn't exist
    /// or the value is not a `Json::Boolean`, the default value
    /// will be returned.
    pub fn get_boolean(&self, key: &str, default: bool) -> bool {
        match self.get(key) {
            Some(value) => {
                match *value {
                    Json::Boolean(value) => value,
                    _ => default
                }   
            },  
            None => default
        }
    }

    /// Loads a configuration from an environment variable pointing to
    /// a JSON configuration file.
    pub fn from_envvar(&mut self, variable_name: &str) {
        match env::var(variable_name) {
            Ok(value) => self.from_jsonfile(&value),
            Err(_) => panic!("The environment variable {} is not set.", variable_name),
        }
    }

    /// Updates the values in the config from a JSON file.
    pub fn from_jsonfile(&mut self, filepath: &str) {
        let path = Path::new(filepath);
        let mut file = File::open(&path).unwrap();
        let mut content = String::new();
        file.read_to_string(&mut content).unwrap();
        let object: Json = Json::from_str(&content).unwrap();
        match object {
            Json::Object(object) => { self.from_object(object); },
            _ => { panic!("The configuration file is not an JSON object."); }
        }
    }

    /// Updates the values from the given `Object`.
    pub fn from_object(&mut self, object: Object) {
        for (key, value) in &object {
            self.set(&key, value.clone());
        }
    }
}

impl fmt::Debug for Config {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<Pencil Config {:?}>", self.config)
    }
}