1 module simpleconfig.args; 2 3 import simpleconfig.attributes; 4 5 /// See `simpleconfig.readConfiguration` 6 public void readConfiguration (S) (ref S dst) 7 { 8 static assert (is(S == struct), "Only structs are supported as configuration target"); 9 10 import core.runtime; 11 12 readConfigurationImpl(dst, Runtime.args()); 13 } 14 15 private template resolveName (alias Field) 16 { 17 import std.traits; 18 19 enum resolveName = getUDAs!(Field, CLI)[0].full.length 20 ? getUDAs!(Field, CLI)[0] 21 : CLI(__traits(identifier, Field)); 22 } 23 24 unittest 25 { 26 struct S 27 { 28 @cli 29 string field1; 30 @cli("renamed|r") 31 string field2; 32 } 33 34 static assert (resolveName!(S.field1).full == "field1"); 35 static assert (resolveName!(S.field1).single == dchar.init); 36 static assert (resolveName!(S.field2).full == "renamed"); 37 static assert (resolveName!(S.field2).single == 'r'); 38 } 39 40 private void readConfigurationImpl (S) (ref S dst, string[] src) 41 { 42 import std.traits; 43 import std.algorithm; 44 import std.range.primitives; 45 import std.conv; 46 47 rt: foreach (idx, arg; src) 48 { 49 bool assign = false; 50 51 static foreach (Field; getSymbolsByUDA!(S, CLI)) 52 { 53 if (arg.startsWith("--")) 54 assign = resolveName!Field.full == arg[2 .. $]; 55 else if (arg.startsWith("-")) 56 assign = resolveName!Field.single == arg[1 .. $].front; 57 58 if (assign) 59 { 60 auto pfield = &__traits(getMember, dst, __traits(identifier, Field)); 61 *pfield = to!(typeof(*pfield))(src[idx + 1]); 62 continue rt; 63 } 64 } 65 } 66 } 67 68 unittest 69 { 70 struct Config 71 { 72 @cli 73 string field1; 74 @cli("alias") 75 int field2; 76 @cli("long|l") 77 string field3; 78 string field4; 79 } 80 81 Config config; 82 83 readConfigurationImpl(config, [ 84 "--field1", "value1", 85 "--alias", "42", 86 "-l", "value3", 87 "--field4", "ignored" 88 ]); 89 90 assert(config.field1 == "value1"); 91 assert(config.field2 == 42); 92 assert(config.field3 == "value3"); 93 assert(config.field4 == ""); 94 }