< Summary

Information
Class: MyNet.Humanizer.Facade.SmartEnumExtensions
Assembly: MyNet.Humanizer
File(s): https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.Humanizer/Facade/Extensions/SmartEnumExtensions.cs
Tag: 323_28699572109
Line coverage
100%
Covered lines: 26
Uncovered lines: 0
Coverable lines: 26
Total lines: 167
Line coverage: 100%
Branch coverage
83%
Covered branches: 10
Total branches: 12
Branch coverage: 83.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
Humanize(...)100%11100%
Humanize(...)100%11100%
DehumanizeTo(...)100%11100%
DehumanizeTo(...)100%11100%
TryDehumanizeTo(...)100%11100%
DehumanizeCore(...)100%66100%
GetLookup(...)50%22100%
CreateLookup(...)75%44100%

File(s)

https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.Humanizer/Facade/Extensions/SmartEnumExtensions.cs

#LineLine coverage
 1// -----------------------------------------------------------------------
 2// <copyright file="SmartEnumExtensions.cs" company="Stéphane ANDRE">
 3// Copyright (c) Stéphane ANDRE. All rights reserved.
 4// </copyright>
 5// -----------------------------------------------------------------------
 6
 7using System;
 8using System.Collections.Concurrent;
 9using System.Collections.Frozen;
 10using System.Collections.Generic;
 11using System.Globalization;
 12using MyNet.Humanizer.Display;
 13using MyNet.Primitives;
 14
 15#pragma warning disable IDE0130 // Namespace does not match folder structure
 16namespace MyNet.Humanizer.Facade;
 17#pragma warning restore IDE0130 // Namespace does not match folder structure
 18
 19/// <summary>
 20/// Contains extension methods for humanizing Enums.
 21/// </summary>
 22public static class SmartEnumExtensions
 23{
 324    private static readonly ConcurrentDictionary<CacheKey, FrozenDictionary<string, ISmartEnum>> Cache = new();
 25
 26    extension(ISmartEnum value)
 27    {
 28        /// <summary>
 29        /// Returns the humanized display name of the SmartEnum value using the default options. If no display name is f
 30        /// </summary>
 31        /// <param name="culture">The culture to use when retrieving the display name.</param>
 32        /// <returns>The humanized display name of the SmartEnum value.</returns>
 1133        public string Humanize(CultureInfo? culture = null) => value.Humanize(DisplayTextOptions.Default, culture);
 34
 35        /// <summary>
 36        /// Returns the humanized display name of the SmartEnum value using the specified options. If no display name is
 37        /// Uses the DI-registered <see cref="IDisplayTextStrategy{T}"/>.
 38        /// </summary>
 39        /// <param name="options">The options to use when retrieving the display name.</param>
 40        /// <param name="culture">The culture to use when retrieving the display name.</param>
 41        /// <returns>The humanized display name of the SmartEnum value.</returns>
 1442        public string Humanize(DisplayTextOptions options, CultureInfo? culture = null) => TextHumanizer.Humanize(value,
 43    }
 44
 45    extension(string? input)
 46    {
 47        /// <summary>
 48        /// Dehumanizes the input string to the specified target enum type. The method first checks if the target enum t
 49        /// </summary>
 50        /// <param name="culture">The culture to use for humanization.</param>
 51        /// <typeparam name="TSmartEnum">The type of the target enum.</typeparam>
 52        /// <returns>The corresponding enum member.</returns>
 53        /// <exception cref="ArgumentNullException">Thrown if the targetEnum is null.</exception>
 54        /// <exception cref="ArgumentException">Thrown if the targetEnum does not implement ISmartEnum.</exception>
 55        /// <exception cref="KeyNotFoundException">Thrown if no matching enum member is found.</exception>
 56        public TSmartEnum DehumanizeTo<TSmartEnum>(CultureInfo? culture = null)
 57            where TSmartEnum : class, ISmartEnum
 1558            => (TSmartEnum)DehumanizeCore(input, typeof(TSmartEnum), culture);
 59
 60        /// <summary>
 61        /// Dehumanizes the input string to the specified target enum type. The method first checks if the target enum t
 62        /// </summary>
 63        /// <param name="targetEnum">The target enum type.</param>
 64        /// <param name="culture">The culture to use for humanization.</param>
 65        /// <returns>The corresponding enum member.</returns>
 66        /// <exception cref="ArgumentNullException">Thrown if the targetEnum is null.</exception>
 67        /// <exception cref="ArgumentException">Thrown if the targetEnum does not implement ISmartEnum.</exception>
 68        /// <exception cref="KeyNotFoundException">Thrown if no matching enum member is found.</exception>
 969        public ISmartEnum DehumanizeTo(Type targetEnum, CultureInfo? culture = null) => (ISmartEnum)DehumanizeCore(input
 70
 71        /// <summary>
 72        /// Tries to dehumanize the input string to the specified target enum type. The method first checks if the targe
 73        /// </summary>
 74        /// <param name="result">The resulting enum member if a match is found; otherwise, null.</param>
 75        /// <param name="culture">The culture to use for humanization.</param>
 76        /// <typeparam name="TSmartEnum">The type of the target enum.</typeparam>
 77        /// <returns>True if a match is found; otherwise, false.</returns>
 78        public bool TryDehumanizeTo<TSmartEnum>(out TSmartEnum? result, CultureInfo? culture = null)
 79            where TSmartEnum : class, ISmartEnum
 80        {
 81            try
 82            {
 683                result = input.DehumanizeTo<TSmartEnum>(culture);
 384                return true;
 85            }
 386            catch (Exception)
 87            {
 388                result = null;
 389                return false;
 90            }
 91        }
 92    }
 93
 94    /// <summary>
 95    /// Dehumanizes the input string to the specified target enum type. The method first checks if the target enum type 
 96    /// </summary>
 97    /// <param name="input">The input string to dehumanize.</param>
 98    /// <param name="targetEnum">The target enum type.</param>
 99    /// <param name="culture">The culture to use for humanization.</param>
 100    /// <returns>The corresponding enum member.</returns>
 101    /// <exception cref="ArgumentNullException">Thrown if the targetEnum is null.</exception>
 102    /// <exception cref="ArgumentException">Thrown if the targetEnum does not implement ISmartEnum.</exception>
 103    /// <exception cref="KeyNotFoundException">Thrown if no matching enum member is found.</exception>
 104    private static object DehumanizeCore(string? input, Type targetEnum, CultureInfo? culture)
 105    {
 24106        ArgumentNullException.ThrowIfNull(targetEnum);
 107
 21108        if (!typeof(ISmartEnum).IsAssignableFrom(targetEnum))
 109        {
 3110            throw new ArgumentException($"Type '{targetEnum}' does not implement ISmartEnum.", nameof(targetEnum));
 111        }
 112
 18113        if (string.IsNullOrWhiteSpace(input))
 114        {
 3115            throw new KeyNotFoundException($"Input string is null or whitespace, cannot dehumanize to enum type '{target
 116        }
 117
 15118        var lookup = GetLookup(targetEnum, culture);
 119
 15120        return lookup.TryGetValue(input, out var result) ? result : throw new KeyNotFoundException($"Couldn't find any e
 121    }
 122
 123    /// <summary>
 124    /// Retrieves a lookup dictionary for the specified target enum type and culture from the cache. If the lookup does 
 125    /// </summary>
 126    /// <param name="targetEnum">The target enum type.</param>
 127    /// <param name="culture">The culture to use for humanization.</param>
 128    /// <returns>A frozen dictionary mapping strings to enum members.</returns>
 129    private static FrozenDictionary<string, ISmartEnum> GetLookup(Type targetEnum, CultureInfo? culture)
 130    {
 15131        var key = new CacheKey(targetEnum, culture?.Name);
 132
 15133        return Cache.GetOrAdd(key, static key => CreateLookup(key.Type, key.Culture));
 134    }
 135
 136    /// <summary>
 137    /// Creates a lookup dictionary for the specified target enum type and culture. The dictionary maps both the enum me
 138    /// </summary>
 139    /// <param name="targetEnum">The target enum type.</param>
 140    /// <param name="cultureName">The name of the culture to use for humanization.</param>
 141    /// <returns>A frozen dictionary mapping strings to enum members.</returns>
 142    private static FrozenDictionary<string, ISmartEnum> CreateLookup(Type targetEnum, string? cultureName)
 143    {
 3144        var culture = cultureName is null ? null : CultureInfo.GetCultureInfo(cultureName);
 145
 3146        var dictionary = new Dictionary<string, ISmartEnum>(StringComparer.OrdinalIgnoreCase);
 147
 18148        foreach (var value in SmartEnumSource.GetAll(targetEnum))
 149        {
 6150            dictionary.TryAdd(value.ToString()!, value);
 151
 6152            var humanized = value.Humanize(culture: culture);
 153
 6154            dictionary.TryAdd(humanized, value);
 155        }
 156
 3157        return dictionary.ToFrozenDictionary(StringComparer.OrdinalIgnoreCase);
 158    }
 159
 160    /// <summary>
 161    /// A struct used as a key for caching the lookup dictionaries for dehumanization. It combines the target enum type 
 162    /// </summary>
 163    /// <param name="Type">The target enum type.</param>
 164    /// <param name="Culture">The culture name.</param>
 165    private readonly record struct CacheKey(Type Type, string? Culture);
 166}
 167