diff --git a/src/Rhythm.Core/CollectionExtensionMethods.cs b/src/Rhythm.Core/CollectionExtensionMethods.cs index 36ad0fc..8e3b7b9 100644 --- a/src/Rhythm.Core/CollectionExtensionMethods.cs +++ b/src/Rhythm.Core/CollectionExtensionMethods.cs @@ -1,155 +1,149 @@ -namespace Rhythm.Core +namespace Rhythm.Core; + +using System; +using System.Collections.Generic; +using System.Linq; + +/// +/// Extension methods for collections. +/// +public static class CollectionExtensionMethods { - // The namespaces. - using System; - using System.Collections.Generic; - using System.Linq; + #region Properties /// - /// Extension methods for collections. + /// Used to generate random numbers. /// - public static class CollectionExtensionMethods - { + private static Random Rnd { get; set; } - #region Properties + #endregion - /// - /// Used to generate random numbers. - /// - private static Random Rnd { get; set; } + #region Constructors - #endregion + /// + /// Static constructor. + /// + static CollectionExtensionMethods() + { + Rnd = new Random(); + } - #region Constructors + #endregion - /// - /// Static constructor. - /// - static CollectionExtensionMethods() - { - Rnd = new Random(); - } + #region Extension Methods - #endregion - - #region Extension Methods - - /// - /// Converts a null collection into an empty collection. - /// - /// - /// The type of item stored by the collection. - /// - /// - /// The collection of items. - /// - /// - /// An empty list, if the supplied collection is null; otherwise, the supplied collection. - /// - public static IEnumerable MakeSafe(this IEnumerable items) - { - return items == null - ? Enumerable.Empty() - : items; - } + /// + /// Converts a null collection into an empty collection. + /// + /// + /// The type of item stored by the collection. + /// + /// + /// The collection of items. + /// + /// + /// An empty list, if the supplied collection is null; otherwise, the supplied collection. + /// + public static IEnumerable MakeSafe(this IEnumerable items) + { + return items ?? Enumerable.Empty(); + } - /// - /// Returns the collection of items without any nulls. - /// - /// - /// The type of item stored by the collection. - /// - /// - /// The collection of items. - /// - /// - /// The collection without null items. - /// - public static IEnumerable WithoutNulls(this IEnumerable items) - { - return items.Where(x => x != null); - } + /// + /// Returns the collection of items without any nulls. + /// + /// + /// The type of item stored by the collection. + /// + /// + /// The collection of items. + /// + /// + /// The collection without null items. + /// + public static IEnumerable WithoutNulls(this IEnumerable items) + { + return items.Where(x => x != null); + } - /// - /// Generates a sequence that conains the specified value the specified number of times. - /// - /// - /// The type of the value to be repeated in the result sequence. - /// - /// - /// The value to be repeated. - /// - /// - /// The number of times to repeat the value in the generated sequence. - /// - /// - /// A collection containing the specified element the specified number of times. - /// - public static IEnumerable Repeat(this T element, int count) - { - return Enumerable.Repeat(element, count); - } + /// + /// Generates a sequence that conains the specified value the specified number of times. + /// + /// + /// The type of the value to be repeated in the result sequence. + /// + /// + /// The value to be repeated. + /// + /// + /// The number of times to repeat the value in the generated sequence. + /// + /// + /// A collection containing the specified element the specified number of times. + /// + public static IEnumerable Repeat(this T element, int count) + { + return Enumerable.Repeat(element, count); + } - /// - /// Returns the specified collection of items in random order. - /// - /// - /// The type of item stored by the collection. - /// - /// - /// The collection of items. - /// - /// - /// The collection, in random order. - /// - public static IEnumerable RandomOrder(this IEnumerable items) + /// + /// Returns the specified collection of items in random order. + /// + /// + /// The type of item stored by the collection. + /// + /// + /// The collection of items. + /// + /// + /// The collection, in random order. + /// + public static IEnumerable RandomOrder(this IEnumerable items) + { + var itemsList = items.MakeSafe().ToList(); + var randomized = new List(); + var count = itemsList.Count; + for(var i = 0; i < count; i++) { - var itemsList = items.MakeSafe().ToList(); - var randomized = new List(); - var count = itemsList.Count; - for(var i = 0; i < count; i++) - { - var index = Rnd.Next(itemsList.Count); - var item = itemsList[index]; - randomized.Add(item); - itemsList[index] = itemsList.Last(); - itemsList.RemoveAt(itemsList.Count - 1); - } - return randomized; + var index = Rnd.Next(itemsList.Count); + var item = itemsList[index]; + randomized.Add(item); + itemsList[index] = itemsList.Last(); + itemsList.RemoveAt(itemsList.Count - 1); } + return randomized; + } - /// - /// Returns a list for the specified collection. Attempts to return the - /// underlying collection if it is already a list; otherwise, it converts - /// the collection to a list. - /// - /// - /// The type of item stored by the collection. - /// - /// - /// The collection of items. - /// - /// - /// An empty list, if the supplied collection is null; otherwise, the - /// supplied collection as a list. - /// - /// - /// This will never return a null (i.e., it will return an empty list - /// rather than a null). - /// - public static List AsList(this IEnumerable items) + /// + /// Returns a list for the specified collection. Attempts to return the + /// underlying collection if it is already a list; otherwise, it converts + /// the collection to a list. + /// + /// + /// The type of item stored by the collection. + /// + /// + /// The collection of items. + /// + /// + /// An empty list, if the supplied collection is null; otherwise, the + /// supplied collection as a list. + /// + /// + /// This will never return a null (i.e., it will return an empty list + /// rather than a null). + /// + public static List AsList(this IEnumerable items) + { + var list = items as List; + if (list == null) { - var list = items as List; - if (list == null) - { - list = items.MakeSafe().ToList(); - } - return list; + list = items.MakeSafe().ToList(); } - - #endregion - + return list; } -} \ No newline at end of file + #endregion + +} diff --git a/src/Rhythm.Core/Enums/StringSplitDelimiters.cs b/src/Rhythm.Core/Enums/StringSplitDelimiters.cs index 64cef8f..c954ac3 100644 --- a/src/Rhythm.Core/Enums/StringSplitDelimiters.cs +++ b/src/Rhythm.Core/Enums/StringSplitDelimiters.cs @@ -1,51 +1,48 @@ -namespace Rhythm.Core.Enums +namespace Rhythm.Core.Enums; + +/// +/// The types of delimiters that can be used to split strings. +/// +public enum StringSplitDelimiters { /// - /// The types of delimiters that can be used to split strings. + /// Default will split by common delimiters (e.g., commas, line breaks, semicolons). /// - public enum StringSplitDelimiters - { - - /// - /// Default will split by common delimiters (e.g., commas, line breaks, semicolons). - /// - Default, - - /// - /// Split by line breaks. - /// - LineBreak, + Default, - /// - /// Split by commas. - /// - Comma, + /// + /// Split by line breaks. + /// + LineBreak, - /// - /// Split by semicolon. - /// - Semicolon, + /// + /// Split by commas. + /// + Comma, - /// - /// Split by tabs. - /// - Tab, + /// + /// Split by semicolon. + /// + Semicolon, - /// - /// Split by equals signs. - /// - Equals, + /// + /// Split by tabs. + /// + Tab, - /// - /// Split by \. - /// - BackSlash, + /// + /// Split by equals signs. + /// + Equals, - /// - /// Split by /. - /// - ForwardSlash, - } + /// + /// Split by \. + /// + BackSlash, -} \ No newline at end of file + /// + /// Split by /. + /// + ForwardSlash, +} diff --git a/src/Rhythm.Core/StringExtensionMethods.cs b/src/Rhythm.Core/StringExtensionMethods.cs index 9aa94a6..c03226c 100644 --- a/src/Rhythm.Core/StringExtensionMethods.cs +++ b/src/Rhythm.Core/StringExtensionMethods.cs @@ -1,277 +1,273 @@ -namespace Rhythm.Core +namespace Rhythm.Core; + +using Enums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; + +/// +/// Extension methods for strings. +/// +public static class StringExtensionMethods { - // Namespaces. - using Enums; - using System.Collections.Generic; - using System.Linq; - using System.Text.RegularExpressions; + #region Constants - /// - /// Extension methods for strings. - /// - public static class StringExtensionMethods - { + private const string SnakeCaseReplace = @"-${EDGE}"; + private const string CssReplace = @"-"; - #region Constants + #endregion - private const string SnakeCaseReplace = @"-${EDGE}"; - private const string CssReplace = @"-"; + #region Properties - #endregion + /// + /// This regular expression matches the substrings that should have a dash inserted. + /// before them. + /// + private static Regex SlugInsertionPointRegex { get; set; } - #region Properties + /// + /// This regular expression matches the a hyphen followed by any character. + /// before them. + /// + private static Regex DashAndCharRegex { get; set; } - /// - /// This regular expression matches the substrings that should have a dash inserted. - /// before them. - /// - private static Regex SlugInsertionPointRegex { get; set; } + /// + /// This regular expression matches a line (i.e., everything except for line breaks). + /// + private static Regex LineRegex { get; set; } - /// - /// This regular expression matches the a hyphen followed by any character. - /// before them. - /// - private static Regex DashAndCharRegex { get; set; } + /// + /// This regular expression matches the invalid CSS characters. + /// + private static Regex InvalidCssChars { get; set; } - /// - /// This regular expression matches a line (i.e., everything except for line breaks). - /// - private static Regex LineRegex { get; set; } + #endregion - /// - /// This regular expression matches the invalid CSS characters. - /// - private static Regex InvalidCssChars { get; set; } + #region Constructors - #endregion + /// + /// Static constructor. + /// + static StringExtensionMethods() + { + var options = RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase; + var options2 = RegexOptions.Compiled | RegexOptions.Singleline; + LineRegex = new Regex(@"((?!\r|\n).)+", options); + SlugInsertionPointRegex = new Regex(@"(?(?.)", options); + InvalidCssChars = new Regex(@"((?![a-z0-9]).)+", options); + } - #region Constructors + #endregion - /// - /// Static constructor. - /// - static StringExtensionMethods() - { - var options = RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase; - var options2 = RegexOptions.Compiled | RegexOptions.Singleline; - LineRegex = new Regex(@"((?!\r|\n).)+", options); - SlugInsertionPointRegex = new Regex(@"(?(?.)", options); - InvalidCssChars = new Regex(@"((?![a-z0-9]).)+", options); - } + #region Extension Methods - #endregion - - #region Extension Methods + /// + /// Splits a string by the specified delimiter. + /// + /// + /// The string to split. + /// + /// + /// Optional. The delimiter. If unspecified, default delimiters will be used. + /// + /// + /// The split strings. + /// + public static IEnumerable SplitBy(this string source, + StringSplitDelimiters delimiter = StringSplitDelimiters.Default) + { - /// - /// Splits a string by the specified delimiter. - /// - /// - /// The string to split. - /// - /// - /// Optional. The delimiter. If unspecified, default delimiters will be used. - /// - /// - /// The split strings. - /// - public static IEnumerable SplitBy(this string source, - StringSplitDelimiters delimiter = StringSplitDelimiters.Default) + // If the source string is null, return an empty collection. + if (source == null) { - - // If the source string is null, return an empty collection. - if (source == null) - { - return Enumerable.Empty(); - } - - // Split by delimiter type. - switch (delimiter) - { - case StringSplitDelimiters.Default: - var lines = SplitByChars(source, ',', ';') - .SelectMany(x => SplitByLineBreaks(x)); - return CleanItems(lines); - case StringSplitDelimiters.Comma: - return CleanItems(SplitByChars(source, ',')); - case StringSplitDelimiters.LineBreak: - return CleanItems(SplitByLineBreaks(source)); - case StringSplitDelimiters.Semicolon: - return CleanItems(SplitByChars(source, ';')); - case StringSplitDelimiters.Tab: - return CleanItems(SplitByChars(source, '\t')); - case StringSplitDelimiters.Equals: - return CleanItems(SplitByChars(source, '=')); - case StringSplitDelimiters.BackSlash: - return CleanItems(SplitByChars(source, '\\')); - case StringSplitDelimiters.ForwardSlash: - return CleanItems(SplitByChars(source, '/')); - default: - return new[] { source }; - } - + return Enumerable.Empty(); } - /// - /// Converts a camel case string to snake case (e.g., converts "thisThing" to "this-thing"). - /// - /// - /// The camel case string to convert. - /// - /// - /// The snake case string. - /// - public static string ToSnakeCase(this string source) + // Split by delimiter type. + switch (delimiter) { - if (string.IsNullOrWhiteSpace(source)) - { - return null; - } - return SlugInsertionPointRegex.Replace(source, SnakeCaseReplace).ToLower(); + case StringSplitDelimiters.Default: + var lines = SplitByChars(source, ',', ';') + .SelectMany(x => SplitByLineBreaks(x)); + return CleanItems(lines); + case StringSplitDelimiters.Comma: + return CleanItems(SplitByChars(source, ',')); + case StringSplitDelimiters.LineBreak: + return CleanItems(SplitByLineBreaks(source)); + case StringSplitDelimiters.Semicolon: + return CleanItems(SplitByChars(source, ';')); + case StringSplitDelimiters.Tab: + return CleanItems(SplitByChars(source, '\t')); + case StringSplitDelimiters.Equals: + return CleanItems(SplitByChars(source, '=')); + case StringSplitDelimiters.BackSlash: + return CleanItems(SplitByChars(source, '\\')); + case StringSplitDelimiters.ForwardSlash: + return CleanItems(SplitByChars(source, '/')); + default: + return new[] { source }; } - /// - /// Converts a snake case string to camel case (e.g., converts "this-thing" to "thisThing"). - /// - /// - /// The snake case string to convert. - /// - /// - /// The camel case string. - /// - public static string ToCamelCase(this string source) + } + + /// + /// Converts a camel case string to snake case (e.g., converts "thisThing" to "this-thing"). + /// + /// + /// The camel case string to convert. + /// + /// + /// The snake case string. + /// + public static string ToSnakeCase(this string source) + { + if (string.IsNullOrWhiteSpace(source)) { - if (string.IsNullOrWhiteSpace(source)) - { - return null; - } - return DashAndCharRegex.Replace(source, x => - { - return x.Groups["CHAR"].Value.ToUpper(); - }); + return null; } + return SlugInsertionPointRegex.Replace(source, SnakeCaseReplace).ToLower(); + } - /// - /// Converts a snake case string to pascal case (e.g., converts "this-thing" to "ThisThing"). - /// - /// - /// The snake case string to convert. - /// - /// - /// The pascal case string. - /// - public static string ToPascalCase(this string source) + /// + /// Converts a snake case string to camel case (e.g., converts "this-thing" to "thisThing"). + /// + /// + /// The snake case string to convert. + /// + /// + /// The camel case string. + /// + public static string ToCamelCase(this string source) + { + if (string.IsNullOrWhiteSpace(source)) { - if (string.IsNullOrWhiteSpace(source)) - { - return null; - } - var camelCase = ToCamelCase(source); - return camelCase.Substring(0, 1).ToUpper() + camelCase.Substring(1); + return null; } + return DashAndCharRegex.Replace(source, x => + { + return x.Groups["CHAR"].Value.ToUpper(); + }); + } - /// - /// Sanitizes a string for use as a CSS class (e.g., converts - /// "some randomText" to "some-random-text"). - /// - /// - /// The string to sanitize. - /// - /// - /// The string that can be used as a CSS class. - /// - public static string SanitizeForCss(this string source) + /// + /// Converts a snake case string to pascal case (e.g., converts "this-thing" to "ThisThing"). + /// + /// + /// The snake case string to convert. + /// + /// + /// The pascal case string. + /// + public static string ToPascalCase(this string source) + { + if (string.IsNullOrWhiteSpace(source)) { - if (string.IsNullOrWhiteSpace(source)) - { - return null; - } - return InvalidCssChars - .Replace(source, CssReplace) - .ToSnakeCase() - .Trim(CssReplace.ToCharArray()); + return null; } + var camelCase = ToCamelCase(source); + return string.Concat(camelCase[..1].ToUpper(), camelCase.AsSpan(1)); + } - /// - /// Returns either the supplied string or null (in the case that the string is empty - /// or whitespace). - /// - /// - /// The string to return. - /// - /// - /// The specified string, or null. - /// - /// - /// Useful when you want to use the null-coalescing operator and you want to treat an - /// empty or whitespace string as if it were null. - /// - public static string PreferNull(this string source) + /// + /// Sanitizes a string for use as a CSS class (e.g., converts + /// "some randomText" to "some-random-text"). + /// + /// + /// The string to sanitize. + /// + /// + /// The string that can be used as a CSS class. + /// + public static string SanitizeForCss(this string source) + { + if (string.IsNullOrWhiteSpace(source)) { - return string.IsNullOrWhiteSpace(source) - ? null - : source; + return null; } + return InvalidCssChars + .Replace(source, CssReplace) + .ToSnakeCase() + .Trim(CssReplace.ToCharArray()); + } - #endregion - - #region Private Methods + /// + /// Returns either the supplied string or null (in the case that the string is empty + /// or whitespace). + /// + /// + /// The string to return. + /// + /// + /// The specified string, or null. + /// + /// + /// Useful when you want to use the null-coalescing operator and you want to treat an + /// empty or whitespace string as if it were null. + /// + public static string PreferNull(this string source) + { + return string.IsNullOrWhiteSpace(source) + ? null + : source; + } - /// - /// Split a string by line breaks. - /// - /// - /// The string to split. - /// - /// - /// The split strings. - /// - private static IEnumerable SplitByLineBreaks(string source) - { - return LineRegex - .Matches(source) - .Cast() - .Select(x => x.Value); - } + #endregion - /// - /// Split a string by the specified characters. - /// - /// - /// The string to split. - /// - /// - /// The characters to split by. - /// - /// - /// The split strings. - /// - private static IEnumerable SplitByChars(string source, params char[] characters) - { - return source.Split(characters); - } + #region Private Methods - /// - /// Cleans the collection of strings, trimming whitespace and removing empties. - /// - /// - /// The items to clean. - /// - /// - /// The cleaned strings. - /// - private static IEnumerable CleanItems(IEnumerable items) - { - return items - .MakeSafe() - .Select(x => x.Trim()) - .Where(x => !string.IsNullOrWhiteSpace(x)); - } + /// + /// Split a string by line breaks. + /// + /// + /// The string to split. + /// + /// + /// The split strings. + /// + private static IEnumerable SplitByLineBreaks(string source) + { + return LineRegex + .Matches(source) + .Cast() + .Select(x => x.Value); + } - #endregion + /// + /// Split a string by the specified characters. + /// + /// + /// The string to split. + /// + /// + /// The characters to split by. + /// + /// + /// The split strings. + /// + private static IEnumerable SplitByChars(string source, params char[] characters) + { + return source.Split(characters); + } + /// + /// Cleans the collection of strings, trimming whitespace and removing empties. + /// + /// + /// The items to clean. + /// + /// + /// The cleaned strings. + /// + private static IEnumerable CleanItems(IEnumerable items) + { + return items + .MakeSafe() + .Select(x => x.Trim()) + .Where(x => !string.IsNullOrWhiteSpace(x)); } -} \ No newline at end of file + #endregion +} diff --git a/src/Tests/StringTests.cs b/src/Tests/StringTests.cs index 0ce29f6..c498ccc 100644 --- a/src/Tests/StringTests.cs +++ b/src/Tests/StringTests.cs @@ -1,51 +1,46 @@ -namespace Tests +namespace Tests; + +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Rhythm.Core; + +/// +/// Tests for string extension methods. +/// +[TestClass] +public sealed class StringTests { - // Namespaces. - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Rhythm.Core; + #region Test Methods /// - /// Tests for string extension methods. + /// Test if camel case works. /// - [TestClass] - public class StringTests + [TestMethod] + public void CamelCase() { + var result = "hello-world-test".ToCamelCase(); + Assert.AreEqual("helloWorldTest", result); + } - #region Test Methods - - /// - /// Test if camel case works. - /// - [TestMethod] - public void CamelCase() - { - var result = "hello-world-test".ToCamelCase(); - Assert.AreEqual("helloWorldTest", result); - } - - /// - /// Test if pascal case works. - /// - [TestMethod] - public void PascalCase() - { - var result = "hello-world-test".ToPascalCase(); - Assert.AreEqual("HelloWorldTest", result); - } - - /// - /// Test if pascal case works with a single letter. - /// - [TestMethod] - public void PascalCaseSingleLetter() - { - var result = "a".ToPascalCase(); - Assert.AreEqual("A", result); - } - - #endregion + /// + /// Test if pascal case works. + /// + [TestMethod] + public void PascalCase() + { + var result = "hello-world-test".ToPascalCase(); + Assert.AreEqual("HelloWorldTest", result); + } + /// + /// Test if pascal case works with a single letter. + /// + [TestMethod] + public void PascalCaseSingleLetter() + { + var result = "a".ToPascalCase(); + Assert.AreEqual("A", result); } -} \ No newline at end of file + #endregion +}