diff --git a/CHANGELOG.md b/CHANGELOG.md index 825f45d..65ec3d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,3 +3,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [3.0.0] - 2018-04-23 +### Added + - Adding extension method for getting Informational Version from an Assembly + - Adding WeakKeyDictionary for caching + - Reflection util methods + +### Changed + - JSON serialization/deserialization features moved into base converter + - Removed suffix from assembly name + \ No newline at end of file diff --git a/ICD.Common.Utils/AttributeUtils.cs b/ICD.Common.Utils/AttributeUtils.cs index e9cf173..637b8cc 100644 --- a/ICD.Common.Utils/AttributeUtils.cs +++ b/ICD.Common.Utils/AttributeUtils.cs @@ -84,6 +84,14 @@ namespace ICD.Common.Utils { foreach (Exception inner in e.LoaderExceptions) { + if (inner is System.IO.FileNotFoundException) + { + Logger.AddEntry(eSeverity.Error, + "{0} failed to cache assembly {1} - Could not find one or more dependencies by path", + typeof(AttributeUtils).Name, assembly.GetName().Name); + continue; + } + Logger.AddEntry(eSeverity.Error, inner, "{0} failed to cache assembly {1}", typeof(AttributeUtils).Name, assembly.GetName().Name); } diff --git a/ICD.Common.Utils/Extensions/AssemblyExtensions.cs b/ICD.Common.Utils/Extensions/AssemblyExtensions.cs index 3a67c37..fafd5a9 100644 --- a/ICD.Common.Utils/Extensions/AssemblyExtensions.cs +++ b/ICD.Common.Utils/Extensions/AssemblyExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using ICD.Common.Properties; using ICD.Common.Utils.IO; #if SIMPLSHARP @@ -12,7 +13,7 @@ namespace ICD.Common.Utils.Extensions public static class AssemblyExtensions { /// - /// Gets the path for the given assembly. Returns null if the assembly can not be found on disk. + /// Gets the path for the assembly. Returns null if the assembly can not be found on disk. /// /// /// @@ -45,10 +46,11 @@ namespace ICD.Common.Utils.Extensions } /// - /// Gets the creation date of the given assembly. + /// Gets the creation date of the assembly. /// /// /// + [PublicAPI] public static DateTime GetCreationTime(this Assembly extends) { if (extends == null) @@ -57,5 +59,40 @@ namespace ICD.Common.Utils.Extensions string path = extends.GetPath(); return path == null ? DateTime.MinValue : IcdFile.GetCreationTime(path); } + + /// + /// Gets the informational version for the assembly. + /// + /// + /// + [PublicAPI] + public static string GetInformationalVersion(this Assembly extends) + { + if (extends == null) + throw new ArgumentNullException("extends"); + + string version; + if (extends.TryGetInformationalVersion(out version)) + return version; + + throw new InvalidOperationException("Assembly has no informational version attribute."); + } + + /// + /// Tries to get the informational version for the assembly. + /// + /// + /// + /// + [PublicAPI] + public static bool TryGetInformationalVersion(this Assembly extends, out string version) + { + if (extends == null) + throw new ArgumentNullException("extends"); + + return extends.GetCustomAttributes() + .Select(a => a.InformationalVersion) + .TryFirst(out version); + } } } diff --git a/ICD.Common.Utils/Extensions/ListExtensions.cs b/ICD.Common.Utils/Extensions/ListExtensions.cs index e5394a8..50c28c7 100644 --- a/ICD.Common.Utils/Extensions/ListExtensions.cs +++ b/ICD.Common.Utils/Extensions/ListExtensions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using ICD.Common.Properties; +using ICD.Common.Utils.Comparers; namespace ICD.Common.Utils.Extensions { @@ -29,7 +30,7 @@ namespace ICD.Common.Utils.Extensions } /// - /// Adds the item into a sorted list. + /// Adds the items into a sorted list. /// /// /// @@ -50,6 +51,30 @@ namespace ICD.Common.Utils.Extensions items.ForEach(i => extends.AddSorted(i, comparer)); } + /// + /// Adds the items into a sorted list. + /// + /// + /// + /// + /// + /// + [PublicAPI] + public static void AddSorted(this List extends, IEnumerable items, Func predicate) + { + if (extends == null) + throw new ArgumentNullException("extends"); + + if (items == null) + throw new ArgumentNullException("items"); + + if (predicate == null) + throw new ArgumentNullException("predicate"); + + PredicateComparer comparer = new PredicateComparer(predicate); + extends.AddSorted(items, comparer); + } + /// /// Adds the item into a sorted list. /// @@ -106,6 +131,27 @@ namespace ICD.Common.Utils.Extensions extends.Insert(index, item); } + /// + /// Adds the item into a sorted list. + /// + /// + /// + /// + /// + /// + [PublicAPI] + public static void AddSorted(this List extends, T item, Func predicate) + { + if (extends == null) + throw new ArgumentNullException("extends"); + + if (predicate == null) + throw new ArgumentNullException("predicate"); + + PredicateComparer comparer = new PredicateComparer(predicate); + extends.AddSorted(item, comparer); + } + /// /// Pads the list to the given total length. /// diff --git a/ICD.Common.Utils/IO/IcdPath.cs b/ICD.Common.Utils/IO/IcdPath.cs index 37d0bad..6ee4a52 100644 --- a/ICD.Common.Utils/IO/IcdPath.cs +++ b/ICD.Common.Utils/IO/IcdPath.cs @@ -10,6 +10,10 @@ namespace ICD.Common.Utils.IO { public static class IcdPath { + public static char DirectorySeparatorChar { get { return Path.DirectorySeparatorChar; } } + + public static char AltDirectorySeparatorChar { get { return Path.AltDirectorySeparatorChar; } } + public static string GetFileName(string path) { if (path == null) diff --git a/ICD.Common.Utils/Json/AbstractGenericJsonConverter.cs b/ICD.Common.Utils/Json/AbstractGenericJsonConverter.cs index 151a7ca..ced8956 100644 --- a/ICD.Common.Utils/Json/AbstractGenericJsonConverter.cs +++ b/ICD.Common.Utils/Json/AbstractGenericJsonConverter.cs @@ -6,6 +6,15 @@ namespace ICD.Common.Utils.Json { public abstract class AbstractGenericJsonConverter : JsonConverter { + /// + /// Creates a new instance of T. + /// + /// + protected virtual T Instantiate() + { + return ReflectionUtils.CreateInstance(); + } + /// /// Writes the JSON representation of the object. /// @@ -36,7 +45,24 @@ namespace ICD.Common.Utils.Json /// The value. /// The calling serializer. [PublicAPI] - public abstract void WriteJson(JsonWriter writer, T value, JsonSerializer serializer); + public virtual void WriteJson(JsonWriter writer, T value, JsonSerializer serializer) + { + writer.WriteStartObject(); + { + WriteProperties(writer, value, serializer); + } + writer.WriteEndObject(); + } + + /// + /// Override to write properties to the writer. + /// + /// + /// + /// + protected virtual void WriteProperties(JsonWriter writer, T value, JsonSerializer serializer) + { + } /// /// Reads the JSON representation of the object. @@ -70,7 +96,52 @@ namespace ICD.Common.Utils.Json /// The object value. /// [PublicAPI] - public abstract T ReadJson(JsonReader reader, T existingValue, JsonSerializer serializer); + public virtual T ReadJson(JsonReader reader, T existingValue, JsonSerializer serializer) + { + T output = default(T); + bool instantiated = false; + + while (reader.Read()) + { + if (reader.TokenType == JsonToken.Null || reader.TokenType == JsonToken.EndObject) + break; + + if (!instantiated) + { + instantiated = true; + output = Instantiate(); + } + + // Get the property + if (reader.TokenType != JsonToken.PropertyName) + continue; + string property = (string)reader.Value; + + // Read into the value + reader.Read(); + + switch (property) + { + default: + ReadProperty(property, reader, output, serializer); + break; + } + } + + return output; + } + + /// + /// Override to handle the current property value with the given name. + /// + /// + /// + /// + /// + protected virtual void ReadProperty(string property, JsonReader reader, T instance, JsonSerializer serializer) + { + reader.Skip(); + } /// /// Determines whether this instance can convert the specified object type. diff --git a/ICD.Common.Utils/PathUtils.cs b/ICD.Common.Utils/PathUtils.cs index 7a691e1..3d473a6 100644 --- a/ICD.Common.Utils/PathUtils.cs +++ b/ICD.Common.Utils/PathUtils.cs @@ -185,6 +185,24 @@ namespace ICD.Common.Utils return IcdFile.Exists(path) || IcdDirectory.Exists(path); } + /// + /// Returns the path if the given path is already a directory or has a trailing slash. + /// Otherwise returns the parent directory name. + /// + /// + /// + [PublicAPI] + public static string GetDirectoryNameFromPath(string path) + { + if (IcdDirectory.Exists(path)) + return path; + + if (path.EndsWith(IcdPath.DirectorySeparatorChar) || path.EndsWith(IcdPath.AltDirectorySeparatorChar)) + return path; + + return IcdPath.GetDirectoryName(path); + } + #endregion } } diff --git a/ICD.Common.Utils/Properties/AssemblyInfo.cs b/ICD.Common.Utils/Properties/AssemblyInfo.cs index 4a435e7..2303f51 100644 --- a/ICD.Common.Utils/Properties/AssemblyInfo.cs +++ b/ICD.Common.Utils/Properties/AssemblyInfo.cs @@ -4,4 +4,4 @@ using System.Reflection; [assembly: AssemblyCompany("ICD Systems")] [assembly: AssemblyProduct("ICD.Common.Utils")] [assembly: AssemblyCopyright("Copyright © ICD Systems 2018")] -[assembly: AssemblyVersion("2.0.0.0")] +[assembly: AssemblyVersion("3.0.0.0")] diff --git a/ICD.Common.Utils/StringUtils.cs b/ICD.Common.Utils/StringUtils.cs index 36008e7..3235b7b 100644 --- a/ICD.Common.Utils/StringUtils.cs +++ b/ICD.Common.Utils/StringUtils.cs @@ -610,5 +610,77 @@ namespace ICD.Common.Utils { return value == null ? null : value.ToUpper(); } + + /// + /// Compares the given chars for equality. + /// + /// + /// + /// + /// + [PublicAPI] + public static bool Compare(char a, char b, bool ignoreCase) + { + if (ignoreCase) + { + a = char.ToUpper(a, CultureInfo.InvariantCulture); + b = char.ToUpper(b, CultureInfo.InvariantCulture); + } + + return a == b; + } + + /// + /// Find the longest common string between the matches. + /// E.g. + /// + /// C:\\Workspace + /// C:\\Workshop + /// + /// Results in + /// + /// C:\\Work + /// + /// + /// + /// + [PublicAPI] + public static string GetLongestCommonIntersectionFromStart(IEnumerable items, bool ignoreCase) + { + if (items == null) + throw new ArgumentNullException("items"); + + string output = null; + + foreach (string item in items) + { + // If there is a null in the sequence that's the best match we can make + if (string.IsNullOrEmpty(item)) + return null; + + // Seed our first item + if (output == null) + { + output = item; + continue; + } + + // Find the common substring + for (int index = 0; index < output.Length; index++) + { + if (index >= item.Length || !Compare(output[index], item[index], ignoreCase)) + { + output = output.Substring(0, index); + break; + } + } + + // Abandon the search if there is no common substring + if (string.IsNullOrEmpty(output)) + break; + } + + return output; + } } }