< Summary

Information
Class: MyNet.Globalization.Facade.InflectorExtensions
Assembly: MyNet.Globalization
File(s): https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.Globalization/Facade/Extensions/InflectorExtensions.cs
Tag: 323_28699572109
Line coverage
68%
Covered lines: 26
Uncovered lines: 12
Coverable lines: 38
Total lines: 232
Line coverage: 68.4%
Branch coverage
88%
Covered branches: 30
Total branches: 34
Branch coverage: 88.2%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Inflect(...)100%210%
Inflect(...)100%210%
Inflect(...)0%620%
Pluralize(...)100%1010100%
Singularize(...)92.85%141491.66%
LooksLikeSimpleSuffixPlural(...)87.5%88100%
GetPluralCategory(...)100%210%
IsPlural(...)100%210%
GetPluralCategory(...)100%210%
IsPlural(...)100%210%
GetPluralCategory(...)100%210%
IsPlural(...)100%210%
GetPluralCategory(...)100%210%
IsPlural(...)100%210%

File(s)

https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.Globalization/Facade/Extensions/InflectorExtensions.cs

#LineLine coverage
 1// -----------------------------------------------------------------------
 2// <copyright file="InflectorExtensions.cs" company="Stéphane ANDRE">
 3// Copyright (c) Stéphane ANDRE. All rights reserved.
 4// </copyright>
 5// -----------------------------------------------------------------------
 6
 7using System;
 8using System.Globalization;
 9using MyNet.Globalization.Inflection;
 10
 11#pragma warning disable IDE0130 // Namespace does not match folder structure
 12namespace MyNet.Globalization.Facade;
 13#pragma warning restore IDE0130 // Namespace does not match folder structure
 14
 15/// <summary>
 16/// Extension methods for inflection and text manipulation.
 17/// </summary>
 18public static class InflectorExtensions
 19{
 20    private const StringComparison Comparison = StringComparison.OrdinalIgnoreCase;
 21
 22    extension(string word)
 23    {
 24        /// <summary>
 25        /// Inflects the word based on the provided quantity and culture. Returns the singular or plural form of the wor
 26        /// </summary>
 27        /// <remarks>
 28        /// This overload is a convenience facade that uses <see cref="Localizer"/>.
 29        /// Prefer explicit DI overloads when services are available.
 30        /// </remarks>
 31        /// <param name="quantity">The quantity used to determine the correct form of the word.</param>
 32        /// <param name="culture">The culture used to determine the correct form of the word.</param>
 33        /// <returns>The inflected form of the word.</returns>
 034        public string Inflect(int quantity, CultureInfo? culture = null) => word.Inflect((decimal)quantity, culture);
 35
 36        /// <summary>
 37        /// Inflects the word based on the provided quantity and culture. Returns the singular or plural form of the wor
 38        /// </summary>
 39        /// <remarks>
 40        /// This overload is a convenience facade that uses <see cref="Localizer"/>.
 41        /// Prefer explicit DI overloads when services are available.
 42        /// </remarks>
 43        /// <param name="quantity">The quantity used to determine the correct form of the word.</param>
 44        /// <param name="culture">The culture used to determine the correct form of the word.</param>
 45        /// <returns>The inflected form of the word.</returns>
 046        public string Inflect(double quantity, CultureInfo? culture = null) => word.Inflect((decimal)quantity, culture);
 47
 48        /// <summary>
 49        /// Inflects the word based on the provided quantity and culture. Returns the singular or plural form of the wor
 50        /// </summary>
 51        /// <remarks>
 52        /// This overload is a convenience facade that uses <see cref="Localizer"/>.
 53        /// Prefer explicit DI overloads when services are available.
 54        /// </remarks>
 55        /// <param name="quantity">The quantity used to determine the correct form of the word.</param>
 56        /// <param name="culture">The culture used to determine the correct form of the word.</param>
 57        /// <returns>The inflected form of the word.</returns>
 058        public string Inflect(decimal quantity, CultureInfo? culture = null) => !quantity.IsPlural(culture) ? word.Singu
 59
 60        /// <summary>
 61        /// Pluralizes the provided input considering irregular words and culture-specific rules.
 62        /// </summary>
 63        /// <remarks>
 64        /// This overload is a convenience facade that uses <see cref="Localizer"/>.
 65        /// Prefer explicit DI overloads when services are available.
 66        /// </remarks>
 67        /// <param name="inputIsKnownToBeSingular">
 68        /// When <c>true</c> (default), always pluralizes.
 69        /// When <c>false</c>, returns the word unchanged if it appears to already be in plural form
 70        /// (detected via singularize→re-pluralize round-trip).
 71        /// </param>
 72        /// <param name="culture">Target culture used to resolve the inflector provider.</param>
 73        public string Pluralize(bool inputIsKnownToBeSingular = true, CultureInfo? culture = null)
 74        {
 157575            ArgumentException.ThrowIfNullOrEmpty(word);
 76
 157577            if (!inputIsKnownToBeSingular)
 78            {
 105079                var asPlural = Localizer.Pluralization.Pluralize(word, culture);
 105080                if (asPlural == word)
 52581                    return word;
 82
 52583                var asSingular = Localizer.Pluralization.Singularize(word, culture);
 84
 85                // Keep irregular plurals (people, children, mice, ...) unchanged when plurality is unknown.
 52586                return asSingular != word && Localizer.Pluralization.Pluralize(asSingular, culture) == word && !string.L
 52587                    ? word
 52588                    : asPlural;
 89            }
 90
 52591            return Localizer.Pluralization.Pluralize(word, culture);
 92        }
 93
 94        /// <summary>
 95        /// Singularizes the provided input considering irregular words and culture-specific rules.
 96        /// </summary>
 97        /// <remarks>
 98        /// This overload is a convenience facade that uses <see cref="Localizer"/>.
 99        /// Prefer explicit DI overloads when services are available.
 100        /// </remarks>
 101        /// <param name="inputIsKnownToBePlural">
 102        /// When <c>true</c> (default), always singularizes.
 103        /// When <c>false</c>, returns the word unchanged if it appears to already be in singular form.
 104        /// </param>
 105        /// <param name="skipSimpleWords">
 106        /// When <c>true</c>, words of 3 characters or fewer are returned unchanged to avoid misidentification.
 107        /// </param>
 108        /// <param name="culture">Target culture used to resolve the inflector provider.</param>
 109        public string Singularize(bool inputIsKnownToBePlural = true, bool skipSimpleWords = false, CultureInfo? culture
 110        {
 1584111            ArgumentException.ThrowIfNullOrEmpty(word);
 112
 1584113            if (skipSimpleWords && word.Length <= 3)
 0114                return word;
 115
 1584116            if (!inputIsKnownToBePlural)
 117            {
 1050118                var asSingular = Localizer.Pluralization.Singularize(word, culture);
 119
 1050120                if (asSingular == word)
 534121                    return word;
 122
 516123                var asPlural = Localizer.Pluralization.Pluralize(word, culture);
 124
 125                // Guard against false positives for singular words ending with 's' (bus, status, analysis, ...).
 516126                return asPlural != word && Localizer.Pluralization.Singularize(asPlural, culture) == word && string.Look
 516127                    ? word
 516128                    : asSingular;
 129            }
 130
 534131            return Localizer.Pluralization.Singularize(word, culture);
 132        }
 133
 134        private static bool LooksLikeSimpleSuffixPlural(string input, string singularCandidate)
 423135            => input.Equals(singularCandidate + "s", Comparison)
 423136               || input.Equals(singularCandidate + "es", Comparison)
 423137               || (singularCandidate.Length > 1
 423138                   && singularCandidate.EndsWith('y')
 423139                   && input.Equals(singularCandidate[..^1] + "ies", Comparison));
 140    }
 141
 142    extension(decimal count)
 143    {
 144        /// <summary>
 145        /// Gets the plural category for a decimal quantity using the culture-specific provider.
 146        /// Falls back to a simple invariant rule when no provider is registered.
 147        /// </summary>
 148        /// <remarks>
 149        /// This overload is a convenience facade that uses <see cref="Localizer"/>.
 150        /// Prefer explicit DI overloads when services are available.
 151        /// </remarks>
 0152        public PluralCategory GetPluralCategory(CultureInfo? culture = null) => Localizer.Pluralization.GetPluralCategor
 153
 154        /// <summary>
 155        /// Returns <c>true</c> when <paramref name="count"/> requires the plural form.
 156        /// Zero is treated as plural (e.g. "0 dogs" in English), only 1 is singular.
 157        /// Falls back to <c>count != 1</c> when no inflector is registered.
 158        /// </summary>
 159        /// <remarks>
 160        /// This overload is a convenience facade that uses <see cref="Localizer"/>.
 161        /// Prefer explicit DI overloads when services are available.
 162        /// </remarks>
 0163        public bool IsPlural(CultureInfo? culture = null) => Localizer.Pluralization.IsPlural(count, culture);
 164    }
 165
 166    extension(int count)
 167    {
 168        /// <summary>
 169        /// Gets the plural category for an integer quantity using the culture-specific provider.
 170        /// </summary>
 171        /// <remarks>
 172        /// This overload is a convenience facade that uses <see cref="Localizer"/>.
 173        /// Prefer explicit DI overloads when services are available.
 174        /// </remarks>
 0175        public PluralCategory GetPluralCategory(CultureInfo? culture = null) => ((decimal)count).GetPluralCategory(cultu
 176
 177        /// <summary>
 178        /// Returns <c>true</c> when <paramref name="count"/> requires the plural form.
 179        /// Zero is treated as plural. Falls back to <c>count != 1</c> when no inflector is registered.
 180        /// </summary>
 181        /// <remarks>
 182        /// This overload is a convenience facade that uses <see cref="Localizer"/>.
 183        /// Prefer explicit DI overloads when services are available.
 184        /// </remarks>
 0185        public bool IsPlural(CultureInfo? culture = null) => ((decimal)count).IsPlural(culture);
 186    }
 187
 188    extension(long count)
 189    {
 190        /// <summary>
 191        /// Gets the plural category for a long quantity using the culture-specific provider.
 192        /// </summary>
 193        /// <remarks>
 194        /// This overload is a convenience facade that uses <see cref="Localizer"/>.
 195        /// Prefer explicit DI overloads when services are available.
 196        /// </remarks>
 0197        public PluralCategory GetPluralCategory(CultureInfo? culture = null) => ((decimal)count).GetPluralCategory(cultu
 198
 199        /// <summary>
 200        /// Returns <c>true</c> when <paramref name="count"/> requires the plural form.
 201        /// Zero is treated as plural. Falls back to <c>count != 1</c> when no inflector is registered.
 202        /// </summary>
 203        /// <remarks>
 204        /// This overload is a convenience facade that uses <see cref="Localizer"/>.
 205        /// Prefer explicit DI overloads when services are available.
 206        /// </remarks>
 0207        public bool IsPlural(CultureInfo? culture = null) => ((decimal)count).IsPlural(culture);
 208    }
 209
 210    extension(double count)
 211    {
 212        /// <summary>
 213        /// Gets the plural category for a double quantity using the culture-specific provider.
 214        /// </summary>
 215        /// <remarks>
 216        /// This overload is a convenience facade that uses <see cref="Localizer"/>.
 217        /// Prefer explicit DI overloads when services are available.
 218        /// </remarks>
 0219        public PluralCategory GetPluralCategory(CultureInfo? culture = null) => ((decimal)count).GetPluralCategory(cultu
 220
 221        /// <summary>
 222        /// Returns <c>true</c> when <paramref name="count"/> requires the plural form.
 223        /// Zero is treated as plural. Falls back to <c>count != 1</c> when no inflector is registered.
 224        /// </summary>
 225        /// <remarks>
 226        /// This overload is a convenience facade that uses <see cref="Localizer"/>.
 227        /// Prefer explicit DI overloads when services are available.
 228        /// </remarks>
 0229        public bool IsPlural(CultureInfo? culture = null) => ((decimal)count).IsPlural(culture);
 230    }
 231}
 232