From c92ed740355b9a2076acf06e2d0448a15b4a0d28 Mon Sep 17 00:00:00 2001 From: Mogens Heller Grabe Date: Mon, 5 Oct 2015 20:15:09 +0200 Subject: [PATCH] updated stuff --- GoCommando.Tests/TestArgParser.cs | 28 ++++++++++++++++++--- GoCommando/Go.cs | 42 +++++++++++++++++++++++++++++++ GoCommando/Internals/Command.cs | 23 ++++++++++++++--- GoCommando/Internals/Parameter.cs | 23 +++++++++++++++-- GoCommando/ParameterAttribute.cs | 4 ++- TestApp/Commands/StopCommand.cs | 8 ++++-- 6 files changed, 116 insertions(+), 12 deletions(-) diff --git a/GoCommando.Tests/TestArgParser.cs b/GoCommando.Tests/TestArgParser.cs index 0e319ca..51731c4 100644 --- a/GoCommando.Tests/TestArgParser.cs +++ b/GoCommando.Tests/TestArgParser.cs @@ -12,7 +12,7 @@ public class TestArgParser [Test] public void CanReturnSimpleCommand() { - var arguments = Parse(new[] {"run"}); + var arguments = Parse(new[] { "run" }); Assert.That(arguments.Command, Is.EqualTo("run")); } @@ -22,7 +22,7 @@ public void DoesNotAcceptSwitchAsCommand() { var ex = Assert.Throws(() => { - Parse(new[] {"-file", @"""C:\temp\file.json"""}); + Parse(new[] { "-file", @"""C:\temp\file.json""" }); }); Console.WriteLine(ex); @@ -37,7 +37,7 @@ public void CanParseOrdinaryArguments() -dir c:\Windows\Microsoft.NET\Framework -flag --moreflag".Split(new[] {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries); +-moreflag".Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); var arguments = Parse(args); @@ -53,6 +53,28 @@ public void CanParseOrdinaryArguments() Assert.That(arguments.Get("flag_not_specified_should_default_to_false"), Is.False); } + [TestCase(@"-path:""c:\temp""")] + [TestCase(@"-path=""c:\temp""")] + [TestCase(@"-path""c:\temp""")] + public void SupportsVariousSingleTokenAliases(string alias) + { + var arguments = Parse(new[] { alias }); + + Assert.That(arguments.Switches.Count(), Is.EqualTo(1)); + Assert.That(arguments.Switches.Single().Key, Is.EqualTo("path")); + Assert.That(arguments.Switches.Single().Value, Is.EqualTo(@"""c:\temp""")); + } + + [TestCase(@"-n23")] + public void SupportsShortFormWithNumber(string alias) + { + var arguments = Parse(new[] { alias }); + + Assert.That(arguments.Switches.Count(), Is.EqualTo(1)); + Assert.That(arguments.Switches.Single().Key, Is.EqualTo("n")); + Assert.That(arguments.Switches.Single().Value, Is.EqualTo(@"23")); + } + static Arguments Parse(IEnumerable args) { return Go.Parse(args, new Settings()); diff --git a/GoCommando/Go.cs b/GoCommando/Go.cs index ea85154..199fc65 100644 --- a/GoCommando/Go.cs +++ b/GoCommando/Go.cs @@ -235,6 +235,18 @@ internal static Arguments Parse(IEnumerable args, Settings settings) } key = arg.Substring(settings.SwitchPrefix.Length); + + if (HasKeyAndValue(key)) + { + var keyAndValue = GetKeyAndValueFromKey(key); + if (keyAndValue == null) + { + throw new ApplicationException($"Expected to get key-value-pair from key '{key}'"); + } + switches.Add(Switch.KeyValue(keyAndValue.Value.Key, keyAndValue.Value.Value)); + key = null; + } + continue; } @@ -257,5 +269,35 @@ internal static Arguments Parse(IEnumerable args, Settings settings) return new Arguments(command, switches, settings); } + + static bool HasKeyAndValue(string key) + { + return GetKeyAndValueFromKey(key) != null; + } + + static KeyValuePair? GetKeyAndValueFromKey(string key) + { + for (var index = 0; index < key.Length; index++) + { + var c = key[index]; + + if (c == ':') + { + return new KeyValuePair(key.Substring(0, index), key.Substring(index + 1)); + } + + if (c == '=') + { + return new KeyValuePair(key.Substring(0, index), key.Substring(index + 1)); + } + + if (!char.IsLetter(c)) + { + return new KeyValuePair(key.Substring(0, index), key.Substring(index)); + } + } + + return null; + } } } diff --git a/GoCommando/Internals/Command.cs b/GoCommando/Internals/Command.cs index 788871e..8e23fd8 100644 --- a/GoCommando/Internals/Command.cs +++ b/GoCommando/Internals/Command.cs @@ -40,7 +40,8 @@ IEnumerable GetParameters(Type type) a.ParameterAttribute.ShortName, a.ParameterAttribute.Optional, a.DescriptionAttribute?.DescriptionText, - a.ExampleAttributes.Select(e => e.ExampleValue))) + a.ExampleAttributes.Select(e => e.ExampleValue), + a.ParameterAttribute.DefaultValue)) .ToList(); } @@ -64,13 +65,13 @@ public void Invoke(IEnumerable switches) var commandInstance = (ICommand)Activator.CreateInstance(Type); var requiredParametersMissing = Parameters - .Where(p => !p.Optional && !switches.Any(s => s.Key == p.Name)) + .Where(p => !p.Optional && !p.HasDefaultValue && !switches.Any(s => s.Key == p.Name)) .ToList(); if (requiredParametersMissing.Any()) { var requiredParametersMissingString = string.Join(Environment.NewLine, - requiredParametersMissing.Select(p => " " + p.Name)); + requiredParametersMissing.Select(p => $" {_settings.SwitchPrefix}{p.Name}")); throw new GoCommandoException($@"The following required parameters are missing: @@ -93,11 +94,25 @@ public void Invoke(IEnumerable switches) {switchesWithoutMathingParameterString}"); } + var setParameters = new HashSet(); + foreach (var switchToSet in switches) { var correspondingParameter = Parameters.FirstOrDefault(p => p.MatchesKey(switchToSet.Key)); - correspondingParameter?.SetValue(commandInstance, switchToSet.Value); + if (correspondingParameter == null) + { + throw new GoCommandoException($"The switch {_settings}{switchToSet.Key} does not correspond to a parameter of the '{Command}' command!"); + } + + correspondingParameter.SetValue(commandInstance, switchToSet.Value); + + setParameters.Add(correspondingParameter); + } + + foreach (var parameterWithDefaultValue in Parameters.Where(p => p.HasDefaultValue).Except(setParameters)) + { + parameterWithDefaultValue.ApplyDefaultValue(commandInstance); } commandInstance.Run(); diff --git a/GoCommando/Internals/Parameter.cs b/GoCommando/Internals/Parameter.cs index eb3a24d..64fb9d6 100644 --- a/GoCommando/Internals/Parameter.cs +++ b/GoCommando/Internals/Parameter.cs @@ -5,24 +5,28 @@ namespace GoCommando.Internals { - class Parameter + class Parameter : IEquatable { public PropertyInfo PropertyInfo { get; } public string Name { get; } public string Shortname { get; } public bool Optional { get; } public string DescriptionText { get; } + public string DefaultValue { get; } public string[] ExampleValues { get; } public bool IsFlag => PropertyInfo.PropertyType == typeof (bool); - public Parameter(PropertyInfo propertyInfo, string name, string shortname, bool optional, string descriptionText, IEnumerable exampleValues) + public bool HasDefaultValue => DefaultValue != null; + + public Parameter(PropertyInfo propertyInfo, string name, string shortname, bool optional, string descriptionText, IEnumerable exampleValues, string defaultValue) { PropertyInfo = propertyInfo; Name = name; Shortname = shortname; Optional = optional; DescriptionText = descriptionText; + DefaultValue = defaultValue; ExampleValues = exampleValues.ToArray(); } @@ -48,5 +52,20 @@ public void SetValue(object commandInstance, string value) throw new FormatException($"Could not set value '{value}' on property named '{PropertyInfo.Name}' on {PropertyInfo.DeclaringType}", exception); } } + + public void ApplyDefaultValue(ICommand commandInstance) + { + if (!HasDefaultValue) + { + throw new InvalidOperationException($"Cannot apply default value of '{Name}' parameter because it has no default!"); + } + + SetValue(commandInstance, DefaultValue); + } + + public bool Equals(Parameter other) + { + return Name.Equals(other.Name); + } } } \ No newline at end of file diff --git a/GoCommando/ParameterAttribute.cs b/GoCommando/ParameterAttribute.cs index 2b8f6e1..de79f24 100644 --- a/GoCommando/ParameterAttribute.cs +++ b/GoCommando/ParameterAttribute.cs @@ -11,12 +11,14 @@ public class ParameterAttribute : Attribute public string Name { get; } public string ShortName { get; } public bool Optional { get; } + public string DefaultValue { get; } - public ParameterAttribute(string name, string shortName = null, bool optional = false) + public ParameterAttribute(string name, string shortName = null, bool optional = false, string defaultValue = null) { Name = name; ShortName = shortName; Optional = optional; + DefaultValue = defaultValue; } } } \ No newline at end of file diff --git a/TestApp/Commands/StopCommand.cs b/TestApp/Commands/StopCommand.cs index 35d1ca5..deac502 100644 --- a/TestApp/Commands/StopCommand.cs +++ b/TestApp/Commands/StopCommand.cs @@ -1,13 +1,17 @@ -using GoCommando; +using System; +using GoCommando; namespace TestApp.Commands { [Command("stop")] public class StopCommand : ICommand { + [Parameter("bimse", defaultValue: "default_value")] + public string Bimse { get; set; } + public void Run() { - + Console.WriteLine("BIMSE: {0}", Bimse); } } } \ No newline at end of file