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