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