1 /// Simple mixin property getter/setter generator
2 module sily.property;
3 
4 import std.traits;
5 
6 /**
7 Generates mixin for automatic property injection. All properties
8 are created as `public final @property`. 
9 
10 Important! If symbol with same name, as property going to be, is present
11 then D will completely override property with that symbol
12 
13 Example:
14 ---
15 // Generates property for "_data" with name "data"
16 mixin property!_data;
17 // Generates only getter for "_data" with name "data"
18 mixin getter!_data;
19 // Generates only setter for "_data" with name "data"
20 mixin setter!_data;
21 
22 // Prefix manipulation, works with getter! and setter! too
23 // _data -> data (removes "_" prefix, default behaviour)
24 mixin property!_data;
25 // __data -> data (removes supplied prefix)
26 mixin property!(__data, "__");
27 // __data -> gdata (replaces supplied prefix)
28 mixin property!(__data, "__", "g");
29 // _data -> c_data (adds new prefix)
30 mixin property!(_data, "", "c");
31 // _data -> _data (can't match prefix, keeping as is)
32 mixin property!(_data, "A");
33 mixin property!(_data, "A", "B");
34 // _data -> propertyData (replaces entire name)
35 mixin property!(_data, "propertyData", true);
36 ---
37 */
38 mixin template property(alias symbol, string prefixRem = "_", string prefixAdd = "") {
39     mixin( ___silyPropertyGenGetter!(symbol, prefixRem, prefixAdd, false) );
40     mixin( ___silyPropertyGenSetter!(symbol, prefixRem, prefixAdd, false) );
41 }
42 
43 /// Ditto
44 mixin template setter(alias symbol, string prefixRem = "_", string prefixAdd = "") {
45     mixin( ___silyPropertyGenSetter!(symbol, prefixRem, prefixAdd, false) );
46 }
47 
48 /// Ditto
49 mixin template getter(alias symbol, string prefixRem = "_", string prefixAdd = "") {
50     mixin( ___silyPropertyGenGetter!(symbol, prefixRem, prefixAdd, false) );
51 }
52 
53 /// Ditto
54 mixin template property(alias symbol, string symbolRename, bool B) if (B == true) {
55     mixin( ___silyPropertyGenGetter!(symbol, "", symbolRename, true) );
56     mixin( ___silyPropertyGenSetter!(symbol, "", symbolRename, true) );
57 }
58 
59 /// Ditto
60 mixin template setter(alias symbol, string symbolRename, bool B) if (B == true) {
61     mixin( ___silyPropertyGenSetter!(symbol, "", symbolRename, true) );
62 }
63 
64 /// Ditto
65 mixin template getter(alias symbol, string symbolRename, bool B) if (B == true) {
66     mixin( ___silyPropertyGenGetter!(symbol, "", symbolRename, true) );
67 }
68 
69 static string ___silyPropertyGenGetter(alias symbol, string prefixStringRem, 
70                         string prefixStringAdd, bool prefixAsRename = false)() {
71     import std.algorithm.searching: countUntil;
72     import std.string: format;
73     import std.array: replaceFirst;
74     string _symname = __traits(identifier, symbol);
75     string _getname = __traits(identifier, symbol);
76     string _type = typeof(symbol).stringof;
77     if (prefixAsRename) {
78         _getname = prefixStringAdd;
79     } else {
80         if (_symname.countUntil(prefixStringRem) == 0) {
81             _getname = _symname.replaceFirst(prefixStringRem, prefixStringAdd);
82         }
83         if (prefixStringRem == "") _getname = prefixStringAdd ~ _symname;
84     }
85     return "public final %s %s() @property { return %s; }".format(
86         _type, _getname, _symname
87     );
88 }
89 
90 static string ___silyPropertyGenSetter(alias symbol, string prefixStringRem, 
91                         string prefixStringAdd, bool prefixAsRename = false)() {
92     import std.algorithm.searching: countUntil;
93     import std.string: format;
94     import std.array: replaceFirst;
95     string _symname = __traits(identifier, symbol);
96     string _setname = __traits(identifier, symbol);
97     string _type = typeof(symbol).stringof;
98     if (prefixAsRename) {
99         _setname = prefixStringAdd;
100     } else {
101         if (_symname.countUntil(prefixStringRem) == 0) {
102             _setname = _symname.replaceFirst(prefixStringRem, prefixStringAdd);
103         }
104         if (prefixStringRem == "") _setname = prefixStringAdd ~ _symname;
105     }
106     return "public final %s %s(%s p_val) @property { return (%s = p_val); }".format(
107         _type, _setname, _type, _symname
108     );
109 }
110 
111 /* -------------------------- String mixin version -------------------------- */
112 
113 /**
114 Generates string for automatic property injection with string mixin.
115 All properties are created as `public final @property`
116 Example:
117 ---
118 // Generates property for "_data" with name "data"
119 mixin(property!_data);
120 // Generates only getter for "_data" with name "data"
121 mixin(getter!_data);
122 // Generates only setter for "_data" with name "data"
123 mixin(setter!_data);
124 
125 // Prefix manipulation, works with getter! and setter! too
126 // _data -> data (removes "_" prefix, default behaviour)
127 mixin(property!_data);
128 // __data -> data (removes supplied prefix)
129 mixin(property!(__data, "__"));
130 // __data -> gdata (replaces supplied prefix)
131 mixin(property!(__data, "__", "g"));
132 // _data -> c_data (adds new prefix)
133 mixin(property!(_data, "", "c"));
134 // _data -> _data (can't match prefix, keeping as is)
135 mixin(property!(_data, "A"));
136 mixin(property!(_data, "A", "B"));
137 // _data -> propertyData (replaces entire name)
138 mixin(property!(_data, "propertyData", true));
139 ---
140 */
141 // static string property(alias symbol, string prefixRem = "_", string prefixAdd = "")() {
142 //     return ___silyPropertyGenGetter!(symbol, prefixRem, prefixAdd, false) ~ "\n" ~
143 //            ___silyPropertyGenSetter!(symbol, prefixRem, prefixAdd, false);
144 // }
145 
146 // /// Ditto
147 // static string setter(alias symbol, string prefixRem = "_", string prefixAdd = "")() {
148 //     return ___silyPropertyGenSetter!(symbol, prefixRem, prefixAdd, false);
149 // }
150 
151 // /// Ditto
152 // static string getter(alias symbol, string prefixRem = "_", string prefixAdd = "")() {
153 //     return ___silyPropertyGenGetter!(symbol, prefixRem, prefixAdd, false);
154 // }
155 
156 // /// Ditto
157 // static string property(alias symbol, string symbolRename, bool B)() if (B == true) {
158 //     return ___silyPropertyGenGetter!(symbol, "", symbolRename, true) ~ "\n" ~
159 //            ___silyPropertyGenSetter!(symbol, "", symbolRename, true);
160 // }
161 
162 // /// Ditto
163 // static string setter(alias symbol, string symbolRename, bool B)() if (B == true) {
164 //     return ___silyPropertyGenSetter!(symbol, "", symbolRename, true);
165 // }
166 
167 // /// Ditto
168 // static string getter(alias symbol, string symbolRename, bool B)() if (B == true) {
169 //     return ___silyPropertyGenGetter!(symbol, "", symbolRename, true);
170 // }