1 module nxt.casing;
2 
3 import std.traits : isSomeString;
4 
5 version(unittest)
6 {
7     import std.algorithm : equal;
8 }
9 
10 /** Convert string $(S s) to lower-case.
11  *
12  * String must contain ASCII characters only.
13  */
14 auto toLowerASCII(S)(S s)
15 if (isSomeString!S)
16 {
17     import std.algorithm.iteration : map;
18     import std.ascii : toLower;
19     import std.traits : isNarrowString;
20     static if (isNarrowString!S)
21     {
22         import std.utf : byUTF;
23         return s.byUTF!dchar.map!(ch => ch.toLower);
24     }
25     else
26         return t.map!(ch => ch.toLower);
27 }
28 
29 ///
30 @safe pure /*TODO: nothrow @nogc*/ unittest
31 {
32     assert("Lasse".toLowerASCII.equal("lasse"));
33     assert("Åberg".toLowerASCII.equal("Åberg")); // ignores unicode letters
34 }
35 
36 /** Convert string $(S s) to lower-case.
37  *
38  * String may contain Unicode characters.
39  */
40 auto toLowerUnicode(S)(S s)
41 if (isSomeString!S)
42 {
43     import std.algorithm.iteration : map;
44     import std.uni : toLower;
45     import std.traits : isNarrowString;
46     // TODO: functionize
47     static if (isNarrowString!S)
48 	{
49 		import std.utf : byUTF;
50         return s.byUTF!dchar.map!(ch => ch.toLower);
51 	}
52     else
53         return t.map!(ch => ch.toLower);
54 }
55 
56 ///
57 @safe pure /*TODO: nothrow @nogc*/ unittest
58 {
59     assert("Lasse".toLowerUnicode.equal("lasse"));
60     assert("Åberg".toLowerUnicode.equal("åberg"));
61 }
62 
63 /** Convert D-style camel-cased string $(S s) to lower-cased words.
64  */
65 auto camelCasedToLower(S)(S s)
66 if (isSomeString!S)
67 {
68     import std.algorithm.iteration : map;
69     import std.ascii : isUpper; // D symbol names can only be in ASCII
70     // TODO: Instead of this add std.ascii.as[Lower|Upper]Case and import std.ascii.asLowerCase
71     import std.uni : asLowerCase;
72     import nxt.slicing : preSlicer;
73     return s.preSlicer!isUpper.map!asLowerCase;
74 }
75 
76 ///
77 @safe pure unittest
78 {
79     auto x = "doThis".camelCasedToLower;
80     assert(x.front.equal("do"));
81     x.popFront();
82     assert(x.front.equal("this"));
83 }
84 
85 /** Convert D-Style camel-cased string $(S s) to space-separated lower-cased words.
86  */
87 auto camelCasedToLowerSpaced(S, Separator)(S s, const Separator separator = " ")
88 if (isSomeString!S)
89 {
90     import std.algorithm.iteration : joiner;
91     return camelCasedToLower(s).joiner(separator);
92 }
93 
94 ///
95 @safe pure unittest
96 {
97     assert(equal("doThis".camelCasedToLowerSpaced,
98                  "do this"));
99 }
100 
101 /** Convert enumeration value (enumerator) $(D t) to a range chars.
102  */
103 auto toLowerSpacedChars(T, Separator)(const T t,
104                                       const Separator separator = " ")
105 if (is(T == enum))
106 {
107     import nxt.enum_ex : toStringFaster;
108     return t.toStringFaster
109             .camelCasedToLowerSpaced(separator);
110 }
111 
112 ///
113 @safe pure unittest
114 {
115     enum Things { isUri, isLink }
116     assert(Things.isUri.toLowerSpacedChars.equal("is uri"));
117     assert(Things.isLink.toLowerSpacedChars.equal("is link"));
118 }
119 
120 ///
121 @safe pure unittest
122 {
123     enum Things { isURI, isLink }
124     auto r = Things.isURI.toLowerSpacedChars;
125     alias R = typeof(r);
126     import std.range.primitives : ElementType;
127     alias E = ElementType!R;
128     static assert(is(E == dchar));
129 }