diff --git a/src/Umbraco.Core/EnumerableExtensions.cs b/src/Umbraco.Core/EnumerableExtensions.cs index dfdd26cd84..2aba7684f0 100644 --- a/src/Umbraco.Core/EnumerableExtensions.cs +++ b/src/Umbraco.Core/EnumerableExtensions.cs @@ -17,21 +17,41 @@ namespace Umbraco.Core throw new NullReferenceException("source"); // enumerate the source only once! - var enumerator = source.GetEnumerator(); - - while (enumerator.MoveNext()) - yield return EnumerateGroup(enumerator, groupSize); + return new InGroupsEnumerator(source, groupSize).Groups(); } - private static IEnumerable EnumerateGroup(IEnumerator enumerator, int count) + // this class makes sure that the source is enumerated only ONCE + // which means that when it is enumerated, the actual groups content + // has to be evaluated at the same time, and stored in an array. + private class InGroupsEnumerator { - var c = 1; - do - { - yield return enumerator.Current; - } while (c++ < count && enumerator.MoveNext()); - } + private readonly IEnumerator _source; + private readonly int _count; + private bool _mightHaveNext; + public InGroupsEnumerator(IEnumerable source, int count) + { + _source = source.GetEnumerator(); + _count = count; + _mightHaveNext = true; + } + + public IEnumerable> Groups() + { + while (_mightHaveNext && _source.MoveNext()) + yield return Group().ToArray(); // see note above + } + + private IEnumerable Group() + { + var c = 0; + do + { + yield return _source.Current; + } while (++c < _count && _source.MoveNext()); + _mightHaveNext = c == _count; + } + } /// The distinct by. /// The source. diff --git a/src/Umbraco.Core/StringExtensions.cs b/src/Umbraco.Core/StringExtensions.cs index 95871ef4d0..dccda746af 100644 --- a/src/Umbraco.Core/StringExtensions.cs +++ b/src/Umbraco.Core/StringExtensions.cs @@ -1064,7 +1064,7 @@ namespace Umbraco.Core /// strings are cleaned up to camelCase and Ascii. /// The clean string. /// The string is cleaned in the context of the IShortStringHelper default culture. - public static string ToCleanString(string text, CleanStringType stringType) + public static string ToCleanString(this string text, CleanStringType stringType) { return ShortStringHelper.CleanString(text, stringType); } @@ -1078,7 +1078,7 @@ namespace Umbraco.Core /// The separator. /// The clean string. /// The string is cleaned in the context of the IShortStringHelper default culture. - public static string ToCleanString(string text, CleanStringType stringType, char separator) + public static string ToCleanString(this string text, CleanStringType stringType, char separator) { return ShortStringHelper.CleanString(text, stringType, separator); } @@ -1091,7 +1091,7 @@ namespace Umbraco.Core /// strings are cleaned up to camelCase and Ascii. /// The culture. /// The clean string. - public static string ToCleanString(string text, CleanStringType stringType, CultureInfo culture) + public static string ToCleanString(this string text, CleanStringType stringType, CultureInfo culture) { return ShortStringHelper.CleanString(text, stringType, culture); } @@ -1105,7 +1105,7 @@ namespace Umbraco.Core /// The separator. /// The culture. /// The clean string. - public static string ToCleanString(string text, CleanStringType stringType, char separator, CultureInfo culture) + public static string ToCleanString(this string text, CleanStringType stringType, char separator, CultureInfo culture) { return ShortStringHelper.CleanString(text, stringType, separator, culture); } diff --git a/src/Umbraco.Tests/CodeFirst/ContentTypeMapper.cs b/src/Umbraco.Tests/CodeFirst/ContentTypeMapper.cs index d7ff2c2f94..d0130b948e 100644 --- a/src/Umbraco.Tests/CodeFirst/ContentTypeMapper.cs +++ b/src/Umbraco.Tests/CodeFirst/ContentTypeMapper.cs @@ -19,9 +19,9 @@ namespace Umbraco.Tests.CodeFirst foreach (var property in content.Properties) { - var @alias = property.Alias; + var @alias = property.Alias.ToLowerInvariant(); - var propertyInfo = propertyInfos.FirstOrDefault(x => x.Name.ToUmbracoAlias() == @alias); + var propertyInfo = propertyInfos.FirstOrDefault(x => x.Name.ToLowerInvariant() == @alias); if (propertyInfo == null) continue; object value = null; diff --git a/src/Umbraco.Tests/CodeFirst/TypeInheritanceTest.cs b/src/Umbraco.Tests/CodeFirst/TypeInheritanceTest.cs index e53d8552e8..ccc5d887f5 100644 --- a/src/Umbraco.Tests/CodeFirst/TypeInheritanceTest.cs +++ b/src/Umbraco.Tests/CodeFirst/TypeInheritanceTest.cs @@ -64,9 +64,9 @@ namespace Umbraco.Tests.CodeFirst } Assert.That(list.Count, Is.EqualTo(3)); - Assert.That(list.Any(x => x == "meta"), Is.True); - Assert.That(list.Any(x => x == "metaSeo"), Is.True); - Assert.That(list.Any(x => x == "base"), Is.True); + Assert.Contains("Meta", list); + Assert.Contains("MetaSeo", list); + Assert.Contains("Base", list); } [Test] diff --git a/src/Umbraco.Tests/CoreStrings/CmsHelperCasingTests.cs b/src/Umbraco.Tests/CoreStrings/CmsHelperCasingTests.cs index 57f0606361..5d369ab11d 100644 --- a/src/Umbraco.Tests/CoreStrings/CmsHelperCasingTests.cs +++ b/src/Umbraco.Tests/CoreStrings/CmsHelperCasingTests.cs @@ -22,7 +22,8 @@ namespace Umbraco.Tests.CoreStrings [TestCase("t", "t")] [TestCase("thisis", "Thisis")] [TestCase("ThisIsTheEnd", "This Is The End")] - [TestCase("WhoIsNumber6InTheVillage", "Who Is Number6In The Village")] // note the issue with Number6In + //[TestCase("WhoIsNumber6InTheVillage", "Who Is Number6In The Village")] // note the issue with Number6In + [TestCase("WhoIsNumber6InTheVillage", "Who Is Number6 In The Village")] // now fixed since DefaultShortStringHelper is the default public void SpaceCamelCasing(string input, string expected) { var output = umbraco.cms.helpers.Casing.SpaceCamelCasing(input); diff --git a/src/Umbraco.Web/Models/DynamicPublishedContent.cs b/src/Umbraco.Web/Models/DynamicPublishedContent.cs index 7771517419..aeb4e40046 100644 --- a/src/Umbraco.Web/Models/DynamicPublishedContent.cs +++ b/src/Umbraco.Web/Models/DynamicPublishedContent.cs @@ -13,6 +13,7 @@ using Umbraco.Core.PropertyEditors; using System.Reflection; using System.Xml.Linq; using umbraco.cms.businesslogic; +using Umbraco.Core.Strings; using ContentType = umbraco.cms.businesslogic.ContentType; namespace Umbraco.Web.Models @@ -404,9 +405,9 @@ namespace Umbraco.Web.Models { //if we cannot get with the current alias, try changing it's case attempt = alias[0].IsUpperCase() - ? getMember(alias.ConvertCase(StringAliasCaseType.CamelCase)) - : getMember(alias.ConvertCase(StringAliasCaseType.PascalCase)); - } + ? getMember(alias.ToCleanString(CleanStringType.Ascii | CleanStringType.Alias | CleanStringType.CamelCase)) + : getMember(alias.ToCleanString(CleanStringType.Ascii | CleanStringType.Alias | CleanStringType.PascalCase)); + } return !attempt.Success ? null diff --git a/src/Umbraco.Web/umbraco.presentation/item.cs b/src/Umbraco.Web/umbraco.presentation/item.cs index 09cb19fced..0ec82b42e5 100644 --- a/src/Umbraco.Web/umbraco.presentation/item.cs +++ b/src/Umbraco.Web/umbraco.presentation/item.cs @@ -7,6 +7,7 @@ using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Models; using Umbraco.Core.Profiling; +using Umbraco.Core.Strings; namespace umbraco { @@ -180,7 +181,7 @@ namespace umbraco else if (helper.FindAttribute(attributes, "case") == "upper") _fieldContent = _fieldContent.ToUpper(); else if (helper.FindAttribute(attributes, "case") == "title") - _fieldContent = _fieldContent.ConvertCase(StringAliasCaseType.PascalCase); + _fieldContent = _fieldContent.ToCleanString(CleanStringType.Ascii | CleanStringType.Alias | CleanStringType.PascalCase); // OTHER FORMATTING FUNCTIONS // If we use masterpages, this is moved to the ItemRenderer to add support for before/after in inline XSLT diff --git a/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs b/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs index c4ee935461..b46187ef94 100644 --- a/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs +++ b/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs @@ -9,6 +9,7 @@ using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Dynamics; using Umbraco.Core.Logging; +using Umbraco.Core.Strings; using umbraco.interfaces; using System.Collections; using System.Reflection; @@ -682,8 +683,8 @@ namespace umbraco.MacroEngines { //if we cannot get with the current alias, try changing it's case attempt = alias[0].IsUpperCase() - ? getMember(alias.ConvertCase(StringAliasCaseType.CamelCase)) - : getMember(alias.ConvertCase(StringAliasCaseType.PascalCase)); + ? getMember(alias.ToCleanString(CleanStringType.Ascii | CleanStringType.Alias | CleanStringType.CamelCase)) + : getMember(alias.ToCleanString(CleanStringType.Ascii | CleanStringType.Alias | CleanStringType.PascalCase)); } return attempt.Success ? attempt.Result : null;