1 module d_properties.properties;
2 
3 import object : Error;
4 import d_properties.reader;
5 import d_properties.writer;
6 
7 /** 
8  * The properties is a struct containing key-value pairs of strings, which can
9  * be easily and efficiently written to and read from a file.
10  */
11 public struct Properties {
12     /** 
13      * The internal values of this properties struct.
14      */
15     public string[string] values;
16 
17     /** 
18      * Constructs a Properties from the given values.
19      * Params:
20      *   valueMap = The associative array of properties.
21      */
22     public this(string[string] valueMap) {
23         foreach (key, value; valueMap) {
24             this.opIndexAssign(value, key);
25         }
26     }
27 
28     /** 
29      * Constructs a Properties by reading from each of the given files, in the
30      * order that they're provided. Note that properties in an earlier file
31      * will be overwritten by properties of the same key in later files.
32      * Params:
33      *   filenames = The list of filenames.
34      */
35     public this(string[] filenames ...) {
36         foreach (filename; filenames) {
37             Properties p = readFromFile(filename);
38             this.addAll(p);
39         }
40     }
41 
42     /** 
43      * Gets the value of a property, or returns the specified default value if
44      * the given property doesn't exist.
45      * Params:
46      *   key = The property name.
47      *   defaultValue = The default value to use, if no property exists.
48      * Returns: The value of the property, or the default value if the property
49      * doesn't exist.
50      */
51     public string get(string key, string defaultValue=null) {
52         if (key !in values) return defaultValue;
53         return values[key];
54     }
55 
56     /** 
57      * Adds all properties from the given Properties to this one, overwriting
58      * any properties with the same name.
59      * Params:
60      *   properties = The properties to add to this one.
61      */
62     public void addAll(Properties[] properties ...) {
63         foreach (p; properties) {
64             foreach (key, value; p.values) {
65                 this.values[key] = value;
66             }
67         }
68     }
69 
70     /** 
71      * Adds all properties from the given files to this one.
72      * Params:
73      *   filenames = The names of files to read properties from.
74      */
75     public void addAll(string[] filenames ...) {
76         auto p = Properties(filenames);
77         this.addAll(p);
78     }
79 
80     /** 
81      * Gets the value of a property, or throws a missing property exception.
82      * Params:
83      *   key = The property name.
84      * Returns: The value of the property.
85      */
86     string opIndex(string key) {
87         if (key !in values) throw new MissingPropertyException(key);
88         return values[key];
89     }
90 
91     /** 
92      * Assigns the given value to a property.
93      * Params:
94      *   value = The value of the property.
95      *   key = The property name.
96      */
97     void opIndexAssign(string value, string key) {
98         values[key] = value;
99     }
100 
101     bool opEquals(Properties other) {
102         return this.values == other.values;
103     }
104 
105     bool opBinaryRight(string op)(string key) const if (op == "in") {
106         return (key in this.values) != null;
107     }
108 }
109 
110 /** 
111  * Exception that's thrown when attempting to index an unknown key.
112  */
113 class MissingPropertyException : Error {
114     this(string missingKey) {
115         super("Missing value for key \"" ~ missingKey ~ "\".");
116     }
117 }