1 /**
2     AutoMapper naming convention.
3 
4     You can create your own naming convetion by defining a struct with this shape:
5 
6     ----
7     struct MyConvention
8     {
9         string convert(string identifier)
10         {
11             ...
12         }
13 
14         string convertBack(string myConvention)
15         {
16             ...
17         }
18     }
19     ----
20 */
21 module automapper.naming;
22 
23 import automapper.meta;
24 
25 /**
26     The camel case naming convetion.
27 */
28 struct CamelCaseNamingConvention
29 {
30     /// Convert from foo.bar.baz to fooBarBaz
31     string convert(string flattened)
32     {
33         import std..string : split, join, capitalize;
34         import std.algorithm : map;
35 
36         auto sp = flattened.split(".");
37         return sp[0] ~ sp[1..$].map!capitalize.join();
38     }
39 
40     /// Convert from fooBarBaz to foo.bar.baz
41     string convertBack(string camelCase)
42     {
43         import std..string : join;
44 
45         return camelCase.splitOnCase().join(".");
46     }
47 }
48 
49 ///
50 unittest
51 {
52     static assert(CamelCaseNamingConvention().convert("foo.bar.baz") == "fooBarBaz");
53     static assert(CamelCaseNamingConvention().convertBack("fooBarBaz") == "foo.bar.baz");
54     static assert(CamelCaseNamingConvention().convert("foo") == "foo");
55     static assert(CamelCaseNamingConvention().convertBack("foo") == "foo");
56 }
57 
58 /**
59     The pascal case naming convetion.
60 */
61 struct PascalCaseNamingConvention
62 {
63     /// Convert from foo.bar.baz to fooBarBaz
64     string convert(string flattened)
65     {
66         import std..string : split, join, capitalize;
67         import std.algorithm : map;
68 
69         auto sp = flattened.split(".");
70         return sp.map!capitalize.join();
71     }
72 
73     /// Convert from fooBarBaz to foo.bar.baz
74     string convertBack(string pascalCase)
75     {
76         import std..string : join;
77         import std..string : toLower;
78 
79         return pascalCase.splitOnCase().join(".").toLower();
80     }
81 }
82 
83 ///
84 unittest
85 {
86     static assert(PascalCaseNamingConvention().convert("foo.bar.baz") == "FooBarBaz");
87     static assert(PascalCaseNamingConvention().convertBack("FooBarBaz") == "foo.bar.baz");
88     static assert(PascalCaseNamingConvention().convert("foo") == "Foo");
89     static assert(PascalCaseNamingConvention().convertBack("Foo") == "foo");
90 }
91 
92 /**
93     The lower undescore naming convetion.
94 */
95 struct LowerUnderscoreNamingConvention
96 {
97     /// Convert from foo.bar.baz to fooBarBaz
98     string convert(string flattened)
99     {
100         import std..string : split, join, capitalize;
101         import std.algorithm : map;
102 
103         return flattened.split(".").join("_");
104     }
105 
106     /// Convert from fooBarBaz to foo.bar.baz
107     string convertBack(string lowerUnder)
108     {
109         import std..string : split, join;
110 
111         return lowerUnder.split("_").join(".");
112     }
113 }
114 
115 ///
116 unittest
117 {
118     static assert(LowerUnderscoreNamingConvention().convert("foo.bar.baz") == "foo_bar_baz");
119     static assert(LowerUnderscoreNamingConvention().convertBack("foo_bar_baz") == "foo.bar.baz");
120     static assert(LowerUnderscoreNamingConvention().convert("foo") == "foo");
121     static assert(LowerUnderscoreNamingConvention().convertBack("foo") == "foo");
122 }
123 
124 ///
125 template isNamingConvention(T)
126 {
127     enum isNamingConvention = (
128         hasSpecifiedCallable!(T, "convert", string, string) &&
129         hasSpecifiedCallable!(T, "convertBack", string, string));
130 }
131 
132 ///
133 unittest
134 {
135     static assert(isNamingConvention!CamelCaseNamingConvention);
136 }