From 41c0c1e519c236576f64d1056ba39999b05b4745 Mon Sep 17 00:00:00 2001 From: Matthias Beerens <3512339+Matthiee@users.noreply.github.com> Date: Thu, 22 Nov 2018 13:56:40 +0100 Subject: [PATCH 01/10] Add codefactor and fix wrong issue badge --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b492fe6..9a14551 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@

Buitld Status (AppVeyor) - Open Issues + Open Issues Codecov + Codefactor badge AGPL v3

From 91e6cd176872125911e53f0a79e75506b771bdb3 Mon Sep 17 00:00:00 2001 From: Matthias Beerens <3512339+Matthiee@users.noreply.github.com> Date: Thu, 22 Nov 2018 13:59:04 +0100 Subject: [PATCH 02/10] Update AppVeyor badge and link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9a14551..6abeabe 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- Buitld Status (AppVeyor) + Buitld Status (AppVeyor) Open Issues Codecov Codefactor badge From 689b08ba482686233b3b8c7dfd7bbb30db0b7781 Mon Sep 17 00:00:00 2001 From: Matthias Beerens <3512339+Matthiee@users.noreply.github.com> Date: Sun, 25 Nov 2018 16:38:07 +0100 Subject: [PATCH 03/10] Add options model --- .../CommandLineArgumentOptionTest.cs | 7 +- .../CommandLineModelTests.cs | 63 ++++++++++++++ .../CommandLineParserTests.cs | 39 ++++----- CommandLineParser.Tests/ExtensionsTests.cs | 37 --------- CommandLineParser.Tests/OptionBuilderTest.cs | 14 +--- .../Parsing/ParserResultTest.cs | 2 - .../Parsing/ResolverFactoryTest.cs | 29 ++++++- .../Parsing/Resolvers/BoolResolverTests.cs | 5 +- .../Parsing/Resolvers/DoubleResolverTests.cs | 6 +- .../Parsing/Resolvers/IntResolverTests.cs | 5 +- .../Parsing/Resolvers/StringResovlerTests.cs | 5 +- CommandLineParser.Tests/XUnitExtensions.cs | 11 ++- .../Abstractions/Command/ICommandBuilder'.cs | 6 +- .../Command/ICommandLineCommand.cs | 7 +- .../Command/ICommandLineCommandParser.cs | 4 +- .../Abstractions/ICommandLineOption'.cs | 13 --- .../Abstractions/ICommandLineOption.cs | 3 - .../Abstractions/ICommandLineParser'.cs | 4 +- .../Abstractions/IOptionBuilder'.cs | 18 ++-- .../Abstractions/Models/ArgumentModel.cs | 6 +- .../Parsing/Command/ICommandParserResult.cs | 2 - .../Abstractions/Parsing/IArgumentManager.cs | 5 +- .../Parsing/ICommandLineArgumentResolver.cs | 15 ++-- .../Abstractions/Parsing/IParser.cs | 5 +- .../Abstractions/Parsing/IParserResult.cs | 1 - .../Abstractions/Parsing/IResolverFactory.cs | 4 +- CommandLineParser/CommandLineParser.cs | 83 ++++++++++++++++--- .../Core/Attributes/BaseAttribute.cs | 9 ++ .../Core/Attributes/DefaultValueAttribute.cs | 9 ++ .../Core/Attributes/HelpTextAttribute.cs | 9 ++ .../Core/Attributes/NameAttribute.cs | 18 ++++ .../Core/Attributes/RequiredAttribute.cs | 9 ++ .../Core/Command/CommandLineCommand.cs | 12 +-- .../Core/Command/CommandLineCommandBase.cs | 4 +- CommandLineParser/Core/CommandLineOption.cs | 31 +++---- .../Core/CommandLineOptionBase.cs | 5 +- .../Exceptions/CommandNotFoundException.cs | 2 - .../Core/Exceptions/CommandParseException.cs | 7 +- .../Exceptions/OptionNotFoundException.cs | 2 - .../Core/Exceptions/OptionParseException.cs | 2 - CommandLineParser/Core/Extensions.cs | 28 ------- .../Core/Parsing/ArgumentManager.cs | 2 - .../Core/Parsing/ResolverFactory.cs | 26 ++++-- .../Core/Parsing/Resolvers/BoolResolver.cs | 4 +- .../Core/Parsing/Resolvers/DoubleResolver.cs | 7 +- .../Core/Parsing/Resolvers/IntResolver.cs | 8 +- .../Core/Parsing/Resolvers/StringResolver.cs | 11 +-- .../Core/ReadOnlyCollectionWrapper.cs | 38 +++++++++ SampleApp/Program.cs | 12 +-- 49 files changed, 368 insertions(+), 286 deletions(-) create mode 100644 CommandLineParser.Tests/CommandLineModelTests.cs delete mode 100644 CommandLineParser.Tests/ExtensionsTests.cs delete mode 100644 CommandLineParser/Abstractions/ICommandLineOption'.cs create mode 100644 CommandLineParser/Core/Attributes/BaseAttribute.cs create mode 100644 CommandLineParser/Core/Attributes/DefaultValueAttribute.cs create mode 100644 CommandLineParser/Core/Attributes/HelpTextAttribute.cs create mode 100644 CommandLineParser/Core/Attributes/NameAttribute.cs create mode 100644 CommandLineParser/Core/Attributes/RequiredAttribute.cs delete mode 100644 CommandLineParser/Core/Extensions.cs create mode 100644 CommandLineParser/Core/ReadOnlyCollectionWrapper.cs diff --git a/CommandLineParser.Tests/CommandLineArgumentOptionTest.cs b/CommandLineParser.Tests/CommandLineArgumentOptionTest.cs index 49bc8db..a061241 100644 --- a/CommandLineParser.Tests/CommandLineArgumentOptionTest.cs +++ b/CommandLineParser.Tests/CommandLineArgumentOptionTest.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Xunit; - -namespace MatthiWare.CommandLineParser.Tests +namespace MatthiWare.CommandLineParser.Tests { public class CommandLineArgumentOptionTest diff --git a/CommandLineParser.Tests/CommandLineModelTests.cs b/CommandLineParser.Tests/CommandLineModelTests.cs new file mode 100644 index 0000000..305b91b --- /dev/null +++ b/CommandLineParser.Tests/CommandLineModelTests.cs @@ -0,0 +1,63 @@ +using MatthiWare.CommandLine; +using MatthiWare.CommandLine.Core.Attributes; +using Xunit; + +namespace MatthiWare.CommandLineParser.Tests +{ + public class CommandLineModelTests + { + [Fact] + public void TestBasicModel() + { + var parser = new CommandLineParser(); + + Assert.Equal(1, parser.Options.Count); + + var message = parser.Options[0]; + + Assert.NotNull(message); + + Assert.True(message.HasLongName && message.HasShortName); + + Assert.Equal("-m", message.ShortName); + Assert.Equal("--message", message.LongName); + + Assert.True(message.HasDefault); + Assert.True(message.IsRequired); + + Assert.Equal("Help", message.HelpText); + } + + [Fact] + public void TestBasicModelWithOverwritingUsingFluentApi() + { + var parser = new CommandLineParser(); + + parser.Configure(_ => _.Message) + .Required(false) + .HelpText("Different"); + + Assert.Equal(1, parser.Options.Count); + + var message = parser.Options[0]; + + Assert.NotNull(message); + + Assert.True(message.HasLongName && message.HasShortName); + + Assert.Equal("-m", message.ShortName); + Assert.Equal("--message", message.LongName); + + Assert.True(message.HasDefault); + Assert.False(message.IsRequired); + + Assert.Equal("Different", message.HelpText); + } + + private class Model + { + [Required, Name("-m", "--message"), DefaultValue("not found"), HelpText("Help")] + public string Message { get; set; } + } + } +} diff --git a/CommandLineParser.Tests/CommandLineParserTests.cs b/CommandLineParser.Tests/CommandLineParserTests.cs index 764e0e8..19eb85b 100644 --- a/CommandLineParser.Tests/CommandLineParserTests.cs +++ b/CommandLineParser.Tests/CommandLineParserTests.cs @@ -1,10 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; +using System.Threading; using MatthiWare.CommandLine; using Xunit; -using static MatthiWare.CommandLineParser.Tests.XUnitExtensions; namespace MatthiWare.CommandLineParser.Tests { @@ -16,7 +12,7 @@ public void ParseTests() var parser = new CommandLineParser(); parser.Configure(opt => opt.Option1) - .ShortName("-o") + .Name("-o") .Default("Default message") .Required(); @@ -38,17 +34,17 @@ public void ParseWithDefaults(string[] args, string result1, string result2, str var parser = new CommandLineParser(); parser.Configure(opt => opt.Option1) - .ShortName("-1") + .Name("-1") .Default(result1) .Required(); parser.Configure(opt => opt.Option2) - .ShortName("-2") + .Name("-2") .Default(result2) .Required(); parser.Configure(opt => opt.Option3) - .ShortName("-3") + .Name("-3") .Default(result3) .Required(); @@ -71,13 +67,12 @@ public void ParseWithCommandTests() var parser = new CommandLineParser(); parser.Configure(opt => opt.Option1) - .ShortName("-o") + .Name("-o") .Default("Default message") .Required(); var addCmd = parser.AddCommand() - .ShortName("-A") - .LongName("--Add") + .Name("-A", "--Add") .OnExecuting(x => { Assert.Equal("my message", x.Message); @@ -86,8 +81,7 @@ public void ParseWithCommandTests() addCmd.Configure(opt => opt.Message) - .LongName("--message") - .ShortName("-m") + .Name("-m", "--message") .Required(); var parsed = parser.Parse(new string[] { "app.exe", "-o", "test", "--Add", "-m", "my message" }); @@ -111,18 +105,15 @@ public void ParseCommandTests(string[] args, string result1, string result2) var parser = new CommandLineParser(); parser.AddCommand() - .LongName("--add") - .ShortName("-a") + .Name("-a", "--add") .Required() .OnExecuting(r => Assert.Equal(result2, r.Message)) .Configure(c => c.Message) - .LongName("--message") - .ShortName("-m") + .Name("-m", "--message") .Required(); parser.Configure(opt => opt.Message) - .LongName("--message") - .ShortName("-m") + .Name("-m", "--message") .Required(); var result = parser.Parse(args); @@ -140,14 +131,12 @@ public void ConfigureTests() var parser = new CommandLineParser(); parser.Configure(opt => opt.Option1) - .ShortName("-o") - .LongName("--opt") + .Name("-o", "--opt") .Default("Default message") .Required(); parser.Configure(opt => opt.Option2) - .ShortName("-x") - .LongName("--xsomething") + .Name("-x", "--xsomething") .Required(); Assert.Equal(2, parser.Options.Count); @@ -171,11 +160,13 @@ private class AddOption { public string Message { get; set; } } + private class Options { public string Option1 { get; set; } public bool Option2 { get; set; } } + private class OptionsWithThreeParams { public string Option1 { get; set; } diff --git a/CommandLineParser.Tests/ExtensionsTests.cs b/CommandLineParser.Tests/ExtensionsTests.cs deleted file mode 100644 index 921233b..0000000 --- a/CommandLineParser.Tests/ExtensionsTests.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using MatthiWare.CommandLine; -using MatthiWare.CommandLine.Abstractions.Parsing; -using MatthiWare.CommandLine.Core; -using Moq; -using Xunit; - -namespace MatthiWare.CommandLineParser.Tests -{ - public class ExtensionsTests - { - //[Fact] - //public void TestV1() - //{ - // var testString = "this is my test string \"with some quotes\" the end. '\"Here is some literal\"' "; - - // var resultArr = new string[] { "this", "is", "my", "test", "string", "with some quotes", "the", "end.", "\"Here is some literal\"", " " }; - - // int i = 0; - // foreach (var token in Extensions.SplitOnWhitespace(testString)) - // { - // Assert.Equal(resultArr[i++], token); - // } - - // Assert.Equal(resultArr.Length, i); - //} - - //[Theory] - //[InlineData("\"with some quotes\"", "with some quotes")] - //[InlineData("'\"with some quotes\"'", "\"with some quotes\"")] - //[InlineData("test", "test")] - //public void TestRemoveLiteralAndDoubleQuotes(string input, string result) - //{ - // Assert.Equal(result, input.AsSpan().RemoveLiteralsAndQuotes()); - //} - } -} diff --git a/CommandLineParser.Tests/OptionBuilderTest.cs b/CommandLineParser.Tests/OptionBuilderTest.cs index ce57bf8..1c62089 100644 --- a/CommandLineParser.Tests/OptionBuilderTest.cs +++ b/CommandLineParser.Tests/OptionBuilderTest.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; -using MatthiWare.CommandLine.Abstractions; +using MatthiWare.CommandLine.Abstractions; using MatthiWare.CommandLine.Abstractions.Parsing; using MatthiWare.CommandLine.Core; using Moq; @@ -11,13 +8,12 @@ namespace MatthiWare.CommandLineParser.Tests { public class OptionBuilderTest { - [Fact] public void OptionBuilderConfiguresOptionCorrectly() { var resolverMock = new Mock>(); - var option = new CommandLineOption(new object(), o => o.ToString(), resolverMock.Object); - var builder = option as IOptionBuilder; + var option = new CommandLineOption(new object(), XUnitExtensions.CreateLambda(o => o.ToString()), resolverMock.Object); + var builder = option as IOptionBuilder; string sDefault = "default"; string sHelp = "help"; @@ -27,8 +23,7 @@ public void OptionBuilderConfiguresOptionCorrectly() builder .Default(sDefault) .HelpText(sHelp) - .LongName(sLong) - .ShortName(sShort) + .Name(sShort, sLong) .Required(); Assert.True(option.HasDefault); @@ -41,7 +36,6 @@ public void OptionBuilderConfiguresOptionCorrectly() Assert.True(option.HasShortName); Assert.Equal(sShort, option.ShortName); - } } } \ No newline at end of file diff --git a/CommandLineParser.Tests/Parsing/ParserResultTest.cs b/CommandLineParser.Tests/Parsing/ParserResultTest.cs index e19c1d2..9f46bb1 100644 --- a/CommandLineParser.Tests/Parsing/ParserResultTest.cs +++ b/CommandLineParser.Tests/Parsing/ParserResultTest.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; using MatthiWare.CommandLine.Abstractions.Parsing.Command; using MatthiWare.CommandLine.Core.Parsing; using Moq; diff --git a/CommandLineParser.Tests/Parsing/ResolverFactoryTest.cs b/CommandLineParser.Tests/Parsing/ResolverFactoryTest.cs index 9c5e3c8..8124192 100644 --- a/CommandLineParser.Tests/Parsing/ResolverFactoryTest.cs +++ b/CommandLineParser.Tests/Parsing/ResolverFactoryTest.cs @@ -1,6 +1,5 @@ using System; -using System.Collections.Generic; -using System.Text; +using MatthiWare.CommandLine.Abstractions.Models; using MatthiWare.CommandLine.Abstractions.Parsing; using MatthiWare.CommandLine.Core.Parsing; using MatthiWare.CommandLine.Core.Parsing.Resolvers; @@ -12,7 +11,7 @@ namespace MatthiWare.CommandLineParser.Tests.Parsing public class ResolverFactoryTest { - private class RandomType { } + public class RandomType { } [Fact] public void ContainsWork() @@ -26,6 +25,30 @@ public void ContainsWork() Assert.False(factory.Contains()); } + [Fact] + public void RegisterAndGet() + { + var instance = new RandomType(); + + var mockResolver = new Mock>(); + mockResolver.Setup(_ => _.CanResolve(It.IsAny())).Returns(true); + mockResolver.Setup(_ => _.Resolve(It.IsAny())).Returns(instance); + + var factory = new ResolverFactory(); + + factory.Register(mockResolver.Object); + + var resolver = factory.CreateResolver(); + + var model = new ArgumentModel(); + + Assert.Same(mockResolver.Object, resolver); + Assert.True(resolver.CanResolve(model)); + Assert.Same(instance, resolver.Resolve(model)); + + mockResolver.VerifyAll(); + } + [Fact] public void RegisterOverrideWorks() { diff --git a/CommandLineParser.Tests/Parsing/Resolvers/BoolResolverTests.cs b/CommandLineParser.Tests/Parsing/Resolvers/BoolResolverTests.cs index 8d22617..e0e94bd 100644 --- a/CommandLineParser.Tests/Parsing/Resolvers/BoolResolverTests.cs +++ b/CommandLineParser.Tests/Parsing/Resolvers/BoolResolverTests.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; -using MatthiWare.CommandLine.Abstractions.Models; +using MatthiWare.CommandLine.Abstractions.Models; using MatthiWare.CommandLine.Core.Parsing.Resolvers; using Xunit; diff --git a/CommandLineParser.Tests/Parsing/Resolvers/DoubleResolverTests.cs b/CommandLineParser.Tests/Parsing/Resolvers/DoubleResolverTests.cs index da87dd1..ddd4197 100644 --- a/CommandLineParser.Tests/Parsing/Resolvers/DoubleResolverTests.cs +++ b/CommandLineParser.Tests/Parsing/Resolvers/DoubleResolverTests.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Text; -using MatthiWare.CommandLine.Abstractions.Models; +using MatthiWare.CommandLine.Abstractions.Models; using MatthiWare.CommandLine.Core.Parsing.Resolvers; using Xunit; diff --git a/CommandLineParser.Tests/Parsing/Resolvers/IntResolverTests.cs b/CommandLineParser.Tests/Parsing/Resolvers/IntResolverTests.cs index 258e9c9..6c4590f 100644 --- a/CommandLineParser.Tests/Parsing/Resolvers/IntResolverTests.cs +++ b/CommandLineParser.Tests/Parsing/Resolvers/IntResolverTests.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; -using MatthiWare.CommandLine.Abstractions.Models; +using MatthiWare.CommandLine.Abstractions.Models; using MatthiWare.CommandLine.Core.Parsing.Resolvers; using Xunit; diff --git a/CommandLineParser.Tests/Parsing/Resolvers/StringResovlerTests.cs b/CommandLineParser.Tests/Parsing/Resolvers/StringResovlerTests.cs index 3d326f7..6423d57 100644 --- a/CommandLineParser.Tests/Parsing/Resolvers/StringResovlerTests.cs +++ b/CommandLineParser.Tests/Parsing/Resolvers/StringResovlerTests.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; -using MatthiWare.CommandLine.Abstractions.Models; +using MatthiWare.CommandLine.Abstractions.Models; using MatthiWare.CommandLine.Core.Parsing.Resolvers; using Xunit; diff --git a/CommandLineParser.Tests/XUnitExtensions.cs b/CommandLineParser.Tests/XUnitExtensions.cs index 8722a82..62bb182 100644 --- a/CommandLineParser.Tests/XUnitExtensions.cs +++ b/CommandLineParser.Tests/XUnitExtensions.cs @@ -1,18 +1,17 @@ using System; -using System.Collections.Generic; -using System.Text; -using Xunit; +using System.Linq.Expressions; using Xunit.Sdk; namespace MatthiWare.CommandLineParser.Tests { public static class XUnitExtensions { - - public static void Fail(string reason) => throw new XunitException(reason); - + public static LambdaExpression CreateLambda(Expression> expression) + { + return expression; + } } } diff --git a/CommandLineParser/Abstractions/Command/ICommandBuilder'.cs b/CommandLineParser/Abstractions/Command/ICommandBuilder'.cs index 51b778d..b5faf2f 100644 --- a/CommandLineParser/Abstractions/Command/ICommandBuilder'.cs +++ b/CommandLineParser/Abstractions/Command/ICommandBuilder'.cs @@ -9,12 +9,12 @@ namespace MatthiWare.CommandLine.Abstractions.Command ICommandBuilder HelpText(string help); - ICommandBuilder ShortName(string shortName); + ICommandBuilder Name(string shortName); - ICommandBuilder LongName(string longName); + ICommandBuilder Name(string shortName, string longName); ICommandBuilder OnExecuting(Action action); - IOptionBuilder Configure(Expression> selector); + IOptionBuilder Configure(Expression> selector); } } diff --git a/CommandLineParser/Abstractions/Command/ICommandLineCommand.cs b/CommandLineParser/Abstractions/Command/ICommandLineCommand.cs index 59777de..db15e1b 100644 --- a/CommandLineParser/Abstractions/Command/ICommandLineCommand.cs +++ b/CommandLineParser/Abstractions/Command/ICommandLineCommand.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Text; - -namespace MatthiWare.CommandLine.Abstractions.Command +namespace MatthiWare.CommandLine.Abstractions.Command { public interface ICommandLineCommand { diff --git a/CommandLineParser/Abstractions/Command/ICommandLineCommandParser.cs b/CommandLineParser/Abstractions/Command/ICommandLineCommandParser.cs index 352d3dd..b6d2a9f 100644 --- a/CommandLineParser/Abstractions/Command/ICommandLineCommandParser.cs +++ b/CommandLineParser/Abstractions/Command/ICommandLineCommandParser.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; +using System.Collections.Generic; using MatthiWare.CommandLine.Abstractions.Parsing; using MatthiWare.CommandLine.Abstractions.Parsing.Command; diff --git a/CommandLineParser/Abstractions/ICommandLineOption'.cs b/CommandLineParser/Abstractions/ICommandLineOption'.cs deleted file mode 100644 index 004f8c2..0000000 --- a/CommandLineParser/Abstractions/ICommandLineOption'.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace MatthiWare.CommandLine.Abstractions -{ - public interface ICommandLineOption : ICommandLineOption - { - - TProperty DefaultValue { get; set; } - - } -} diff --git a/CommandLineParser/Abstractions/ICommandLineOption.cs b/CommandLineParser/Abstractions/ICommandLineOption.cs index 8cdeb65..c8c4d7a 100644 --- a/CommandLineParser/Abstractions/ICommandLineOption.cs +++ b/CommandLineParser/Abstractions/ICommandLineOption.cs @@ -1,7 +1,4 @@ using MatthiWare.CommandLine.Abstractions.Command; -using System; -using System.Collections.Generic; -using System.Text; namespace MatthiWare.CommandLine.Abstractions { diff --git a/CommandLineParser/Abstractions/ICommandLineParser'.cs b/CommandLineParser/Abstractions/ICommandLineParser'.cs index 612e702..c664248 100644 --- a/CommandLineParser/Abstractions/ICommandLineParser'.cs +++ b/CommandLineParser/Abstractions/ICommandLineParser'.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq.Expressions; -using System.Text; using MatthiWare.CommandLine.Abstractions.Command; using MatthiWare.CommandLine.Abstractions.Parsing; @@ -27,7 +25,7 @@ public interface ICommandLineParser #region Configuration - IOptionBuilder Configure(Expression> selector); + IOptionBuilder Configure(Expression> selector); ICommandBuilder AddCommand() where TCommandOption : class, new(); diff --git a/CommandLineParser/Abstractions/IOptionBuilder'.cs b/CommandLineParser/Abstractions/IOptionBuilder'.cs index d3145b0..86fca91 100644 --- a/CommandLineParser/Abstractions/IOptionBuilder'.cs +++ b/CommandLineParser/Abstractions/IOptionBuilder'.cs @@ -1,19 +1,15 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace MatthiWare.CommandLine.Abstractions +namespace MatthiWare.CommandLine.Abstractions { - public interface IOptionBuilder + public interface IOptionBuilder { - IOptionBuilder Required(bool required = true); + IOptionBuilder Required(bool required = true); - IOptionBuilder HelpText(string help); + IOptionBuilder HelpText(string help); - IOptionBuilder Default(TProperty defaultValue = default(TProperty)); + IOptionBuilder Default(object defaultValue); - IOptionBuilder ShortName(string shortName); + IOptionBuilder Name(string shortName); - IOptionBuilder LongName(string longName); + IOptionBuilder Name(string shortName, string longName); } } diff --git a/CommandLineParser/Abstractions/Models/ArgumentModel.cs b/CommandLineParser/Abstractions/Models/ArgumentModel.cs index 2ed2f9c..d3ffa45 100644 --- a/CommandLineParser/Abstractions/Models/ArgumentModel.cs +++ b/CommandLineParser/Abstractions/Models/ArgumentModel.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace MatthiWare.CommandLine.Abstractions.Models +namespace MatthiWare.CommandLine.Abstractions.Models { public struct ArgumentModel { diff --git a/CommandLineParser/Abstractions/Parsing/Command/ICommandParserResult.cs b/CommandLineParser/Abstractions/Parsing/Command/ICommandParserResult.cs index a0818f0..e7914a8 100644 --- a/CommandLineParser/Abstractions/Parsing/Command/ICommandParserResult.cs +++ b/CommandLineParser/Abstractions/Parsing/Command/ICommandParserResult.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; namespace MatthiWare.CommandLine.Abstractions.Parsing.Command { diff --git a/CommandLineParser/Abstractions/Parsing/IArgumentManager.cs b/CommandLineParser/Abstractions/Parsing/IArgumentManager.cs index a0dcd85..03a9ece 100644 --- a/CommandLineParser/Abstractions/Parsing/IArgumentManager.cs +++ b/CommandLineParser/Abstractions/Parsing/IArgumentManager.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; -using MatthiWare.CommandLine.Abstractions.Command; +using MatthiWare.CommandLine.Abstractions.Command; using MatthiWare.CommandLine.Abstractions.Models; namespace MatthiWare.CommandLine.Abstractions.Parsing diff --git a/CommandLineParser/Abstractions/Parsing/ICommandLineArgumentResolver.cs b/CommandLineParser/Abstractions/Parsing/ICommandLineArgumentResolver.cs index 33d21eb..560abf1 100644 --- a/CommandLineParser/Abstractions/Parsing/ICommandLineArgumentResolver.cs +++ b/CommandLineParser/Abstractions/Parsing/ICommandLineArgumentResolver.cs @@ -1,17 +1,16 @@ -using System; -using System.Collections.Generic; -using System.Text; -using MatthiWare.CommandLine.Abstractions.Models; -using MatthiWare.CommandLine.Core.Parsing; +using MatthiWare.CommandLine.Abstractions.Models; namespace MatthiWare.CommandLine.Abstractions.Parsing { - public interface ICommandLineArgumentResolver + public interface ICommandLineArgumentResolver { - bool CanResolve(ArgumentModel model); - T Resolve(ArgumentModel model); + object Resolve(ArgumentModel model); + } + public interface ICommandLineArgumentResolver : ICommandLineArgumentResolver + { + new T Resolve(ArgumentModel model); } } diff --git a/CommandLineParser/Abstractions/Parsing/IParser.cs b/CommandLineParser/Abstractions/Parsing/IParser.cs index d1d9557..1cbcec3 100644 --- a/CommandLineParser/Abstractions/Parsing/IParser.cs +++ b/CommandLineParser/Abstractions/Parsing/IParser.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; -using MatthiWare.CommandLine.Abstractions.Models; +using MatthiWare.CommandLine.Abstractions.Models; namespace MatthiWare.CommandLine.Abstractions.Parsing { diff --git a/CommandLineParser/Abstractions/Parsing/IParserResult.cs b/CommandLineParser/Abstractions/Parsing/IParserResult.cs index c19b9fb..35bf025 100644 --- a/CommandLineParser/Abstractions/Parsing/IParserResult.cs +++ b/CommandLineParser/Abstractions/Parsing/IParserResult.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Text; using MatthiWare.CommandLine.Abstractions.Parsing.Command; namespace MatthiWare.CommandLine.Abstractions.Parsing diff --git a/CommandLineParser/Abstractions/Parsing/IResolverFactory.cs b/CommandLineParser/Abstractions/Parsing/IResolverFactory.cs index bf05763..ecf3190 100644 --- a/CommandLineParser/Abstractions/Parsing/IResolverFactory.cs +++ b/CommandLineParser/Abstractions/Parsing/IResolverFactory.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; namespace MatthiWare.CommandLine.Abstractions.Parsing { @@ -16,5 +14,7 @@ public interface IResolverFactory ICommandLineArgumentResolver CreateResolver(); + ICommandLineArgumentResolver CreateResolver(Type type); + } } diff --git a/CommandLineParser/CommandLineParser.cs b/CommandLineParser/CommandLineParser.cs index 37baa98..ad0521f 100644 --- a/CommandLineParser/CommandLineParser.cs +++ b/CommandLineParser/CommandLineParser.cs @@ -2,12 +2,14 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; +using System.Reflection; using System.Runtime.CompilerServices; using MatthiWare.CommandLine.Abstractions; using MatthiWare.CommandLine.Abstractions.Command; using MatthiWare.CommandLine.Abstractions.Models; using MatthiWare.CommandLine.Abstractions.Parsing; using MatthiWare.CommandLine.Core; +using MatthiWare.CommandLine.Core.Attributes; using MatthiWare.CommandLine.Core.Command; using MatthiWare.CommandLine.Core.Exceptions; using MatthiWare.CommandLine.Core.Parsing; @@ -19,10 +21,10 @@ namespace MatthiWare.CommandLine public sealed class CommandLineParser : ICommandLineParser where TSource : class, new() { private readonly TSource m_option; - private readonly List m_options; + private readonly Dictionary m_options; private readonly List m_commands; - public IReadOnlyList Options => m_options.AsReadOnly(); + public IReadOnlyList Options => new ReadOnlyCollectionWrapper(m_options.Values); public IResolverFactory ResolverFactory { get; } @@ -32,22 +34,32 @@ public CommandLineParser() { m_option = new TSource(); - m_options = new List(); + m_options = new Dictionary(); m_commands = new List(); ResolverFactory = new ResolverFactory(); + + InitialzeModel(); } - public IOptionBuilder Configure(Expression> selector) - => ConfigureInternal(selector); + public IOptionBuilder Configure(Expression> selector) + { + var memberInfo = ((MemberExpression)selector.Body).Member; + var key = $"{memberInfo.DeclaringType.FullName}.{memberInfo.Name}"; + + return ConfigureInternal(selector, key); + } - private IOptionBuilder ConfigureInternal(Expression> selector) + private IOptionBuilder ConfigureInternal(LambdaExpression selector, string key) { - var option = new CommandLineOption(m_option, selector, ResolverFactory.CreateResolver()); + if (!m_options.ContainsKey(key)) + { + var option = new CommandLineOption(m_option, selector, ResolverFactory.CreateResolver(selector.ReturnType)); - m_options.Add(option); + m_options.Add(key, option); + } - return option; + return m_options[key] as IOptionBuilder; } public IParserResult Parse(string[] args) @@ -56,7 +68,7 @@ public IParserResult Parse(string[] args) var result = new ParseResult(); - var argumentManager = new ArgumentManager(args, m_commands, m_options); + var argumentManager = new ArgumentManager(args, m_commands, m_options.Values); foreach (var cmd in m_commands) { @@ -75,8 +87,10 @@ public IParserResult Parse(string[] args) result.MergeResult(cmdParseResult); } - foreach (var option in m_options) + foreach (var o in m_options) { + var option = o.Value; + if (!argumentManager.TryGetValue(option, out ArgumentModel model) && option.IsRequired) { errors.Add(new OptionNotFoundException(option)); @@ -115,5 +129,52 @@ public IParserResult Parse(string[] args) return command; } + + private void InitialzeModel() + { + var properties = typeof(TSource).GetProperties(); + + foreach (var propInfo in properties) + { + var attributes = propInfo.GetCustomAttributes(true); + + var lambda = GetLambdaExpression(propInfo, out string key); + + foreach (var attribute in attributes) + { + switch (attribute) + { + case RequiredAttribute required: + ConfigureInternal(lambda, key).Required(required.Required); + + break; + case DefaultValueAttribute defaultValue: + ConfigureInternal(lambda, key).Default(defaultValue.DefaultValue); + + break; + case HelpTextAttribute helpText: + ConfigureInternal(lambda, key).HelpText(helpText.HelpText); + break; + case NameAttribute name: + ConfigureInternal(lambda, key).Name(name.ShortName, name.LongName); + + break; + } + } + } + + LambdaExpression GetLambdaExpression(PropertyInfo propInfo, out string key) + { + var entityType = propInfo.DeclaringType; + var propType = propInfo.PropertyType; + var parameter = Expression.Parameter(entityType, entityType.FullName); + var property = Expression.Property(parameter, propInfo); + var funcType = typeof(Func<,>).MakeGenericType(entityType, propType); + + key = $"{entityType.ToString()}.{propInfo.Name}"; + + return Expression.Lambda(funcType, property, parameter); + } + } } } diff --git a/CommandLineParser/Core/Attributes/BaseAttribute.cs b/CommandLineParser/Core/Attributes/BaseAttribute.cs new file mode 100644 index 0000000..d29b76f --- /dev/null +++ b/CommandLineParser/Core/Attributes/BaseAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace MatthiWare.CommandLine.Core.Attributes +{ + [AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)] + public abstract class BaseAttribute : Attribute + { + } +} diff --git a/CommandLineParser/Core/Attributes/DefaultValueAttribute.cs b/CommandLineParser/Core/Attributes/DefaultValueAttribute.cs new file mode 100644 index 0000000..c96c51a --- /dev/null +++ b/CommandLineParser/Core/Attributes/DefaultValueAttribute.cs @@ -0,0 +1,9 @@ +namespace MatthiWare.CommandLine.Core.Attributes +{ + public class DefaultValueAttribute : BaseAttribute + { + public object DefaultValue { get; private set; } + + public DefaultValueAttribute(object defaultValue) => DefaultValue = defaultValue; + } +} diff --git a/CommandLineParser/Core/Attributes/HelpTextAttribute.cs b/CommandLineParser/Core/Attributes/HelpTextAttribute.cs new file mode 100644 index 0000000..d4c8848 --- /dev/null +++ b/CommandLineParser/Core/Attributes/HelpTextAttribute.cs @@ -0,0 +1,9 @@ +namespace MatthiWare.CommandLine.Core.Attributes +{ + public class HelpTextAttribute : BaseAttribute + { + public string HelpText { get; private set; } + + public HelpTextAttribute(string helpText) => HelpText = helpText; + } +} diff --git a/CommandLineParser/Core/Attributes/NameAttribute.cs b/CommandLineParser/Core/Attributes/NameAttribute.cs new file mode 100644 index 0000000..a298085 --- /dev/null +++ b/CommandLineParser/Core/Attributes/NameAttribute.cs @@ -0,0 +1,18 @@ +namespace MatthiWare.CommandLine.Core.Attributes +{ + public class NameAttribute : BaseAttribute + { + public string ShortName { get; private set; } + public string LongName { get; private set; } + + public NameAttribute(string shortName) + : this(shortName, string.Empty) + { } + + public NameAttribute(string shortName, string longName) + { + ShortName = shortName; + LongName = longName; + } + } +} diff --git a/CommandLineParser/Core/Attributes/RequiredAttribute.cs b/CommandLineParser/Core/Attributes/RequiredAttribute.cs new file mode 100644 index 0000000..193c1fe --- /dev/null +++ b/CommandLineParser/Core/Attributes/RequiredAttribute.cs @@ -0,0 +1,9 @@ +namespace MatthiWare.CommandLine.Core.Attributes +{ + public class RequiredAttribute : BaseAttribute + { + public bool Required { get; private set; } + + public RequiredAttribute(bool required = true) => Required = required; + } +} diff --git a/CommandLineParser/Core/Command/CommandLineCommand.cs b/CommandLineParser/Core/Command/CommandLineCommand.cs index 9956e81..2e38964 100644 --- a/CommandLineParser/Core/Command/CommandLineCommand.cs +++ b/CommandLineParser/Core/Command/CommandLineCommand.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Linq.Expressions; using MatthiWare.CommandLine.Abstractions; using MatthiWare.CommandLine.Abstractions.Command; @@ -25,9 +24,9 @@ public CommandLineCommand(IResolverFactory resolverFactory) source = new TSource(); } - public IOptionBuilder Configure(Expression> selector) + public IOptionBuilder Configure(Expression> selector) { - var option = new CommandLineOption(source, selector, resolverFactory.CreateResolver()); + var option = new CommandLineOption(source, selector, resolverFactory.CreateResolver()); m_options.Add(option); @@ -91,16 +90,17 @@ ICommandBuilder ICommandBuilder.HelpText(string help) return this; } - ICommandBuilder ICommandBuilder.LongName(string longName) + ICommandBuilder ICommandBuilder.Name(string shortName) { - LongName = longName; + ShortName = shortName; return this; } - ICommandBuilder ICommandBuilder.ShortName(string shortName) + ICommandBuilder ICommandBuilder.Name(string shortName, string longName) { ShortName = shortName; + LongName = longName; return this; } diff --git a/CommandLineParser/Core/Command/CommandLineCommandBase.cs b/CommandLineParser/Core/Command/CommandLineCommandBase.cs index da8ba56..5c627bb 100644 --- a/CommandLineParser/Core/Command/CommandLineCommandBase.cs +++ b/CommandLineParser/Core/Command/CommandLineCommandBase.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; +using System.Collections.Generic; using MatthiWare.CommandLine.Abstractions; using MatthiWare.CommandLine.Abstractions.Command; using MatthiWare.CommandLine.Abstractions.Parsing; diff --git a/CommandLineParser/Core/CommandLineOption.cs b/CommandLineParser/Core/CommandLineOption.cs index 6c6b37d..65ebd1c 100644 --- a/CommandLineParser/Core/CommandLineOption.cs +++ b/CommandLineParser/Core/CommandLineOption.cs @@ -7,24 +7,24 @@ namespace MatthiWare.CommandLine.Core { - internal class CommandLineOption : + internal class CommandLineOption : CommandLineOptionBase, - ICommandLineOption, - IOptionBuilder where TSource : class + ICommandLineOption, + IOptionBuilder { - private readonly TSource source; - private readonly Expression> selector; - private TProperty m_defaultValue = default(TProperty); - private readonly ICommandLineArgumentResolver resolver; + private readonly object source; + private readonly LambdaExpression selector; + private object m_defaultValue = null; + private readonly ICommandLineArgumentResolver resolver; - public CommandLineOption(TSource source, Expression> selector, ICommandLineArgumentResolver resolver) + public CommandLineOption(object source, LambdaExpression selector, ICommandLineArgumentResolver resolver) { this.source = source ?? throw new ArgumentNullException(nameof(source)); this.selector = selector ?? throw new ArgumentNullException(nameof(selector)); this.resolver = resolver ?? throw new ArgumentNullException(nameof(resolver)); } - public TProperty DefaultValue + public object DefaultValue { get => m_defaultValue; set @@ -43,42 +43,43 @@ public override bool CanParse(ArgumentModel model) public override void Parse(ArgumentModel model) => AssignValue(resolver.Resolve(model)); - IOptionBuilder IOptionBuilder.Default(TProperty defaultValue) + IOptionBuilder IOptionBuilder.Default(object defaultValue) { DefaultValue = defaultValue; return this; } - IOptionBuilder IOptionBuilder.HelpText(string help) + IOptionBuilder IOptionBuilder.HelpText(string help) { HelpText = help; return this; } - IOptionBuilder IOptionBuilder.LongName(string longName) + IOptionBuilder IOptionBuilder.Name(string shortName, string longName) { LongName = longName; + ShortName = shortName; return this; } - IOptionBuilder IOptionBuilder.Required(bool required = true) + IOptionBuilder IOptionBuilder.Required(bool required = true) { IsRequired = required; return this; } - IOptionBuilder IOptionBuilder.ShortName(string shortName) + IOptionBuilder IOptionBuilder.Name(string shortName) { ShortName = shortName; return this; } - private void AssignValue(TProperty value) + private void AssignValue(object value) { var property = (PropertyInfo)((MemberExpression)selector.Body).Member; property.SetValue(source, value, null); diff --git a/CommandLineParser/Core/CommandLineOptionBase.cs b/CommandLineParser/Core/CommandLineOptionBase.cs index 18f3963..1ae7faf 100644 --- a/CommandLineParser/Core/CommandLineOptionBase.cs +++ b/CommandLineParser/Core/CommandLineOptionBase.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; +using System.Diagnostics; using MatthiWare.CommandLine.Abstractions; using MatthiWare.CommandLine.Abstractions.Models; using MatthiWare.CommandLine.Abstractions.Parsing; diff --git a/CommandLineParser/Core/Exceptions/CommandNotFoundException.cs b/CommandLineParser/Core/Exceptions/CommandNotFoundException.cs index 6e3eceb..8fe544c 100644 --- a/CommandLineParser/Core/Exceptions/CommandNotFoundException.cs +++ b/CommandLineParser/Core/Exceptions/CommandNotFoundException.cs @@ -1,7 +1,5 @@ using MatthiWare.CommandLine.Abstractions.Command; -using System; using System.Collections.Generic; -using System.Text; namespace MatthiWare.CommandLine.Core.Exceptions { diff --git a/CommandLineParser/Core/Exceptions/CommandParseException.cs b/CommandLineParser/Core/Exceptions/CommandParseException.cs index b710545..c96807d 100644 --- a/CommandLineParser/Core/Exceptions/CommandParseException.cs +++ b/CommandLineParser/Core/Exceptions/CommandParseException.cs @@ -1,10 +1,5 @@ -using MatthiWare.CommandLine.Abstractions; -using MatthiWare.CommandLine.Abstractions.Command; -using MatthiWare.CommandLine.Abstractions.Models; -using MatthiWare.CommandLine.Core.Command; +using MatthiWare.CommandLine.Abstractions.Command; using System; -using System.Collections.Generic; -using System.Text; namespace MatthiWare.CommandLine.Core.Exceptions { diff --git a/CommandLineParser/Core/Exceptions/OptionNotFoundException.cs b/CommandLineParser/Core/Exceptions/OptionNotFoundException.cs index e2ca11a..43b519f 100644 --- a/CommandLineParser/Core/Exceptions/OptionNotFoundException.cs +++ b/CommandLineParser/Core/Exceptions/OptionNotFoundException.cs @@ -1,7 +1,5 @@ using MatthiWare.CommandLine.Abstractions; -using System; using System.Collections.Generic; -using System.Text; namespace MatthiWare.CommandLine.Core.Exceptions { diff --git a/CommandLineParser/Core/Exceptions/OptionParseException.cs b/CommandLineParser/Core/Exceptions/OptionParseException.cs index d972f2a..af2bc97 100644 --- a/CommandLineParser/Core/Exceptions/OptionParseException.cs +++ b/CommandLineParser/Core/Exceptions/OptionParseException.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; using MatthiWare.CommandLine.Abstractions; using MatthiWare.CommandLine.Abstractions.Models; diff --git a/CommandLineParser/Core/Extensions.cs b/CommandLineParser/Core/Extensions.cs deleted file mode 100644 index 6fde1e5..0000000 --- a/CommandLineParser/Core/Extensions.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace MatthiWare.CommandLine.Core -{ - internal static class Extensions - { - public static T GetAndRemove(this IList src, int index) - { - if (index < 0 || index > src.Count) return default(T); - - T item = src[index]; - - src.RemoveAt(index); - - return item; - } - - public static ReadOnlySpan Substring(this ReadOnlySpan src, int start, int len) - { - if (src.IsEmpty) return src; - - return src.Slice(start, len); - } - - } -} diff --git a/CommandLineParser/Core/Parsing/ArgumentManager.cs b/CommandLineParser/Core/Parsing/ArgumentManager.cs index 5519644..a4c650c 100644 --- a/CommandLineParser/Core/Parsing/ArgumentManager.cs +++ b/CommandLineParser/Core/Parsing/ArgumentManager.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using MatthiWare.CommandLine.Abstractions; using MatthiWare.CommandLine.Abstractions.Command; using MatthiWare.CommandLine.Abstractions.Models; using MatthiWare.CommandLine.Abstractions.Parsing; diff --git a/CommandLineParser/Core/Parsing/ResolverFactory.cs b/CommandLineParser/Core/Parsing/ResolverFactory.cs index 30b3bcc..a1f21fb 100644 --- a/CommandLineParser/Core/Parsing/ResolverFactory.cs +++ b/CommandLineParser/Core/Parsing/ResolverFactory.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Text; using MatthiWare.CommandLine.Abstractions.Parsing; using MatthiWare.CommandLine.Core.Parsing.Resolvers; @@ -27,16 +26,31 @@ public bool Contains(Type argument) public ICommandLineArgumentResolver CreateResolver() { - Type argType = typeof(T); + return (ICommandLineArgumentResolver)CreateResolver(typeof(T)); + } - if (!m_cache.ContainsKey(argType)) + public ICommandLineArgumentResolver CreateResolver(Type type) + { + if (!m_cache.ContainsKey(type)) { - var instance = (ICommandLineArgumentResolver)Activator.CreateInstance(m_types[argType]); + var instance = (ICommandLineArgumentResolver)Activator.CreateInstance(m_types[type]); - m_cache.Add(argType, instance); + m_cache.Add(type, instance); } - return (ICommandLineArgumentResolver)m_cache[argType]; + return (ICommandLineArgumentResolver)m_cache[type]; + } + + public void Register(ICommandLineArgumentResolver resolverInstance, bool overwrite = false) + { + Register>(overwrite); + + var typeKey = typeof(TArgument); + + if (overwrite && m_cache.ContainsKey(typeKey)) + m_cache.Remove(typeKey); + + m_cache.Add(typeKey, resolverInstance); } public void Register(bool overwrite = false) where TResolver : ICommandLineArgumentResolver diff --git a/CommandLineParser/Core/Parsing/Resolvers/BoolResolver.cs b/CommandLineParser/Core/Parsing/Resolvers/BoolResolver.cs index 4881174..a8314ec 100644 --- a/CommandLineParser/Core/Parsing/Resolvers/BoolResolver.cs +++ b/CommandLineParser/Core/Parsing/Resolvers/BoolResolver.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; using System.Linq; -using System.Text; using MatthiWare.CommandLine.Abstractions.Models; using MatthiWare.CommandLine.Abstractions.Parsing; @@ -21,6 +19,8 @@ public bool Resolve(ArgumentModel model) return result; } + object ICommandLineArgumentResolver.Resolve(ArgumentModel model) => Resolve(model); + private bool TryParse(ArgumentModel model, out bool result) { if (!model.HasValue) diff --git a/CommandLineParser/Core/Parsing/Resolvers/DoubleResolver.cs b/CommandLineParser/Core/Parsing/Resolvers/DoubleResolver.cs index bf916dc..7cad2f9 100644 --- a/CommandLineParser/Core/Parsing/Resolvers/DoubleResolver.cs +++ b/CommandLineParser/Core/Parsing/Resolvers/DoubleResolver.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Text; +using System.Globalization; using MatthiWare.CommandLine.Abstractions.Models; using MatthiWare.CommandLine.Abstractions.Parsing; @@ -23,6 +20,8 @@ public double Resolve(ArgumentModel model) return result; } + object ICommandLineArgumentResolver.Resolve(ArgumentModel model) => Resolve(model); + private bool TryResolve(ArgumentModel model, out double result) { if (!model.HasValue) diff --git a/CommandLineParser/Core/Parsing/Resolvers/IntResolver.cs b/CommandLineParser/Core/Parsing/Resolvers/IntResolver.cs index 2801060..7f66874 100644 --- a/CommandLineParser/Core/Parsing/Resolvers/IntResolver.cs +++ b/CommandLineParser/Core/Parsing/Resolvers/IntResolver.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; -using MatthiWare; -using MatthiWare.CommandLine.Abstractions.Models; +using MatthiWare.CommandLine.Abstractions.Models; using MatthiWare.CommandLine.Abstractions.Parsing; namespace MatthiWare.CommandLine.Core.Parsing.Resolvers @@ -23,6 +19,8 @@ public int Resolve(ArgumentModel model) return result; } + object ICommandLineArgumentResolver.Resolve(ArgumentModel model) => Resolve(model); + private bool TryResolve(ArgumentModel model, out int result) { if (!model.HasValue) diff --git a/CommandLineParser/Core/Parsing/Resolvers/StringResolver.cs b/CommandLineParser/Core/Parsing/Resolvers/StringResolver.cs index 8d4db2d..82fbe55 100644 --- a/CommandLineParser/Core/Parsing/Resolvers/StringResolver.cs +++ b/CommandLineParser/Core/Parsing/Resolvers/StringResolver.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using MatthiWare.CommandLine.Abstractions.Models; +using MatthiWare.CommandLine.Abstractions.Models; using MatthiWare.CommandLine.Abstractions.Parsing; namespace MatthiWare.CommandLine.Core.Parsing.Resolvers @@ -11,7 +7,8 @@ internal class StringResolver : ICommandLineArgumentResolver { public bool CanResolve(ArgumentModel model) => true; - public string Resolve(ArgumentModel model) - => model.HasValue ? model.Value : null; + public string Resolve(ArgumentModel model) => model.HasValue ? model.Value : null; + + object ICommandLineArgumentResolver.Resolve(ArgumentModel model) => Resolve(model); } } diff --git a/CommandLineParser/Core/ReadOnlyCollectionWrapper.cs b/CommandLineParser/Core/ReadOnlyCollectionWrapper.cs new file mode 100644 index 0000000..c713b0e --- /dev/null +++ b/CommandLineParser/Core/ReadOnlyCollectionWrapper.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace MatthiWare.CommandLine.Core +{ + internal class ReadOnlyCollectionWrapper : IReadOnlyList + { + private readonly Dictionary.ValueCollection values; + + public ReadOnlyCollectionWrapper(Dictionary.ValueCollection values) + { + this.values = values; + } + + public TValue this[int index] => FindFirstIndex(GetEnumerator(), index); + + public int Count => values.Count; + + public IEnumerator GetEnumerator() => values.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + private TValue FindFirstIndex(IEnumerator enumerator, int index) + { + int i = 0; + while (enumerator.MoveNext()) + { + if (i == index) + return enumerator.Current; + + i++; + } + + throw new IndexOutOfRangeException(); + } + } +} diff --git a/SampleApp/Program.cs b/SampleApp/Program.cs index 9181d81..3b6e772 100644 --- a/SampleApp/Program.cs +++ b/SampleApp/Program.cs @@ -11,23 +11,19 @@ static int Main(string[] args) // setup parser.Configure(opt => opt.MyInt) - .ShortName("-i") - .LongName("--int") + .Name("-i", "--int") .Required(); parser.Configure(opt => opt.MyString) - .ShortName("-s") - .LongName("--string") + .Name("-s", "--string") .Required(); parser.Configure(opt => opt.MyBool) - .ShortName("-b") - .LongName("--bool") + .Name("-b", "--bool") .Required(); parser.Configure(opt => opt.MyDouble) - .ShortName("-d") - .LongName("--double") + .Name("-d", "--double") .Required(); var result = parser.Parse(args); From 9fdc46ac706ccaad7851c0f9f60132fb5d10c14f Mon Sep 17 00:00:00 2001 From: Matthias Beerens <3512339+Matthiee@users.noreply.github.com> Date: Sun, 25 Nov 2018 16:44:34 +0100 Subject: [PATCH 04/10] Fix codefactor warnings --- CommandLineParser.Tests/Parsing/ResolverFactoryTest.cs | 4 +--- CommandLineParser/Abstractions/ICommandLineParser'.cs | 2 -- CommandLineParser/Abstractions/Models/ArgumentModel.cs | 1 - CommandLineParser/Abstractions/Parsing/IResolverFactory.cs | 1 - CommandLineParser/Core/Command/CommandLineCommand.cs | 2 -- 5 files changed, 1 insertion(+), 9 deletions(-) diff --git a/CommandLineParser.Tests/Parsing/ResolverFactoryTest.cs b/CommandLineParser.Tests/Parsing/ResolverFactoryTest.cs index 8124192..412b6b9 100644 --- a/CommandLineParser.Tests/Parsing/ResolverFactoryTest.cs +++ b/CommandLineParser.Tests/Parsing/ResolverFactoryTest.cs @@ -10,7 +10,6 @@ namespace MatthiWare.CommandLineParser.Tests.Parsing { public class ResolverFactoryTest { - public class RandomType { } [Fact] @@ -33,7 +32,7 @@ public void RegisterAndGet() var mockResolver = new Mock>(); mockResolver.Setup(_ => _.CanResolve(It.IsAny())).Returns(true); mockResolver.Setup(_ => _.Resolve(It.IsAny())).Returns(instance); - + var factory = new ResolverFactory(); factory.Register(mockResolver.Object); @@ -69,6 +68,5 @@ public void RegisterThrowsException() Assert.Throws(() => factory.Register()); } - } } diff --git a/CommandLineParser/Abstractions/ICommandLineParser'.cs b/CommandLineParser/Abstractions/ICommandLineParser'.cs index c664248..fef0bc5 100644 --- a/CommandLineParser/Abstractions/ICommandLineParser'.cs +++ b/CommandLineParser/Abstractions/ICommandLineParser'.cs @@ -8,7 +8,6 @@ namespace MatthiWare.CommandLine.Abstractions { public interface ICommandLineParser { - #region Properties IReadOnlyList Commands { get; } @@ -30,6 +29,5 @@ public interface ICommandLineParser ICommandBuilder AddCommand() where TCommandOption : class, new(); #endregion - } } diff --git a/CommandLineParser/Abstractions/Models/ArgumentModel.cs b/CommandLineParser/Abstractions/Models/ArgumentModel.cs index d3ffa45..2e2184c 100644 --- a/CommandLineParser/Abstractions/Models/ArgumentModel.cs +++ b/CommandLineParser/Abstractions/Models/ArgumentModel.cs @@ -19,6 +19,5 @@ public ArgumentModel(string key) this.Key = key; this.Value = null; } - } } diff --git a/CommandLineParser/Abstractions/Parsing/IResolverFactory.cs b/CommandLineParser/Abstractions/Parsing/IResolverFactory.cs index ecf3190..0f5dc26 100644 --- a/CommandLineParser/Abstractions/Parsing/IResolverFactory.cs +++ b/CommandLineParser/Abstractions/Parsing/IResolverFactory.cs @@ -15,6 +15,5 @@ public interface IResolverFactory ICommandLineArgumentResolver CreateResolver(); ICommandLineArgumentResolver CreateResolver(Type type); - } } diff --git a/CommandLineParser/Core/Command/CommandLineCommand.cs b/CommandLineParser/Core/Command/CommandLineCommand.cs index 2e38964..9400bdb 100644 --- a/CommandLineParser/Core/Command/CommandLineCommand.cs +++ b/CommandLineParser/Core/Command/CommandLineCommand.cs @@ -104,7 +104,5 @@ ICommandBuilder ICommandBuilder.Name(string shortName, string return this; } - - } } From 15115040d9e7df672413b0db5349c7fe03a2885c Mon Sep 17 00:00:00 2001 From: Matthias Beerens <3512339+Matthiee@users.noreply.github.com> Date: Sun, 25 Nov 2018 20:15:32 +0100 Subject: [PATCH 05/10] Add nuspec --- CommandLineParser/CommandLineParser.nuspec | 18 ++++++++++++++++++ build.cake | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 CommandLineParser/CommandLineParser.nuspec diff --git a/CommandLineParser/CommandLineParser.nuspec b/CommandLineParser/CommandLineParser.nuspec new file mode 100644 index 0000000..639915e --- /dev/null +++ b/CommandLineParser/CommandLineParser.nuspec @@ -0,0 +1,18 @@ + + + + $id$ + $version$ + $title$ + $author$ + $author$ + http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE + http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE + http://ICON_URL_HERE_OR_DELETE_THIS_LINE + false + $description$ + Summary of changes made in this release of the package. + Copyright 2018 + Tag1 Tag2 + + \ No newline at end of file diff --git a/build.cake b/build.cake index 86732c5..cd3c85b 100644 --- a/build.cake +++ b/build.cake @@ -12,7 +12,7 @@ var configuration = Argument("configuration", "Release"); var project = "CommandLineParser"; var solution = $"./{project}.sln"; -var commandLineParserProjPath = $"./{project}/{project}.csproj"; +var commandLineParserProjPath = $"./{project}/{project}/{project}.nuspec"; var tests = $"./{project}.Tests/{project}.Tests.csproj"; var publishPath = MakeAbsolute(Directory("./output")); var nugetPackageDir = MakeAbsolute(Directory("./nuget")); From 402891acf8cc65801e29ebfd4f4e02bf552078e9 Mon Sep 17 00:00:00 2001 From: Matthias Beerens <3512339+Matthiee@users.noreply.github.com> Date: Sun, 25 Nov 2018 20:26:05 +0100 Subject: [PATCH 06/10] Update reference --- build.cake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cake b/build.cake index cd3c85b..18edf47 100644 --- a/build.cake +++ b/build.cake @@ -12,7 +12,7 @@ var configuration = Argument("configuration", "Release"); var project = "CommandLineParser"; var solution = $"./{project}.sln"; -var commandLineParserProjPath = $"./{project}/{project}/{project}.nuspec"; +var commandLineParserProjPath = $"./{project}/{project}.nuspec"; var tests = $"./{project}.Tests/{project}.Tests.csproj"; var publishPath = MakeAbsolute(Directory("./output")); var nugetPackageDir = MakeAbsolute(Directory("./nuget")); From a2a862637c18a840e26f39cc045859575493adcd Mon Sep 17 00:00:00 2001 From: Matthias Beerens <3512339+Matthiee@users.noreply.github.com> Date: Tue, 27 Nov 2018 21:17:39 +0100 Subject: [PATCH 07/10] Add logging --- build.cake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.cake b/build.cake index 18edf47..db99c44 100644 --- a/build.cake +++ b/build.cake @@ -73,6 +73,9 @@ Task("Publish-NuGet") .IsDependentOn("Publish") .Does(() => { + Information($"nuget package dir: {nugetPackageDir}"); + Information($"nuspec: {commandLineParserProjPath}"); + var nuGetPackSettings = new NuGetPackSettings { BasePath = publishPath, From 325a69102defd852c060bea293af260de90d9c7a Mon Sep 17 00:00:00 2001 From: Matthias Beerens <3512339+Matthiee@users.noreply.github.com> Date: Tue, 27 Nov 2018 21:41:56 +0100 Subject: [PATCH 08/10] pack options --- build.cake | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/build.cake b/build.cake index db99c44..b457deb 100644 --- a/build.cake +++ b/build.cake @@ -12,7 +12,7 @@ var configuration = Argument("configuration", "Release"); var project = "CommandLineParser"; var solution = $"./{project}.sln"; -var commandLineParserProjPath = $"./{project}/{project}.nuspec"; +var commandLineParserProjPath = $"./{project}/{project}.csproj"; var tests = $"./{project}.Tests/{project}.Tests.csproj"; var publishPath = MakeAbsolute(Directory("./output")); var nugetPackageDir = MakeAbsolute(Directory("./nuget")); @@ -73,13 +73,9 @@ Task("Publish-NuGet") .IsDependentOn("Publish") .Does(() => { - Information($"nuget package dir: {nugetPackageDir}"); - Information($"nuspec: {commandLineParserProjPath}"); - var nuGetPackSettings = new NuGetPackSettings { - BasePath = publishPath, - OutputDirectory = nugetPackageDir, + OutputDirectory = publishPath, Properties = new Dictionary { { "Configuration", configuration } From 35e6e58eca34161e373035649eaaa85679b87513 Mon Sep 17 00:00:00 2001 From: Matthias Beerens <3512339+Matthiee@users.noreply.github.com> Date: Tue, 27 Nov 2018 21:50:05 +0100 Subject: [PATCH 09/10] update --- build.cake | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build.cake b/build.cake index b457deb..8a5ab36 100644 --- a/build.cake +++ b/build.cake @@ -75,7 +75,10 @@ Task("Publish-NuGet") { var nuGetPackSettings = new NuGetPackSettings { - OutputDirectory = publishPath, + BasePath = publishPath, + OutputDirectory = nugetPackageDir, + IncludeReferencedProjects = true, + Properties = new Dictionary { { "Configuration", configuration } From 8b67f5f16afe189f83cd9c664468fd5e8b8deecf Mon Sep 17 00:00:00 2001 From: Matthias Beerens <3512339+Matthiee@users.noreply.github.com> Date: Wed, 28 Nov 2018 20:19:20 +0100 Subject: [PATCH 10/10] nuget update --- CommandLineParser/CommandLineParser.nuspec | 29 +++++++++++++--------- build.cake | 4 +-- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/CommandLineParser/CommandLineParser.nuspec b/CommandLineParser/CommandLineParser.nuspec index 639915e..3e3723a 100644 --- a/CommandLineParser/CommandLineParser.nuspec +++ b/CommandLineParser/CommandLineParser.nuspec @@ -1,18 +1,23 @@ - $id$ - $version$ - $title$ - $author$ - $author$ - http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE - http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE - http://ICON_URL_HERE_OR_DELETE_THIS_LINE + MatthiWare.CommandLineParser + 0.1.0 + CommandLineParser.Core + Matthias Beerens + Matthiee + https://github.com/MatthiWare/CommandLineParser.Core/blob/master/LICENSE + https://github.com/MatthiWare/CommandLineParser.Core false - $description$ - Summary of changes made in this release of the package. - Copyright 2018 - Tag1 Tag2 + + Command Line Parser for .Net Core written in .Net Standard. + + Configuration is done through a option model class using attributes or fluent api can be used to configure the properties of the class. + This library allows to add commands with their own set of options as well. + +

A simple, light-weight and strongly typed command line parser. Configuration using fluent API and an options class. + Initial release + Copyright Matthias Beerens 2018 + commandline parser commandline-parser \ No newline at end of file diff --git a/build.cake b/build.cake index 8a5ab36..e0a8ce2 100644 --- a/build.cake +++ b/build.cake @@ -12,7 +12,7 @@ var configuration = Argument("configuration", "Release"); var project = "CommandLineParser"; var solution = $"./{project}.sln"; -var commandLineParserProjPath = $"./{project}/{project}.csproj"; +var nuspecFile = $"./{project}/{project}.nuspec"; var tests = $"./{project}.Tests/{project}.Tests.csproj"; var publishPath = MakeAbsolute(Directory("./output")); var nugetPackageDir = MakeAbsolute(Directory("./nuget")); @@ -85,7 +85,7 @@ Task("Publish-NuGet") } }; - NuGetPack(commandLineParserProjPath, nuGetPackSettings); + NuGetPack(nuspecFile, nuGetPackSettings); });