Skip to content

Commit f5f5c3e

Browse files
committed
Using name factory for anon type naming / Using an optional Func for configuration instead of TranslationSettings instance / Adding documentation
1 parent e80a701 commit f5f5c3e

File tree

6 files changed

+78
-63
lines changed

6 files changed

+78
-63
lines changed

ReadableExpressions.UnitTests/Extensions/WhenGeneratingVariableNames.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,61 +14,61 @@ public class WhenGeneratingVariableNames
1414
[Fact]
1515
public void ShouldNameAVariableForAnArrayType()
1616
{
17-
typeof(Box[]).GetVariableNameInCamelCase(new TranslationSettings()).ShouldBe("boxArray");
17+
typeof(Box[]).GetVariableNameInCamelCase().ShouldBe("boxArray");
1818
}
1919

2020
[Fact]
2121
public void ShouldNameAVariableForACollectionTypeEndingInX()
2222
{
23-
typeof(ICollection<Box>).GetVariableNameInCamelCase(new TranslationSettings()).ShouldBe("boxes");
23+
typeof(ICollection<Box>).GetVariableNameInCamelCase().ShouldBe("boxes");
2424
}
2525

2626
[Fact]
2727
public void ShouldNameAVariableForAnEnumerableTypeEndingInZ()
2828
{
29-
typeof(IEnumerable<Fuzz>).GetVariableNameInPascalCase(new TranslationSettings()).ShouldBe("Fuzzes");
29+
typeof(IEnumerable<Fuzz>).GetVariableNameInPascalCase().ShouldBe("Fuzzes");
3030
}
3131

3232
[Fact]
3333
public void ShouldNameAVariableForAnEnumerableTypeEndingInDoubleS()
3434
{
35-
typeof(IEnumerable<Glass>).GetVariableNameInPascalCase(new TranslationSettings()).ShouldBe("Glasses");
35+
typeof(IEnumerable<Glass>).GetVariableNameInPascalCase().ShouldBe("Glasses");
3636
}
3737

3838
[Fact]
3939
public void ShouldNameAVariableForAListTypeEndingInCh()
4040
{
41-
typeof(List<Church>).GetVariableNameInCamelCase(new TranslationSettings()).ShouldBe("churches");
41+
typeof(List<Church>).GetVariableNameInCamelCase().ShouldBe("churches");
4242
}
4343

4444
[Fact]
4545
public void ShouldNameAVariableForAListTypeEndingInSh()
4646
{
47-
typeof(List<Hush>).GetVariableNameInCamelCase(new TranslationSettings()).ShouldBe("hushes");
47+
typeof(List<Hush>).GetVariableNameInCamelCase().ShouldBe("hushes");
4848
}
4949

5050
[Fact]
5151
public void ShouldNameAVariableForAListTypeEndingInVowelY()
5252
{
53-
typeof(List<Journey>).GetVariableNameInCamelCase(new TranslationSettings()).ShouldBe("journeys");
53+
typeof(List<Journey>).GetVariableNameInCamelCase().ShouldBe("journeys");
5454
}
5555

5656
[Fact]
5757
public void ShouldNameAVariableForAnIListTypeEndingInConsonantY()
5858
{
59-
typeof(IList<Body>).GetVariableNameInPascalCase(new TranslationSettings()).ShouldBe("Bodies");
59+
typeof(IList<Body>).GetVariableNameInPascalCase().ShouldBe("Bodies");
6060
}
6161

6262
[Fact]
6363
public void ShouldNameANullableLongVariable()
6464
{
65-
typeof(long?).GetVariableNameInCamelCase(new TranslationSettings()).ShouldBe("nullableLong");
65+
typeof(long?).GetVariableNameInCamelCase().ShouldBe("nullableLong");
6666
}
6767

6868
[Fact]
6969
public void ShouldNameAnArrayOfArraysVariable()
7070
{
71-
typeof(int?[][]).GetVariableNameInCamelCase(new TranslationSettings()).ShouldBe("nullableIntArrayArray");
71+
typeof(int?[][]).GetVariableNameInCamelCase().ShouldBe("nullableIntArrayArray");
7272
}
7373

7474
// ReSharper disable ClassNeverInstantiated.Local

ReadableExpressions.UnitTests/Extensions/WhenGettingFriendlyNames.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,18 @@ public void ShouldUseFriendlyNamesForAnonymousTypes()
4141
{
4242
var anon = new { One = 1, Two = "two" };
4343

44-
var friendlyName = anon.GetType().GetFriendlyName(new TranslationSettings());
44+
var friendlyName = anon.GetType().GetFriendlyName();
4545

4646
friendlyName.ShouldBe("AnonymousType<int, string>");
4747
}
4848

49+
// See https://github.com/agileobjects/ReadableExpressions/pull/25
4950
[Fact]
50-
public void ShouldUseObjectForAnonymousTypesIfConfigured()
51+
public void ShouldUseAnonymousTypeNameFactoryIfConfigured()
5152
{
5253
var anon = new { One = 1, Two = "two" };
5354

54-
var friendlyName = anon.GetType().GetFriendlyName(new TranslationSettings().SerializeAnonymousTypesAsObject);
55+
var friendlyName = anon.GetType().GetFriendlyName(c => c.NameAnonymousTypesUsing(t => "object"));
5556

5657
friendlyName.ShouldBe("object");
5758
}

ReadableExpressions.UnitTests/ShouldExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -396,8 +396,8 @@ public static void ShouldBeOfType<TExpected>(this object actual)
396396
if (!(actual is TExpected))
397397
{
398398
Asplode(
399-
"An object of type " + typeof(TExpected).GetFriendlyName(new TranslationSettings()),
400-
actual.GetType().GetFriendlyName(new TranslationSettings()));
399+
"An object of type " + typeof(TExpected).GetFriendlyName(),
400+
actual.GetType().GetFriendlyName());
401401
}
402402
}
403403

ReadableExpressions/Extensions/PublicTypeExtensions.cs

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Collections.Generic;
66
using System.Diagnostics;
77
using NetStandardPolyfills;
8+
using static TranslationContext;
89

910
/// <summary>
1011
/// Provides a set of static extension methods for type information.
@@ -15,9 +16,12 @@ public static class PublicTypeExtensions
1516
/// Returns a friendly, readable version of the name of the given <paramref name="type"/>.
1617
/// </summary>
1718
/// <param name="type">The type for which to retrieve a friendly, readable name.</param>
18-
/// <param name="translationSettings"></param>
19+
/// <param name="configuration">The configuration to use for the variable naming, if required.</param>
1920
/// <returns>A friendly, readable version of the name of the given <paramref name="type"/>.</returns>
20-
public static string GetFriendlyName(this Type type, TranslationSettings translationSettings)
21+
public static string GetFriendlyName(this Type type, Func<TranslationSettings, TranslationSettings> configuration = null)
22+
=> GetFriendlyName(type, GetTranslationSettings(configuration));
23+
24+
internal static string GetFriendlyName(this Type type, TranslationSettings translationSettings)
2125
{
2226
if (type.FullName == null)
2327
{
@@ -52,10 +56,10 @@ public static string GetFriendlyName(this Type type, TranslationSettings transla
5256
return GetGenericTypeName(type, translationSettings);
5357
}
5458

55-
private static string GetGenericTypeName(Type genericType, TranslationSettings translationSettings)
59+
private static string GetGenericTypeName(Type genericType, TranslationSettings settings)
5660
{
5761
var typeGenericTypeArguments = genericType.GetGenericTypeArguments();
58-
var genericTypeName = GetGenericTypeName(genericType.Name, typeGenericTypeArguments.Length, typeGenericTypeArguments, translationSettings);
62+
var genericTypeName = GetGenericTypeName(genericType, typeGenericTypeArguments.Length, typeGenericTypeArguments, settings);
5963

6064
if (!genericType.IsNested)
6165
{
@@ -103,7 +107,7 @@ private static string GetGenericTypeName(Type genericType, TranslationSettings t
103107
typeGenericTypeArguments = typeGenericTypeArgumentsSubset;
104108
}
105109

106-
parentTypeName = GetGenericTypeName(parentTypeName, numberOfParameters, typeArguments, translationSettings);
110+
parentTypeName = GetGenericTypeName(genericType, numberOfParameters, typeArguments, settings);
107111
}
108112

109113
genericTypeName = parentTypeName + "." + genericTypeName;
@@ -112,34 +116,37 @@ private static string GetGenericTypeName(Type genericType, TranslationSettings t
112116
return genericTypeName;
113117
}
114118

115-
private static string GetGenericTypeName(string typeName,
119+
private static string GetGenericTypeName(
120+
Type type,
116121
int numberOfParameters,
117-
IEnumerable<Type> typeArguments, TranslationSettings translationSettings)
122+
IEnumerable<Type> typeArguments,
123+
TranslationSettings settings)
118124
{
125+
var anonTypeIndex = 0;
126+
127+
var isAnonType =
128+
type.Name.StartsWith('<') &&
129+
((anonTypeIndex = type.Name.IndexOf("AnonymousType", StringComparison.Ordinal)) != -1);
130+
131+
if (isAnonType && (settings.AnonymousTypeNameFactory != null))
132+
{
133+
return settings.AnonymousTypeNameFactory.Invoke(type);
134+
}
135+
136+
var typeName = type.Name;
137+
119138
var typeGenericTypeArgumentFriendlyNames =
120-
typeArguments.Project(type => GetFriendlyName(type, translationSettings)).Join(", ");
139+
typeArguments.Project(t => GetFriendlyName(t, settings)).Join(", ");
121140

122141
typeName = typeName.Replace(
123142
"`" + numberOfParameters,
124143
"<" + typeGenericTypeArgumentFriendlyNames + ">");
125144

126-
return typeName.StartsWith('<') ? GetAnonymousTypeName(typeName, translationSettings) : typeName;
145+
return isAnonType ? GetAnonymousTypeName(typeName, anonTypeIndex) : typeName;
127146
}
128147

129-
private static string GetAnonymousTypeName(string typeName, TranslationSettings translationSettings)
148+
private static string GetAnonymousTypeName(string typeName, int anonTypeIndex)
130149
{
131-
var anonTypeIndex = typeName.IndexOf("AnonymousType", StringComparison.Ordinal);
132-
133-
if (anonTypeIndex == -1)
134-
{
135-
return typeName;
136-
}
137-
138-
if (translationSettings.AnonymousTypesAsObject)
139-
{
140-
return "object";
141-
}
142-
143150
typeName = typeName.Substring(anonTypeIndex);
144151

145152
var trimStartIndex = "AnonymousType".Length;
@@ -154,29 +161,37 @@ private static string GetAnonymousTypeName(string typeName, TranslationSettings
154161
/// Retrieves a camel-case variable name for a variable of this <paramref name="type"/>.
155162
/// </summary>
156163
/// <param name="type">The Type for which to retrieve the variable name.</param>
157-
/// <param name="translationSettings"></param>
164+
/// <param name="configuration">The configuration to use for the variable naming, if required.</param>
158165
/// <returns>A camel-case variable name for a variable of this <paramref name="type"/>.</returns>
159-
public static string GetVariableNameInCamelCase(this Type type, TranslationSettings translationSettings) => GetVariableName(type, translationSettings).ToCamelCase();
166+
public static string GetVariableNameInCamelCase(this Type type, Func<TranslationSettings, TranslationSettings> configuration = null)
167+
=> GetVariableNameInCamelCase(type, GetTranslationSettings(configuration));
168+
169+
internal static string GetVariableNameInCamelCase(this Type type, TranslationSettings settings)
170+
=> GetVariableName(type, settings).ToCamelCase();
160171

161172
/// <summary>
162173
/// Retrieves a pascal-case variable name for a variable of this <paramref name="type"/>.
163174
/// </summary>
164175
/// <param name="type">The Type for which to retrieve the variable name.</param>
165-
/// <param name="translationSettings"></param>
176+
/// <param name="configuration">The configuration to use for the variable naming, if required.</param>
166177
/// <returns>A pascal-case variable name for a variable of this <paramref name="type"/>.</returns>
167-
public static string GetVariableNameInPascalCase(this Type type, TranslationSettings translationSettings) => GetVariableName(type, translationSettings).ToPascalCase();
178+
public static string GetVariableNameInPascalCase(this Type type, Func<TranslationSettings, TranslationSettings> configuration = null)
179+
=> GetVariableNameInPascalCase(type, GetTranslationSettings(configuration));
180+
181+
internal static string GetVariableNameInPascalCase(this Type type, TranslationSettings settings)
182+
=> GetVariableName(type, settings).ToPascalCase();
168183

169-
private static string GetVariableName(Type type, TranslationSettings translationSettings)
184+
private static string GetVariableName(Type type, TranslationSettings settings)
170185
{
171186
if (type.IsArray)
172187
{
173-
return GetVariableName(type.GetElementType(), translationSettings) + "Array";
188+
return GetVariableName(type.GetElementType(), settings) + "Array";
174189
}
175190

176191
var typeIsEnumerable = type.IsEnumerable();
177192
var typeIsDictionary = typeIsEnumerable && type.IsDictionary();
178193
var namingType = (typeIsEnumerable && !typeIsDictionary) ? type.GetEnumerableElementType() : type;
179-
var variableName = GetBaseVariableName(namingType, translationSettings);
194+
var variableName = GetBaseVariableName(namingType, settings);
180195

181196
if (namingType.IsInterface())
182197
{
@@ -185,7 +200,7 @@ private static string GetVariableName(Type type, TranslationSettings translation
185200

186201
if (namingType.IsGenericType())
187202
{
188-
variableName = GetGenericTypeVariableName(variableName, namingType, translationSettings);
203+
variableName = GetGenericTypeVariableName(variableName, namingType, settings);
189204
}
190205

191206
variableName = RemoveLeadingNonAlphaNumerics(variableName);
@@ -196,21 +211,23 @@ private static string GetVariableName(Type type, TranslationSettings translation
196211
private static string GetBaseVariableName(Type namingType, TranslationSettings translationSettings)
197212
=> namingType.IsPrimitive() ? namingType.GetFriendlyName(translationSettings) : namingType.Name;
198213

199-
private static string GetGenericTypeVariableName(string variableName, Type namingType,
200-
TranslationSettings translationSettings)
214+
private static string GetGenericTypeVariableName(
215+
string variableName,
216+
Type namingType,
217+
TranslationSettings settings)
201218
{
202219
var nonNullableType = namingType.GetNonNullableType();
203220
var genericTypeArguments = namingType.GetGenericTypeArguments();
204221

205222
if (nonNullableType != namingType)
206223
{
207-
return "nullable" + genericTypeArguments[0].GetVariableNameInPascalCase(translationSettings);
224+
return "nullable" + genericTypeArguments[0].GetVariableNameInPascalCase(settings);
208225
}
209226

210227
variableName = variableName.Substring(0, variableName.IndexOf('`'));
211228

212229
variableName += genericTypeArguments
213-
.Project(arg => "_" + arg.GetVariableNameInPascalCase(translationSettings))
230+
.Project(arg => "_" + arg.GetVariableNameInPascalCase(settings))
214231
.Join(string.Empty);
215232

216233
return variableName;

ReadableExpressions/TranslationContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public static TranslationContext For(
7070
return new TranslationContext(analyzer, globalTranslator, settings);
7171
}
7272

73-
private static TranslationSettings GetTranslationSettings(
73+
internal static TranslationSettings GetTranslationSettings(
7474
Func<TranslationSettings, TranslationSettings> configuration)
7575
{
7676
return configuration?.Invoke(new TranslationSettings()) ?? TranslationSettings.Default;

ReadableExpressions/TranslationSettings.cs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
namespace AgileObjects.ReadableExpressions
22
{
3+
using System;
4+
35
/// <summary>
46
/// Provides configuration options to control aspects of source-code string generation.
57
/// </summary>
68
public class TranslationSettings
79
{
810
internal static readonly TranslationSettings Default = new TranslationSettings();
911

10-
/// <summary>
11-
/// Creates a Translation Settings instance.
12-
/// </summary>
13-
public TranslationSettings()
12+
internal TranslationSettings()
1413
{
1514
UseImplicitGenericParameters = true;
1615
}
@@ -47,18 +46,16 @@ public TranslationSettings ShowQuotedLambdaComments
4746
internal bool CommentQuotedLambdas { get; set; }
4847

4948
/// <summary>
50-
/// Annotate a Quoted Lambda Expression with a comment indicating that it has
51-
/// been Quoted.
49+
/// Name anonymous types using the given <paramref name="nameFactory"/> instead of the
50+
/// default method.
5251
/// </summary>
53-
public TranslationSettings SerializeAnonymousTypesAsObject
52+
/// <param name="nameFactory">The factory method to execute to retrieve the name for an anonymous type.</param>
53+
public TranslationSettings NameAnonymousTypesUsing(Func<Type, string> nameFactory)
5454
{
55-
get
56-
{
57-
AnonymousTypesAsObject = true;
58-
return this;
59-
}
55+
AnonymousTypeNameFactory = nameFactory;
56+
return this;
6057
}
6158

62-
internal bool AnonymousTypesAsObject { get; private set; }
59+
internal Func<Type, string> AnonymousTypeNameFactory { get; private set; }
6360
}
6461
}

0 commit comments

Comments
 (0)